AnsweredAssumed Answered

SDIO 8 bit bus eMMC/SD Card Issues

Question asked by MP on Apr 14, 2016
Latest reply on Apr 22, 2016 by MP
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

Outcomes