cancel
Showing results for 
Search instead for 
Did you mean: 

Programming an STM32H7 for Samsung eMMC Support

yaxsomo
Associate III

Hello,

I've just received my custom PCB with an STM32H743VIT6 MCU.

It has a Samsung eMMC connected to the SDMMC1 interface (MMC 8 Bits Wide Bus) :

yaxsomo_0-1737130265822.png

(I'll link the eMMC datasheet below.)

I'm encountering some issues while initializing the device with the MX_SDMMC1_MMC_Init function. 
More particularly it seems to be stuck in the HAL_MMC_InitCard function, on this block : 

/* Card initialization */

errorstate = MMC_InitCard(hmmc);

if (errorstate != HAL_MMC_ERROR_NONE)

{

hmmc->State = HAL_MMC_STATE_READY;

hmmc->ErrorCode |= errorstate;

return HAL_ERROR;

}

 

When i launch a debug session it seems to freeze on this block :

/* Get CSD parameters */

if (HAL_MMC_GetCardCSD(hmmc, &CSD) != HAL_OK)

{

return hmmc->ErrorCode;

}

 


Here's the variables states at this breakpoint :

yaxsomo_1-1737130504759.pngyaxsomo_2-1737130510135.pngyaxsomo_3-1737130514249.png

The data does not seem coherent. Am I missing something here ?
For the configuration of the SDMMC1 interface i setted the Clock at 50MHz on the Clock Configuration, and a Divide Factor of 8 (tried 0, 5 and 6 but have the same result) :

yaxsomo_4-1737130600566.pngyaxsomo_5-1737130627953.png

Could someone help me solve this issue?

 

3 REPLIES 3
tjaekel
Lead

Just questions and thoughts:
- why do you have 5pF caps there?
- why do you have everywhere pull-ups? (really needed?)
- are you sure to have an external eMMC chip for 3V3 logic levels?
  (there are different versions, for different "interface power")

As I understand (eMMC, SD card...):
- the initial config phase is just a simple, single lane (like SPI) access
- just after this was successful - the config keeps going by checking capabilities (eMMC registers), such as:
  - voltage level for the signaling - yes! it can be "negotiated" that chips wants to get with lower voltage and signal levels

  - 1bit, 4bit, 8bit capabilities

In which phase do you stuck? (e.g. reading fundamental status registers, capability registers)?

I would assume that your chip wants to go down on power supply level, signal voltage level but you do not "follow" the chip capabilities(even assuming you could read the very first eMMC register): you keep driving always 3V3, never lowering VDD... Maybe the chip "tells" you (or it fails to respond properly) that it does not want to stay all the time at 3V3, instead it wants to go with lower voltages.

What do you get from eMMC chip (on status and capability registers read)?


@tjaekel wrote:

Just questions and thoughts:
- why do you have 5pF caps there?
- why do you have everywhere pull-ups? (really needed?)

As per JEDEC standard, i applied what I learned from the standard no.JESD84-B50 :

yaxsomo_0-1737194885616.png

So yes, pull-ups are indeed needed, and capacitors also.

 


@tjaekel wrote:


- are you sure to have an external eMMC chip for 3V3 logic levels?
  (there are different versions, for different "interface power")

 


For this eMMC model, i can totally power it with only 3.3V on both VCC and VCCQ :

yaxsomo_1-1737195140926.png

The only thing is that, as per JEDEC standard, HS200 and HS400 will not be supported.


@tjaekel wrote:

As I understand (eMMC, SD card...):
- the initial config phase is just a simple, single lane (like SPI) access
- just after this was successful - the config keeps going by checking capabilities (eMMC registers), such as:
  - voltage level for the signaling - yes! it can be "negotiated" that chips wants to get with lower voltage and signal levels

  - 1bit, 4bit, 8bit capabilities

In which phase do you stuck? (e.g. reading fundamental status registers, capability registers)?

I would assume that your chip wants to go down on power supply level, signal voltage level but you do not "follow" the chip capabilities(even assuming you could read the very first eMMC register): you keep driving always 3V3, never lowering VDD... Maybe the chip "tells" you (or it fails to respond properly) that it does not want to stay all the time at 3V3, instead it wants to go with lower voltages.

What do you get from eMMC chip (on status and capability registers read)?


I don't think it's a voltage level issue. Here's the execution of the commands CMD2, CMD3, CMD9 and CMD12 : 

For CMD2 : 

 

  /* Send CMD2 ALL_SEND_CID */
  errorstate = SDMMC_CmdSendCID(hmmc->Instance);
  if (errorstate != HAL_MMC_ERROR_NONE)
  {
    return errorstate;
  }
  else
  {
    /* Get Card identification number data */
    hmmc->CID[0U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP1);
    hmmc->CID[1U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP2);
    hmmc->CID[2U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP3);
    hmmc->CID[3U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP4);
  }

 

Here's the result on the variables state : 

yaxsomo_2-1737198179170.png

(Seems correct to me, as it corresponds to the 128-bit CID register)

 

For CMD3 : 

 

  /* Send CMD3 SET_REL_ADDR with RCA = 2 (should be greater than 1) */
  /* MMC Card publishes its RCA. */
  errorstate = SDMMC_CmdSetRelAddMmc(hmmc->Instance, mmc_rca);
  if (errorstate != HAL_MMC_ERROR_NONE)
  {
    return errorstate;
  }

  /* Get the MMC card RCA */
  hmmc->MmcCard.RelCardAdd = mmc_rca;

 

Here's the result : 

yaxsomo_3-1737198259791.png

RCA seems valid, as it requires to be greater than 1, as per MMC protocol.

 

For CMD9 : 

 

  /* Send CMD9 SEND_CSD with argument as card's RCA */
  errorstate = SDMMC_CmdSendCSD(hmmc->Instance, (uint32_t)(hmmc->MmcCard.RelCardAdd << 16U));
  if (errorstate != HAL_MMC_ERROR_NONE)
  {
    return errorstate;
  }
  else
  {
    /* Get Card Specific Data */
    hmmc->CSD[0U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP1);
    hmmc->CSD[1U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP2);
    hmmc->CSD[2U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP3);
    hmmc->CSD[3U] = SDMMC_GetResponse(hmmc->Instance, SDMMC_RESP4);
  }

 

I get this result : 

yaxsomo_4-1737198346639.png

 I don't know how to decode this thing, but it does not seem too bad.

 

For CMD7 : 

 

  /* Select the Card */
  errorstate = SDMMC_CmdSelDesel(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
  if (errorstate != HAL_MMC_ERROR_NONE)
  {
    return errorstate;
  }

here's the function definition : 

uint32_t SDMMC_CmdSelDesel(SDMMC_TypeDef *SDMMCx, uint32_t Addr)
{
  SDMMC_CmdInitTypeDef  sdmmc_cmdinit;
  uint32_t errorstate;

  /* Send CMD7 SDMMC_SEL_DESEL_CARD */
  sdmmc_cmdinit.Argument         = (uint32_t)Addr;
  sdmmc_cmdinit.CmdIndex         = SDMMC_CMD_SEL_DESEL_CARD;
  sdmmc_cmdinit.Response         = SDMMC_RESPONSE_SHORT;
  sdmmc_cmdinit.WaitForInterrupt = SDMMC_WAIT_NO;
  sdmmc_cmdinit.CPSM             = SDMMC_CPSM_ENABLE;
  (void)SDMMC_SendCommand(SDMMCx, &sdmmc_cmdinit);

  /* Check for error conditions */
  errorstate = SDMMC_GetCmdResp1(SDMMCx, SDMMC_CMD_SEL_DESEL_CARD, SDMMC_CMDTIMEOUT);

  return errorstate;
}

 

I get this result : 

yaxsomo_5-1737198454702.png

And seems also good to me.

 

The issue lies withing the MMC_ReadExtCSD function, particularly in the polling loop that waits for the SDMMC flags (RXOVERR, DCRCFAIL, DTIMEOUT, DATAEND) to be set, but the loop never exits : 

 

  /* Get CSD parameters */  --> The issues starts here
  if (HAL_MMC_GetCardCSD(hmmc, &CSD) != HAL_OK)
  {
    return hmmc->ErrorCode;
  }
      // --> We never get to this point
  /* While card is not ready for data and trial number for sending CMD13 is not exceeded */ 
  errorstate = SDMMC_CmdSendStatus(hmmc->Instance, (uint32_t)(((uint32_t)hmmc->MmcCard.RelCardAdd) << 16U));
  if (errorstate != HAL_MMC_ERROR_NONE)
  {
    hmmc->ErrorCode |= errorstate;
  }

 

On the HAL_MMC_GetCardCSD, :

 

/**
  * @brief  Returns information the information of the card which are stored on
  *         the CSD register.
  * @PAram  hmmc: Pointer to MMC handle
  * @PAram  pCSD: Pointer to a HAL_MMC_CardCSDTypeDef structure that
  *         contains all CSD register parameters
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_MMC_GetCardCSD(MMC_HandleTypeDef *hmmc, HAL_MMC_CardCSDTypeDef *pCSD)
{
  uint32_t block_nbr = 0;

  pCSD->CSDStruct = (uint8_t)((hmmc->CSD[0] & 0xC0000000U) >> 30U);

  pCSD->SysSpecVersion = (uint8_t)((hmmc->CSD[0] & 0x3C000000U) >> 26U);

  pCSD->Reserved1 = (uint8_t)((hmmc->CSD[0] & 0x03000000U) >> 24U);

  pCSD->TAAC = (uint8_t)((hmmc->CSD[0] & 0x00FF0000U) >> 16U);

  pCSD->NSAC = (uint8_t)((hmmc->CSD[0] & 0x0000FF00U) >> 8U);

  pCSD->MaxBusClkFrec = (uint8_t)(hmmc->CSD[0] & 0x000000FFU);

  pCSD->CardComdClasses = (uint16_t)((hmmc->CSD[1] & 0xFFF00000U) >> 20U);

  pCSD->RdBlockLen = (uint8_t)((hmmc->CSD[1] & 0x000F0000U) >> 16U);

  pCSD->PartBlockRead   = (uint8_t)((hmmc->CSD[1] & 0x00008000U) >> 15U);

  pCSD->WrBlockMisalign = (uint8_t)((hmmc->CSD[1] & 0x00004000U) >> 14U);

  pCSD->RdBlockMisalign = (uint8_t)((hmmc->CSD[1] & 0x00002000U) >> 13U);

  pCSD->DSRImpl = (uint8_t)((hmmc->CSD[1] & 0x00001000U) >> 12U);

  pCSD->Reserved2 = 0U; /*!< Reserved */

  if (MMC_ReadExtCSD(hmmc, &block_nbr, 212, 0x0FFFFFFFU) != HAL_OK) /* Field SEC_COUNT [215:212] */ --> Here's the problematic function
  {
    return HAL_ERROR;
  }

  if (hmmc->MmcCard.CardType == MMC_LOW_CAPACITY_CARD)
  {
    pCSD->DeviceSize = (((hmmc->CSD[1] & 0x000003FFU) << 2U) | ((hmmc->CSD[2] & 0xC0000000U) >> 30U));

    pCSD->MaxRdCurrentVDDMin = (uint8_t)((hmmc->CSD[2] & 0x38000000U) >> 27U);

    pCSD->MaxRdCurrentVDDMax = (uint8_t)((hmmc->CSD[2] & 0x07000000U) >> 24U);

    pCSD->MaxWrCurrentVDDMin = (uint8_t)((hmmc->CSD[2] & 0x00E00000U) >> 21U);

    pCSD->MaxWrCurrentVDDMax = (uint8_t)((hmmc->CSD[2] & 0x001C0000U) >> 18U);

    pCSD->DeviceSizeMul = (uint8_t)((hmmc->CSD[2] & 0x00038000U) >> 15U);

    hmmc->MmcCard.BlockNbr  = (pCSD->DeviceSize + 1U) ;
    hmmc->MmcCard.BlockNbr *= (1UL << ((pCSD->DeviceSizeMul & 0x07U) + 2U));
    hmmc->MmcCard.BlockSize = (1UL << (pCSD->RdBlockLen & 0x0FU));

    hmmc->MmcCard.LogBlockNbr = (hmmc->MmcCard.BlockNbr) * ((hmmc->MmcCard.BlockSize) / 512U);
    hmmc->MmcCard.LogBlockSize = 512U;
  }
  else if (hmmc->MmcCard.CardType == MMC_HIGH_CAPACITY_CARD)
  {
    hmmc->MmcCard.BlockNbr = block_nbr;
    hmmc->MmcCard.LogBlockNbr = hmmc->MmcCard.BlockNbr;
    hmmc->MmcCard.BlockSize = 512U;
    hmmc->MmcCard.LogBlockSize = hmmc->MmcCard.BlockSize;
  }
  else
  {
    /* Clear all the static flags */
    __HAL_MMC_CLEAR_FLAG(hmmc, SDMMC_STATIC_FLAGS);
    hmmc->ErrorCode |= HAL_MMC_ERROR_UNSUPPORTED_FEATURE;
    hmmc->State = HAL_MMC_STATE_READY;
    return HAL_ERROR;
  }

  pCSD->EraseGrSize = (uint8_t)((hmmc->CSD[2] & 0x00004000U) >> 14U);

  pCSD->EraseGrMul = (uint8_t)((hmmc->CSD[2] & 0x00003F80U) >> 7U);

  pCSD->WrProtectGrSize = (uint8_t)(hmmc->CSD[2] & 0x0000007FU);

  pCSD->WrProtectGrEnable = (uint8_t)((hmmc->CSD[3] & 0x80000000U) >> 31U);

  pCSD->ManDeflECC = (uint8_t)((hmmc->CSD[3] & 0x60000000U) >> 29U);

  pCSD->WrSpeedFact = (uint8_t)((hmmc->CSD[3] & 0x1C000000U) >> 26U);

  pCSD->MaxWrBlockLen = (uint8_t)((hmmc->CSD[3] & 0x03C00000U) >> 22U);

  pCSD->WriteBlockPaPartial = (uint8_t)((hmmc->CSD[3] & 0x00200000U) >> 21U);

  pCSD->Reserved3 = 0;

  pCSD->ContentProtectAppli = (uint8_t)((hmmc->CSD[3] & 0x00010000U) >> 16U);

  pCSD->FileFormatGroup = (uint8_t)((hmmc->CSD[3] & 0x00008000U) >> 15U);

  pCSD->CopyFlag = (uint8_t)((hmmc->CSD[3] & 0x00004000U) >> 14U);

  pCSD->PermWrProtect = (uint8_t)((hmmc->CSD[3] & 0x00002000U) >> 13U);

  pCSD->TempWrProtect = (uint8_t)((hmmc->CSD[3] & 0x00001000U) >> 12U);

  pCSD->FileFormat = (uint8_t)((hmmc->CSD[3] & 0x00000C00U) >> 10U);

  pCSD->ECC = (uint8_t)((hmmc->CSD[3] & 0x00000300U) >> 8U);

  pCSD->CSD_CRC = (uint8_t)((hmmc->CSD[3] & 0x000000FEU) >> 1U);

  pCSD->Reserved4 = 1;

  return HAL_OK;
}

 

There's the function while loop: 

 

  /* Poll on SDMMC flags */
  while (!__HAL_MMC_GET_FLAG(hmmc, SDMMC_FLAG_RXOVERR | SDMMC_FLAG_DCRCFAIL | SDMMC_FLAG_DTIMEOUT |
                             SDMMC_FLAG_DATAEND))
  {
    if (__HAL_MMC_GET_FLAG(hmmc, SDMMC_FLAG_RXFIFOHF))
    {
      /* Read data from SDMMC Rx FIFO */
      for (count = 0U; count < 8U; count++)
      {
        tmp_data = SDMMC_ReadFIFO(hmmc->Instance);
        /* eg : SEC_COUNT   : FieldIndex = 212 => i+count = 53 */
        /*      DEVICE_TYPE : FieldIndex = 196 => i+count = 49 */
        if ((i + count) == ((uint32_t)FieldIndex / 4U))
        {
          *pFieldData = tmp_data;
        }
      }
      i += 8U;
    }

    if (((HAL_GetTick() - tickstart) >=  Timeout) || (Timeout == 0U))
    {
      /* Clear all the static flags */
      __HAL_MMC_CLEAR_FLAG(hmmc, SDMMC_STATIC_FLAGS);
      hmmc->ErrorCode |= HAL_MMC_ERROR_TIMEOUT;
      hmmc->State = HAL_MMC_STATE_READY;
      return HAL_TIMEOUT;
    }
  }

 

 

 

And I'm not sure why it's stuck there

 

 

yaxsomo
Associate III

Anyone who can help me figure out the issue ?