cancel
Showing results for 
Search instead for 
Did you mean: 

16GB eMMC (8-bit) on STM32F676ZI

Jack3
Senior II

Hi, I connected a 16GB Sandisk eMMC in 8-bit mode to an STM32F676ZI SDMMC interface.

I use HAL drivers and TrueStudio for development.

HAL_MMC_GetCardInfo returns this information:

CardType    : 0
Class       : 2293
RelCardAdd  : 0
BlockNbr    : 2097152
BlockSize   : 512
LogBlockNbr : 2097152
LogBlockSize: 512

If I multiply 2097152 * 512, I get 1GB, instead of 16GB.

When I use HAL_MMC_WriteBlocks and HAL_MMC_ReadBlocks, this works well, but only up to block 60111 (~30MB). After this, bot read and rite fails, and I see HAL_MMC_ERROR_CMD_CRC_FAIL.

This is about 512 times less capacity which I can access, making me think bytes addressing was used instead of block addressing.

What went wrong?

Just in case, the CID and CSD details.

HAL_MMC_GetCardCID returns:

ManufacturerID: 45
OEM_AppliID   : 100
ProdName1     : DG40
ProdName2     : 1
ProdRev       : 6
ProdSN        : 019B4A6F
ManufactDate  : 0315
CID_CRC       : 7F

HAL_MMC_GetCardCSD returns:

CSDStruct          : 3
SysSpecVersion     : 4
TAAC               : 15
NSAC               : 0
MaxBusClkFrec      : 50
CardComdClasses    : 2293
RdBlockLen         : 9
PartBlockRead      : 0
WrBlockMisalign    : 0
RdBlockMisalign    : 0
DSRImpl            : 0
DeviceSize         : 4095
MaxRdCurrentVDDMin : 7
MaxRdCurrentVDDMax : 7
MaxWrCurrentVDDMin : 7
MaxWrCurrentVDDMax : 7
DeviceSizeMul      : 7
EraseGrSize        : 1
EraseGrMul         : 127
WrProtectGrSize    : 111
WrProtectGrEnable  : 1
ManDeflECC         : 0
WrSpeedFact        : 2
MaxWrBlockLen      : 9
WriteBlockPaPartial: 0
ContentProtectAppli: 0
FileFormatGrouop   : 0
CopyFlag           : 1
PermWrProtect      : 0
TempWrProtect      : 0
FileFormat         : 0
ECC                : 0
CSD_CRC            : 17

 Some code. I use for testing:

