Skip to main content
Explorer
January 15, 2019
Solved

STM32H743 unreliable micro SD transfers

  • January 15, 2019
  • 11 replies
  • 6243 views

Hello all,

I have worked through a number of issues with the SDMMC system and am currently stuck with not being able to reliably transfer from micro SD. I wrote test code to repeatedly read a file from the external card. In some cases HAL_SD_ErrorCallback is called with error code SDMMC_ERROR_CMD_CRC_FAIL.

Here are some things I have tried:

1) Slowing down the clock speed

2) Redesigning the board to improve the signal integrity of the micro SD lines

3) Using SDMMC2 instead of SDMMC1

4) Using 1-bit mode

5) Upgrading to Cube 1.3

6) Switching the pullup mode on the pins on and off

Here is a code excerpt:

SD_HandleTypeDef hsd1;
 
 
void SDMgr::Init()
{
	memset(&hsd1, 0, sizeof(hsd1));
 
	hsd1.Instance					= SDMMC1;
	hsd1.Init.BusWide				= SDMMC_BUS_WIDE_4B;
	hsd1.Init.ClockEdge				= SDMMC_CLOCK_EDGE_RISING;
	hsd1.Init.ClockPowerSave		 = SDMMC_CLOCK_POWER_SAVE_DISABLE;
	hsd1.Init.HardwareFlowControl	= SDMMC_HARDWARE_FLOW_CONTROL_DISABLE;
 
 
	// This assumes an incoming clock of 400MHz / 16 = 25MHz
	// Based on measurements, this results in a 50MHz micro SD clock. We get checksum errors
//	hsd1.Init.ClockDiv				= 2;
 
	// Based on measurements, this results in a 25MHz micro SD clock. We get checksum errors
	hsd1.Init.ClockDiv				= 4;
 
	memset(&m_SDFatFs, 0, sizeof(m_SDFatFs));
	memset(&m_SDPath, 0, sizeof(m_SDPath));
 
	// It is not necessary to cal BSP_SD_Init() here. It is already being called
	// through FatFS at the appropriate time.
 
	Mount();
}
 
 
void SDMgr::Mount()
{
	FATFS_UnLinkDriver(m_SDPath);
 
	/*##-1- Link the micro SD disk I/O driver ##################################*/
	if (FATFS_LinkDriver(&SD_Driver, m_SDPath) != 0)
	{
		Logger::Print("Unable to FATFS_LinkDriver\n");
		return;
	}
 
	/*##-2- Register the file system object to the FatFs module ##############*/
	if(f_mount(&m_SDFatFs, (TCHAR const*)m_SDPath, 0) != FR_OK)
	{
		/* FatFs Initialization Error */
		Logger::Print("Unable to f_mount\n");
		Error_Handler();
	}
}
 
 
void HAL_SD_MspInit(SD_HandleTypeDef* hsd)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	if(hsd->Instance==SDMMC1)
	{
		/* Peripheral clock enable */
		__HAL_RCC_SDMMC1_CLK_ENABLE();
 
		/**SDMMC1 GPIO Configuration 
		PC10 ------> SDMMC1_D2
		PC11 ------> SDMMC1_D3
		PC12 ------> SDMMC1_CK
		PD2 ------> SDMMC1_CMD
		PC8 ------> SDMMC1_D0
		PC9 ------> SDMMC1_D1 
		*/
		GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_8 
							 |GPIO_PIN_9;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
		GPIO_InitStruct.Pull = GPIO_PULLUP;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1;
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
		GPIO_InitStruct.Pin = GPIO_PIN_12;
		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_SDIO1;
		HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
		GPIO_InitStruct.Pin = GPIO_PIN_2;
		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_SDIO1;
		HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
		__HAL_RCC_SDMMC1_FORCE_RESET();
		__HAL_RCC_SDMMC1_RELEASE_RESET();
 
		/* NVIC configuration for SDIO interrupts */
		HAL_NVIC_SetPriority(SDMMC1_IRQn, IRQ_PRIORITY_SD, 0);
		HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
	}
}

Any ideas? Thank you very much.

