Hi all,
I'm having trouble successfully utilizing the 8 bit SDIO bus for the STM32F4. I am using it to communicate with an eMMC 4GB from Kingston.
My current firmware successfully and reliably communicates over the 4 bit SDIO bus, however I'd like to expand it to 8 bits for faster communication.
I've attached some relevant code. Sadly I'm at a loss about what I might be doing wrong. Any guidance or suggestions would be greatly appreciated!
Thanks,
MP
Code functions below:
emmc_init();
EmmcPowerON();
EmmcEnableWideBusOperation():
EmmcEnWideBus():
(Relevant defines listed at end.)
emmc_init();
int emmc_init(void) {
/***************************************************************************
* NVIC INITIALIZATION
**************************************************************************/
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel = SDIO_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1);
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel = EMMC_SDIO_DMA_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 2);
NVIC_Init(&NVIC_InitStruct);
/***************************************************************************
* GPIO INITIALIZATION
**************************************************************************/
GPIO_InitTypeDef GPIO_InitStruct;
/* Configure eMMC reset pin: C13. Set high for operation. */
power_init(&emmc_power_pin);
/* Disable the power (reset) pin until additional initializations. */
power_disable(&emmc_power_pin);
/* Configure emmc_d0_sense_pin: G2. */
RCC_AHB1PeriphClockCmd(emmc_d0_sense_pin.clk, ENABLE);
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStruct.GPIO_Pin = emmc_d0_sense_pin.pin;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(emmc_d0_sense_pin.port, &GPIO_InitStruct);
/* To measure: */
//if (GPIO_ReadInputDataBit(emmc_d0_sense_pin.port, emmc_d0_sense_pin.pin)) {;}
/* GPIOC and GPIOD Periph clock enable */
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB | RCC_AHB1Periph_GPIOC |
RCC_AHB1Periph_GPIOD, ENABLE);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_SDIO); /* Data line: D4.*/
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_SDIO); /* Data line: D5.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource6, GPIO_AF_SDIO); /* Data line: D6.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource7, GPIO_AF_SDIO); /* Data line: D7.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO); /* Data line: D0.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO); /* Data line: D1.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO); /* Data line: D2.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO); /* Data line: D3.*/
GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO); /* CLK line.*/
GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO); /* CMD line.*/
/* Configure PC.06, PC.07, PC.08, PC.09, PC.10, PC.11 pins:
* D6, D7, D0, D1, D2, D3 pins */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 |
GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; /* Max speed: 48 MHz. */
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOC, &GPIO_InitStruct);
/* Configure PB.08, PB.09 pins: D4, D5 */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStruct);
/* Configure PC.12 pin: CLK pin */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOC, &GPIO_InitStruct);
/* Configure PD.02 CMD line */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD, &GPIO_InitStruct);
/***************************************************************************
* SET UP COMMUNICATION
**************************************************************************/
EmmcError Result;
int count = 10;
/* EMMC power on. */
do {
Result = EmmcPowerON();
count--;
} while ((count != 0) && (Result != EMMC_OK));
if (count == 0) {
/* SYSTEM FAILURE */
;// handle error here.
}
/* Initialization of the EMMC. */
MyEmmcCardInfo.RCA = 0x1; /* eMMC address. */
Result = EmmcInitializeCards(&MyEmmcCardInfo);
if (Result != EMMC_OK) {
return(Result);
}
/***************************************************************************
* SET UP 8 BIT COMMUNICATION
**************************************************************************/
/* Set to 8b wide mode on the EMMC. */
#if defined (EMMC_4B_MODE)
Result = EmmcEnableWideBusOperation(SDIO_BusWide_4b);
#elif defined (EMMC_8B_MODE)
Result = EmmcEnableWideBusOperation(SDIO_BusWide_8b);
#endif
if (Result != EMMC_OK) {
return(Result);
}
return(Result);
}
EmmcPowerON():
EmmcError EmmcPowerON(void) {
__IO EmmcError Result = EMMC_OK;
uint32_t count = 400;
uint32_t resp = 0;
/* De-init. the SDIO interface. */
SDIO_DeInit();
/* Enable the SDIO APB2 Clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);
/* Enable the DMA2 Clock */
RCC_AHB1PeriphClockCmd(EMMC_SDIO_DMA_CLK, ENABLE);
SDIO_InitTypeDef SDIO_InitStruct;
/*!< Power ON Sequence -----------------------------------------------------*/
/*!< Configure the SDIO peripheral */
/*!< SDIO_CK = SDIOCLK / (SDIO_INIT_CLK_DIV + 2) */
/*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */
/*!< SDIO_CK for initialization should not exceed 400 KHz */
SDIO_InitStruct.SDIO_ClockDiv = SDIO_INIT_CLK_DIV;
SDIO_InitStruct.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStruct.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStruct.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStruct.SDIO_BusWide = SDIO_BusWide_1b;
SDIO_InitStruct.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStruct);
/*!< Set Power State to ON */
SDIO_SetPowerState(SDIO_PowerState_ON);
/*!< Enable SDIO Clock */
SDIO_ClockCmd(ENABLE);
sys_time_delay_ms(100);
/*!< CMD0: GO_IDLE_STATE ---------------------------------------------------*/
/*!< No CMD response required */
SDIO_CmdInitStruct.SDIO_Argument = 0x00;
SDIO_CmdInitStruct.SDIO_CmdIndex = EMMC_CMD_GO_IDLE_STATE;
SDIO_CmdInitStruct.SDIO_Response = SDIO_Response_No;
SDIO_CmdInitStruct.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStruct.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStruct);
Result = CmdError();
if (Result != EMMC_OK)
return(Result);
sys_time_delay_ms(10);
CardType = SDIO_HIGH_CAPACITY_MMC_CARD;
do {
/*!< SEND CMD1*/
SDIO_CmdInitStruct.SDIO_Argument = EMMC_OCR_REG;
SDIO_CmdInitStruct.SDIO_CmdIndex = EMMC_CMD_SEND_OP_COND;
SDIO_CmdInitStruct.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStruct.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStruct.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStruct);
Result = CmdResp3Error();
count--;
if (count == 0) {
Result = EMMC_ERROR;
break;
}
resp = SDIO_GetResponse(SDIO_RESP1); /* Should be: 0xC0FF8080 */
} while ( (Result != EMMC_OK) || (resp != EMMC_OCR_READY) );
sys_time_delay_ms(10);
return(Result);
}
EmmcEnableWideBusOperation():
EmmcError EmmcEnableWideBusOperation(uint32_t WideMode)
{
SDIO_InitTypeDef SDIO_InitStruct;
EmmcError errorstatus = EMMC_OK;
if (SDIO_BusWide_4b == WideMode)
{
errorstatus = EmmcEnWideBus(ENABLE);
if (EMMC_OK == errorstatus)
{
/*!< Configure the SDIO peripheral */
SDIO_InitStruct.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
SDIO_InitStruct.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStruct.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStruct.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStruct.SDIO_BusWide = SDIO_BusWide_4b;
SDIO_InitStruct.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStruct);
/*!< Set SDIO Power State to ON. */
SDIO_SetPowerState(SDIO_PowerState_ON);
}
}
else if (SDIO_BusWide_8b == WideMode)
{
errorstatus = EmmcEnWideBus(ENABLE);
if (EMMC_OK == errorstatus)
{
/*!< Configure the SDIO peripheral */
SDIO_InitStruct.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
SDIO_InitStruct.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStruct.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStruct.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStruct.SDIO_BusWide = SDIO_BusWide_8b;
SDIO_InitStruct.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStruct);
/*!< Set SDIO Power State to ON. */
SDIO_SetPowerState(SDIO_PowerState_ON);
}
}
else
{
errorstatus = EmmcEnWideBus(DISABLE);
if (EMMC_OK == errorstatus)
{
/*!< Configure the SDIO peripheral */
SDIO_InitStruct.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;
SDIO_InitStruct.SDIO_ClockEdge = SDIO_ClockEdge_Rising;
SDIO_InitStruct.SDIO_ClockBypass = SDIO_ClockBypass_Disable;
SDIO_InitStruct.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;
SDIO_InitStruct.SDIO_BusWide = SDIO_BusWide_1b;
SDIO_InitStruct.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;
SDIO_Init(&SDIO_InitStruct);
/*!< Set SDIO Power State to ON. */
SDIO_SetPowerState(SDIO_PowerState_ON);
}
}
/* Proven necessary. 10 is too short. Trying 100... */
sys_time_delay_ms(10);
return(errorstatus);
}
EmmcEnWideBus():
EmmcError EmmcEnWideBus(FunctionalState NewState)
{
EmmcError Result = EMMC_ERROR;
// uint32_t scr[2] = {0, 0};
if (SDIO_GetResponse(SDIO_RESP1) & EMMC_CARD_LOCKED)
{
Result = EMMC_LOCK_UNLOCK_FAILED;
return(Result);
}
/*!<
If
wide bus operation to be enabled */
if (NewState == ENABLE)
{
// /* CMD6 */
//
SDIO_CmdInitStruct.SDIO_Argument
=
EMMC_POWER_REG
;
//
SDIO_CmdInitStruct.SDIO_CmdIndex
=
EMMC_CMD_HS_SWITCH
;
//
SDIO_CmdInitStruct.SDIO_Response
=
SDIO_Response_Short
;
//
SDIO_CmdInitStruct.SDIO_Wait
=
SDIO_Wait_No
;
//
SDIO_CmdInitStruct.SDIO_CPSM
=
SDIO_CPSM_Enable
;
// SDIO_SendCommand(&SDIO_CmdInitStruct);
//
Result
=
CmdResp1Error
(EMMC_CMD_HS_SWITCH);
//
// if (EMMC_OK != Result)
// {
// return(Result);
// }
/* CMD6 */ /* Not at high speed because Vcc is 3.3V (-> !E HS) */
// SDIO_CmdInitStruct.SDIO_Argument = EMMC_HIGHSPEED_REG;
// SDIO_CmdInitStruct.SDIO_CmdIndex = EMMC_CMD_HS_SWITCH;
// SDIO_CmdInitStruct.SDIO_Response = SDIO_Response_Short;
// SDIO_CmdInitStruct.SDIO_Wait = SDIO_Wait_No;
// SDIO_CmdInitStruct.SDIO_CPSM = SDIO_CPSM_Enable;
// SDIO_SendCommand(&SDIO_CmdInitStruct);
// Result = CmdResp1Error(EMMC_CMD_HS_SWITCH);
// if (EMMC_OK != Result)
// {
// return(Result);
// }
/* CMD6 */
SDIO_CmdInitStruct.SDIO_Argument = EMMC_xBIT_REG;
SDIO_CmdInitStruct.SDIO_CmdIndex = EMMC_CMD_HS_SWITCH;
SDIO_CmdInitStruct.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStruct.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStruct.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStruct);
Result = CmdResp1Error(EMMC_CMD_HS_SWITCH);
if (EMMC_OK != Result)
{
return(Result);
}
return(Result);
} /*!< If wide bus operation to be disabled */
else
{
Result = CmdResp1Error(EMMC_CMD_APP_CMD);
if (Result != EMMC_OK)
{
return(Result);
}
if (Result != EMMC_OK)
{
return(Result);
}
return(Result);
}
}
defines:
#define EMMC_POWER_REG 0x03BB0800
#define EMMC_HIGHSPEED_REG 0x03B90100
#if defined (EMMC_4B_MODE)
#define EMMC_4BIT_REG 0x03B70100
#elif defined (EMMC_8B_MODE)
#define EMMC_8BIT_REG 0x03B70200
#endif
#if defined (EMMC_4BIT_REG)
#define EMMC_xBIT_REG EMMC_4BIT_REG
#elif defined (EMMC_8BIT_REG)
#define EMMC_xBIT_REG EMMC_8BIT_REG
#else
#define EMMC_xBIT_REG EMMC_4BIT_REG
#endif