void MX_SDMMC1_MMC_Init(void)
{
 
  hmmc1.Instance = SDMMC1;
  hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
  hmmc1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
  hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  hmmc1.Init.BusWide = SDMMC_BUS_WIDE_1B;
  hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
  hmmc1.Init.ClockDiv = 0;
  if (HAL_MMC_Init(&hmmc1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  if (HAL_MMC_ConfigWideBusOperation(&hmmc1, SDMMC_BUS_WIDE_8B) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
}

    uint32_t dataSize = 512;    // 131072
    uint32_t blockSize = 512;
    uint32_t numberOfBlocks = dataSize / blockSize;
    uint32_t errorState = 0;
    uint32_t timeout = 1000000;
    uint32_t blockAdd = 0;
    uint8_t *wData = (uint8_t *) malloc(dataSize);
    uint8_t *rData = (uint8_t *) malloc(dataSize);
    uint32_t kB = 0;
    uint32_t capacity = 32*1024*1024;
    uint32_t iterations = capacity / dataSize;
 
    printf("\n*** Reset Card...\n");
    ResetCard();
    GetCardState();
 
    printf("\n*** Init Card (HAL_MMC_InitCard)...\n");
    HAL_Delay(100);
    errorState = HAL_MMC_InitCard(&hmmc1);
    if(errorState == HAL_MMC_ERROR_NONE) {
        printf("HAL_MMC_InitCard OK\n");
    }
    else {
        printf("HAL_MMC_InitCard FAILED\n");
    }
    GetCardState();
    GetCardErrorState(errorState);
 
    // SDMMC_CmdBlockLength(SDMMC_TypeDef *SDMMCx, uint32_t BlockSize)
 
    //    HAL_Delay(100);
//    errorstate = HAL_MMC_InitCard(&hmmc1);
    printf("\n*** Get Card Info (HAL_MMC_GetCardInfo)...\n");
    HAL_Delay(100);
    HAL_MMC_CardInfoTypeDef pCardInfo;
    errorState = HAL_MMC_GetCardInfo(&hmmc1, &pCardInfo);
 
    //    errorstate = HAL_MMC_InitCard(&hmmc1);
 
    int status = 0;
    blockAdd = 0;
     
    for (int iteration = 0; iteration < iterations; iteration++) {
        blockAdd += numberOfBlocks; //  + 2097152 HAL_MMC_ERROR_CMD_CRC_FAIL
        kB = blockAdd / 2;
 
        // Write
        for (int i = 0; i < dataSize; i++) {
            wData[i] = (i + iteration) & 0xff;
        }
        errorState = HAL_MMC_WriteBlocks(&hmmc1, wData, blockAdd, numberOfBlocks, timeout);
        while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER) {
            HAL_Delay(1);
        }
        HAL_Delay(50);
 
        printf("Wr ");
            for (int j = 0; j < 1; j++) {
                for (int i = 0; i < 16; i++) {
                    printf("%02X ", wData[i+ j*16]);
                }
                printf("\n");
            }
 
        // Read
        for (int i = 0; i < 512; i++) {
            rData[i] = 0xff;
        }
        errorState = HAL_MMC_ReadBlocks(&hmmc1, rData, blockAdd, numberOfBlocks, timeout);
        while (HAL_MMC_GetCardState(&hmmc1) != HAL_MMC_CARD_TRANSFER) {
            HAL_Delay(1);
        }
        HAL_Delay(50);
        printf("Rd ");
            for (int j = 0; j < 1; j++) {
                for (int i = 0; i < 16; i++) {
                    printf("%02X ", rData[i+ j*16]);
                }
                printf("\n");
            }
//        }
        if (memcmp(wData, rData, 512) == 0) {
            printf("Compare Passed. (BA: %8ld, %8ld kB) %d\n", blockAdd, kB, status);
        }
        else {
            status = 1;
            printf("Compare FAILED! (BA: %8ld, %8ld kB) %d\n", blockAdd, kB, status);
        }
    }
 
    free(wData);
    free(rData);

Kind regards,

Jack.

18 REPLIES 18

You have to read the EXTCSD

EMMC Build

00200000 2097152  1.00 GB GetCardCSD

00000000 : 03 04 00 2F 01 32 F5 00-09 00 00 00 01 00 00 00 .../.2..........

00000010 : FF 0F 00 00 07 07 07 07-07 01 7F 6F 01 00 03 09 ...........o....

00000020 : 00 00 00 00 00 00 00 00-00 18 01 20            ...........

HAL_SD_ReadEXTCSD Enter

00E40000  7.13 GB  7.47 GB EXTCSD

00000000 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000010 : 01 01 00 00 70 00 00 00-00 00 00 00 00 00 00 00 ....p...........

00000020 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000030 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000040 : 03 A3 02 00 01 00 00 00-00 00 00 00 00 00 00 00 ................

00000050 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000060 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000070 : 00 00 00 00 00 00 00 00-00 00 20 00 00 10 00 00 .......... .....

00000080 : 00 00 01 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000090 : 00 00 00 00 00 00 00 00-00 00 00 00 00 C8 01 00 ................

000000A0 : 07 00 00 00 00 00 15 1F-20 00 00 00 00 00 00 00 ........ .......

000000B0 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

000000C0 : 07 00 02 00 57 1F 0A 03-00 00 00 00 00 08 14 08 ....W...........

000000D0 : 14 08 13 00 00 00 E4 00-0F 13 14 08 08 10 01 11 ................

000000E0 : 01 07 10 00 07 3A 3A 55-11 00 00 13 00 00 00 00 .....::U........

000000F0 : 00 64 01 00 00 00 00 FF-19 00 02 00 00 00 05 00 .d..............

00000100 : 00 00 00 00 00 00 00 00-01 08 01 01 01 01 00 00 ................

00000110 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000120 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000130 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000140 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000150 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000160 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000170 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000180 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

00000190 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

000001A0 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

000001B0 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

000001C0 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

000001D0 : 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................

000001E0 : 00 00 00 00 00 00 00 FF-FF 00 00 00 00 03 03 07 ................

000001F0 : 05 00 03 01 3F 3F 01 01-01 00 00 00 00 00 00 00 ....??..........

Selecting 8-Bit Mode

HAL_SD_GetCardInfo 14942208 14942208  7.13 GB

 CardInfo 14942208 512 512 ( 7.13 GB)

...and fix a bunch of stupidity in ST's code. Have eMMC solutions proven on 4, 8 16, 32, 64 and 128GB, 4 or 8-bit width, and supporting SanDisk, Samsung and Micron parts.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Jack3
Senior II

Hi Clive, thank you for the fast response.

How do I read that with HAL? Do I need to implement a function to do so?

Kind regards,

Jack.

ST's code only supports 2GB and smaller eMMC, and forks the SD and MMC code, which is arguably unnecessary. You'd need to add code to read the full capacity from the EXTCSD, and then fix the block computations.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Jack3
Senior II

Hi Clive, thank you very much, I will have a look into this.

Does something to be configured on the card too, so it doesn't start failing after block 60111?

I assume just reading EXTCSD (once I'm able to do so) wouldn't fix the limit on the block address?

Kind regards,

Jack.

You have to work through this brain damage

#define CAPACITY   ((uint32_t)0x80000000U) /*!< 2 G bytes constant     */

..

   /* Check the Card capacity in term of Logical number of blocks */

   if ((hmmc->MmcCard.LogBlockNbr) < CAPACITY)

   {

     BlockAdd *= 512;

   }

ie, put the right value in LogBlockNbr, and compare it to a BLOCK COUNT

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Provide pin usage on your board for the SDMMC interface, a USART usable for debug/diagnostic output and HSE clock source details, and I'll make a benchmark/integrity demo. sourcer32@gmail.com

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Jack3
Senior II

Hi Clive,

thank you very much!

These are the pin connections (I hope this is what you mean):

STM32F767ZITx
PC8  SDMMC1_D0
PC9  SDMMC1_D1
PC10 SDMMC1_D2
PC11 SDMMC1_D3
PB8  SDMMC1_D4
PB9  SDMMC1_D5
PC6  SDMMC1_D6
PC7  SDMMC1_D7
PD2  SDMMC1_CMD
PC12 SDMMC1_CK
void HAL_MMC_MspInit(MMC_HandleTypeDef* mmcHandle)
{
 
  GPIO_InitTypeDef GPIO_InitStruct;
  if(mmcHandle->Instance==SDMMC1)
  {
  /* USER CODE BEGIN SDMMC1_MspInit 0 */
 
  /* USER CODE END SDMMC1_MspInit 0 */
    /* SDMMC1 clock enable */
    __HAL_RCC_SDMMC1_CLK_ENABLE();
  
    /**SDMMC1 GPIO Configuration    
    PC6     ------> SDMMC1_D6
    PC7     ------> SDMMC1_D7
    PC8     ------> SDMMC1_D0
    PC9     ------> SDMMC1_D1
    PC10     ------> SDMMC1_D2
    PC11     ------> SDMMC1_D3
    PC12     ------> SDMMC1_CK
    PD2     ------> SDMMC1_CMD
    PB8     ------> SDMMC1_D4
    PB9     ------> SDMMC1_D5 
    */
    GPIO_InitStruct.Pin = SDMMC1_D6_Pin|SDMMC1_D7_Pin|SDMMC1_D0_Pin|SDMMC1_D1_Pin
            |SDMMC1_D2_Pin|SDMMC1_D3_Pin|SDMMC1_CK_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = SDMMC1_CMD_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    HAL_GPIO_Init(SDMMC1_CMD_GPIO_Port, &GPIO_InitStruct);
 
    GPIO_InitStruct.Pin = SDMMC1_D4_Pin|SDMMC1_D5_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
 
    /* SDMMC1 DMA Init */
    /* SDMMC1 Init */
    hdma_sdmmc1.Instance = DMA2_Stream3;
    hdma_sdmmc1.Init.Channel = DMA_CHANNEL_4;
    hdma_sdmmc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_sdmmc1.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdmmc1.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdmmc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdmmc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdmmc1.Init.Mode = DMA_PFCTRL;
    hdma_sdmmc1.Init.Priority = DMA_PRIORITY_LOW;
    hdma_sdmmc1.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_sdmmc1.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_sdmmc1.Init.MemBurst = DMA_MBURST_INC4;
    hdma_sdmmc1.Init.PeriphBurst = DMA_PBURST_INC4;
    if (HAL_DMA_Init(&hdma_sdmmc1) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }
 
    /* Several peripheral DMA handle pointers point to the same DMA handle.
     Be aware that there is only one stream to perform all the requested DMAs. */
    /* Be sure to change transfer direction before calling
     HAL_SD_ReadBlocks_DMA or HAL_SD_WriteBlocks_DMA. */
    __HAL_LINKDMA(mmcHandle,hdmarx,hdma_sdmmc1);
    __HAL_LINKDMA(mmcHandle,hdmatx,hdma_sdmmc1);
 
    /* SDMMC1 interrupt Init */
    HAL_NVIC_SetPriority(SDMMC1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
  /* USER CODE BEGIN SDMMC1_MspInit 1 */
 
  /* USER CODE END SDMMC1_MspInit 1 */
  }
}

Yet, I do not use DMA or interrupt for the card, but I prepared some configurations for that.

I have routed printf to USART2, and enabled formatting for float too:

int __io_putchar(int ch)
{
    uint8_t c[1];
    c[0] = ch & 0x00FF;
    HAL_UART_Transmit(&huart2, &*c, 1, 10);
    return ch;
}
 
int _write(int file,char *ptr, int len)
{
    int i;
    for(i = 0; i < len; i++)
    {
       __io_putchar(*ptr++);
    }
    return len;
}

0690X000006BrRVQA0.png

PLL48CLK (48MHz) to MMC

void SystemClock_Config(void)
{
 
  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;
  RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
 
    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();
 
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 432;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Activate the Over-Drive mode 
    */
  if (HAL_PWREx_EnableOverDrive() != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
 
  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
  PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART2|RCC_PERIPHCLK_USART3
                              |RCC_PERIPHCLK_I2C2|RCC_PERIPHCLK_SDMMC1
                              |RCC_PERIPHCLK_CLK48;
  PeriphClkInitStruct.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
  PeriphClkInitStruct.Usart3ClockSelection = RCC_USART3CLKSOURCE_PCLK1;
  PeriphClkInitStruct.I2c2ClockSelection = RCC_I2C2CLKSOURCE_PCLK1;
  PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLL;
  PeriphClkInitStruct.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_CLK48;
  if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
 
    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);
 
    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
 
  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

Kind regards,

Jack.

USART2 on PA2/PA3?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Jack3
Senior II

Hi Clive, USART 2 is on PD5 (TX) and PD6 (RX). Thanks, Jack.

0690X000006BrSnQAK.png