UPDATE: I am using FreeRTOS and followed the FatFs_uSD_DMA_RTOS sample.

    This topic has been closed for replies.
    Best answer by AHigg

    This change ultimately proved to be the answer:

    uint32_t SDMMC_CmdReadMultiBlock(SDMMC_TypeDef *SDMMCx, uint32_t ReadAdd)
    {
     
     uint32_t maskReg = SDMMCx->MASK;
     SDMMCx->MASK = 0;
     
     
     SDMMC_CmdInitTypeDef sdmmc_cmdinit;
     uint32_t errorstate;
     
     /* Set Block Size for Card */ 
     sdmmc_cmdinit.Argument = (uint32_t)ReadAdd;
     sdmmc_cmdinit.CmdIndex = SDMMC_CMD_READ_MULT_BLOCK;
     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_READ_MULT_BLOCK, SDMMC_CMDTIMEOUT);
     
     SDMMCx->MASK = maskReg;
     
     
     return errorstate;
    }

    11 replies

    Visitor II
    December 29, 2021

    I’m adding this here as I think this is belonging to the same issue but regarding STM32F7 family

    The problem I see is about the combination of RTOS, SDMMC, FATFS and DMA

    I’m currently working on code development for a new product based on STM32F769. At the moment I’m using STM32F769 Discovery kit as development hardware. I’m using FreeRTOS and FATFS. As data drive I use a standard SD card which is using SDMMC2 in SD 4 bits wide bus mode with a clock frequency of 24MHz. Transfer mode is DMA. I was able to manage through all the problems with DMA, CACHE, MMU and the code seemed to work quite stable. For testing, I’m using a test task which permanently reads a 140MB size file from the SD card (reading in 8kByte chunks). For better understanding I added a shot of successful card reading signals. Top three channels show some IRQs, ERR is indicating a timeout in SDMMC_GetCmdResp1, the signals on the SDCARD (D0-3,CMD,CLK), RESPW toggles while waiting in SDMMC_GetCmdResp1 (also when leaving) and CMD12 which indicates the stop command. (200us/diff)  

     0693W00000Hq5WdQAJ.pngIn my next step I added LWIP to the project and created a task allowing me to do some TCP communication. Now, when sending data on the TCP channel, after some time, I get low level disk I/O errors. The more and faster I sent, the earlier the errors occur.

    I did some investigation on that issue and tracked the problem down to SDMMC_GetCmdResp1. Here the code is running into a timeout. I did some hard debugging to figure out to get more info about it. I think I found the following:

    0693W00000Hq5XMQAZ.png1.)   After the ending of previous 8k read the next read multiple block command (CMD18) is sent to the card and wait for the response. Below picture show the zoom of the start.

    0693W00000Hq5XbQAJ.png

    While handling the CMD18 response an IRQ of the Ethernet is occurring. The toggling of RESPW stops although the response is not even received (in above zoom it is setting RESPW to high). Reason for that is that the Ethernet IRQ is serviced (is fine). However, with the IRQ the scheduler also seems do a task switch. The task for the SD card seems to get suspended.   

    2.)   The data transfer starts and DMA is handling this. SD card task still seems to be suspended. 

    3.)   The data transfer is complete, DMA IRQ handles the stop command and overwrites by that the contents of the SDMMC_STA register. Short time after the SD_IRQ is handled the SD card task is getting back context and continues. However, as SDMMC_STA was modified by the DMA IRQ the SD card task never sees the result of sending the command.   

    4.)   SDMMC_GetCmdResp1 runs into timeout

    I haven't tried the patch by now but I thought it should be in the STM32F7 firmware package. 

    For test purpose I tried vTaskSuspendAll() and xTaskResumeAll() to avoid tasks switching between sending the command and the receive. This removed the the disk IO errors. However, I doubt this is a clean solution.

    My environment:

    STM32Cube IDE 1.8.0

    MCU Package 1.16.1

    RTOS, FATFS, DMA, LWIP

    STM32F769 Discovery kit

    8 Gbyte SD card, 24MHz SD CLK, 4 bit wide mode

    Maybe someone is finding this helpful.