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

    Graduate II
    January 15, 2019

    What's your platform? NUCLEO, EVAL or custom

    Try backing this off

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;

    For the NUCLEO remove SB116/SB117 to lose the stubs

    Does your socket have pull-ups, or not?

    Would probably pull-up PD2/CMD

    AHiggAuthor
    Explorer
    January 17, 2019

    First, thanks again Clive. For others who run into this problem, please note the following:

    I tried a number of different options and the best results came from GPIO_SPEED_FREQ_MEDIUM.

    This was true even for series resistors of 0, 25, and 100 Ohms. They didn't seem to make a difference. I found the internal GPIO pullups did the job (GPIO_PULLUP on the data and command lines).

    After modifying it for my board, I can now run this example for an extended time without errors:

    STM32Cube_FW_H7_V1.3.0\Projects\STM32H743I_EVAL\Examples\SD\SD_ReadWrite_DMA

    My previous test code still has problems. My next move is to dig into the FatFs stack and see what the problem is.

    Graduate II
    January 17, 2019

    I have a soak tester that fills the media and checks the integrity of the data.

    Do you have a debug UART available? Which UART/PINS?

    AHiggAuthor
    Explorer
    January 15, 2019

    Clive,

    Thanks for the quick response. Let me also thank you for your enormous contributions in this community.

    This is a custom platform. There is no transceiver for the micro SD socket. From everything I have seen it is not required. Would you recommend one?

    There are no external pullups. I don't believe the socket has anything built in. I will try out your recommendations tomorrow.

    Thank you

    Graduate II
    January 15, 2019

    The socket itself probably doesn't but usually one can place them close in. Typically 33K or 47K

    The slew rate you're using will dump a lot of energy into the traces, this can be problematic if they are very short, and you don't have any series resistor (27R or 33R) on them.

    VERY_HIGH can drive 100-220 MHz depending on the capacitive loading. MEDIUM (60-110) and HIGH (85-166) might be more accommodative.

    You might also want to double check the soldering at the socket, Without a card, you could try putting the pins in a GPIO OD mode, pulled high, and then drive each pin low individually via ODR, and then checking the value readback via IDR. This should show any interconnectivity.

    Used these on NUCLEO-H7 boards https://www.waveshare.com/micro-sd-storage-board.htm

    AHiggAuthor
    Explorer
    January 19, 2019

    Clive,

    Thanks again, at this point I have to conclude the PCB and circuit is good but there is some kind of SDMMC state machine/driver stack problem. Specifically, I see the state machine crash following a multiblock transfer and a SDMMC_CMD_STOP_TRANSMISSION command. This affects both reading and writing. It seems to be more prevalent when using FatFs because of the more complex transactions.

    I appreciate that this one may be out of your direct experience because you use a different driver stack. Perhaps you can alert the STM people?

    Is there any special behavior needed to close a multiblock transaction?

    Here are some things I can say with confidence:

    • My PCB can reliably perform low level DMA transfers to micro SD. I have run extended read/write tests at 25Mhz
    • With FatFs in place, I can successfully read files at 50MHz and write them at 10MHz
    • When I crank up the speed on the write test, the state machine will crash following a stop command
    • When I use my product level code that attempts to read many things at once, the state machine will crash following a stop command
    • I did obtain a Nucleo board and the WaveShare micro SD module. My initial tests yielded worse results than my custom board, so I stopped pursuing it.

    I have reviewed the errata dated June 2018. I've attempted to patch some of the issues, including the Clock stop, with no success.

    At this point, I'm not sure what my next move is. I need to sign off on this PCB to keep my project on schedule. I'm confident the board/circuit design is OK. I am unclear on how to get past this state machine issue.

    I appreciate any guidance you have to offer.

    void HAL_SD_IRQHandler(SD_HandleTypeDef *hsd)
    {
     uint32_t errorstate;
     uint32_t context = hsd->Context;
     
     /* Check for SDMMC interrupt flags */
     if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_DATAEND) != RESET)
     {
     // Attempted fix for errata 2.11.5
     if((context & SD_CONTEXT_DMA) != 0U && (((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)))
    	{
    	 __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DATAEND | SDMMC_FLAG_CKSTOP);
    	}
    	else
    	{
    		__HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DATAEND);
    	}
     
     __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_DATAEND | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT |\
     SDMMC_IT_TXUNDERR | SDMMC_IT_RXOVERR | SDMMC_IT_TXFIFOHE |\
     SDMMC_IT_RXFIFOHF);
     
     __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_IDMABTC);
     __SDMMC_CMDTRANS_DISABLE( hsd->Instance);
     
     if((context & SD_CONTEXT_IT) != 0U)
     {
     if(((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
     {
     errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
     if(errorstate != HAL_SD_ERROR_NONE)
     {
     hsd->ErrorCode |= errorstate;
     HAL_SD_ErrorCallback(hsd);
     }
     }
     
     /* Clear all the static flags */
     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
     
     hsd->State = HAL_SD_STATE_READY;
     if(((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
     {
     HAL_SD_RxCpltCallback(hsd);
     }
     else
     {
     HAL_SD_TxCpltCallback(hsd);
     }
     }
     else if((context & SD_CONTEXT_DMA) != 0U)
     {
     hsd->Instance->DLEN = 0;
     hsd->Instance->DCTRL = 0;
     hsd->Instance->IDMACTRL = SDMMC_DISABLE_IDMA;
     
     /* Stop Transfer for Write Single/Multi blocks or Read Multi blocks */
     if(((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
     {
     errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
     if(errorstate != HAL_SD_ERROR_NONE)
     {
     hsd->ErrorCode |= errorstate;
     HAL_SD_ErrorCallback(hsd);
     }
     }
     
     hsd->State = HAL_SD_STATE_READY;
     if(((context & SD_CONTEXT_WRITE_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U))
     {
     HAL_SD_TxCpltCallback(hsd);
     }
     if(((context & SD_CONTEXT_READ_SINGLE_BLOCK) != 0U) || ((context & SD_CONTEXT_READ_MULTIPLE_BLOCK) != 0U))
     {
     HAL_SD_RxCpltCallback(hsd);
     }
     }
     else
     {
     /* Nothing to do */
     }
     }
     
     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_TXFIFOHE) != RESET)
     {
     SD_Write_IT(hsd);
     }
     
     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_RXFIFOHF) != RESET)
     {
     SD_Read_IT(hsd);
     }
     
     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT | SDMMC_IT_RXOVERR | SDMMC_IT_TXUNDERR) != RESET)
     {
     /* Set Error code */
     if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_DCRCFAIL) != RESET)
     {
     hsd->ErrorCode |= HAL_SD_ERROR_DATA_CRC_FAIL;
     }
     if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_DTIMEOUT) != RESET)
     {
     hsd->ErrorCode |= HAL_SD_ERROR_DATA_TIMEOUT;
     }
     if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_RXOVERR) != RESET)
     {
     hsd->ErrorCode |= HAL_SD_ERROR_RX_OVERRUN;
     }
     if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_TXUNDERR) != RESET)
     {
     hsd->ErrorCode |= HAL_SD_ERROR_TX_UNDERRUN;
     }
     
     /* Clear All flags */
     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_DATA_FLAGS);
     
     /* Disable all interrupts */
     __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_DATAEND | SDMMC_IT_DCRCFAIL | SDMMC_IT_DTIMEOUT|\
     SDMMC_IT_TXUNDERR| SDMMC_IT_RXOVERR);
     
     __SDMMC_CMDTRANS_DISABLE( hsd->Instance);
     hsd->Instance->DCTRL |= SDMMC_DCTRL_FIFORST;
     hsd->Instance->CMD |= SDMMC_CMD_CMDSTOP;
     hsd->ErrorCode |= SDMMC_CmdStopTransfer(hsd->Instance);
     hsd->Instance->CMD &= ~(SDMMC_CMD_CMDSTOP);
     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_DABORT);
     
     if((context & SD_CONTEXT_IT) != 0U)
     {
     /* Set the SD state to ready to be able to start again the process */
     hsd->State = HAL_SD_STATE_READY;
     HAL_SD_ErrorCallback(hsd);
     }
     else if((context & SD_CONTEXT_DMA) != 0U)
     {
     if(hsd->ErrorCode != HAL_SD_ERROR_NONE)
     {
     /* Disable Internal DMA */
     __HAL_SD_DISABLE_IT(hsd, SDMMC_IT_IDMABTC);
     hsd->Instance->IDMACTRL = SDMMC_DISABLE_IDMA;
     
     /* Set the SD state to ready to be able to start again the process */
     hsd->State = HAL_SD_STATE_READY;
     HAL_SD_ErrorCallback(hsd);
     }
     }
     else
     {
     /* Nothing to do */
     }
     }
     
     else if(__HAL_SD_GET_FLAG(hsd, SDMMC_IT_IDMABTC) != RESET)
     {
     if(READ_BIT(hsd->Instance->IDMACTRL, SDMMC_IDMA_IDMABACT) == 0U)
     {
     /* Current buffer is buffer0, Transfer complete for buffer1 */
     if((hsd->Context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)
     {
     HAL_SDEx_Write_DMADoubleBuffer1CpltCallback(hsd);
     }
     else /* SD_CONTEXT_READ_MULTIPLE_BLOCK */
     {
     HAL_SDEx_Read_DMADoubleBuffer1CpltCallback(hsd);
     }
     }
     else /* SD_DMA_BUFFER1 */
     {
     /* Current buffer is buffer1, Transfer complete for buffer0 */
     if((context & SD_CONTEXT_WRITE_MULTIPLE_BLOCK) != 0U)
     {
     HAL_SDEx_Write_DMADoubleBuffer0CpltCallback(hsd);
     }
     else /* SD_CONTEXT_READ_MULTIPLE_BLOCK */
     {
     HAL_SDEx_Read_DMADoubleBuffer0CpltCallback(hsd);
     }
     }
     __HAL_SD_CLEAR_FLAG(hsd, SDMMC_FLAG_IDMABTC);
     }
     else
     {
     /* Nothing to do */
     }
    }

    AHiggAuthor
    Explorer
    January 19, 2019
    I’m not sure where you are headed with this. I do have a debug port available on USART2, pins PD5 and PD6. I haven’t used it before.
    I am using a Segger J-Link on the SWD port for debugging purposes.
    I did run some of your test code on the Nucleo with the WaveShare micro SD socket. I wasn’t sure what to expect so it was of limited use.
    Thank you and please let me know how I can help.
    Aaron Higgins
    1010music LLC
    aaron@1010music.com
    AHiggAuthor
    Explorer
    January 23, 2019

    Here is a patch to stm32h77xx_II_sdmmc.c that looks promising. Note the difference in line 16 where SDMMC_FLAG_BUSYD0END is removed from the conditional.

    static uint32_t SDMMC_GetCmdResp1(SDMMC_TypeDef *SDMMCx, uint8_t SD_CMD, uint32_t Timeout)
    {
     uint32_t response_r1;
     
     /* 8 is the number of required instructions cycles for the below loop statement.
     The Timeout is expressed in ms */
     register uint32_t count = Timeout * (SystemCoreClock / 8U /1000U);
     
     do
     {
     if (count-- == 0U)
     {
     return SDMMC_ERROR_TIMEOUT;
     }
     
     }while(!__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT));
     
    <snip>
     

    Technical Moderator
    April 22, 2019

    Hello,

    The SDMMC driver is updated in the new STM32H7 Cube package (that will be available soon on ST website).

    Regarding this loop condition, it will be updated as described below:

    static uint32_t SDMMC_GetCmdResp1(SDMMC_TypeDef *SDMMCx, uint8_t SD_CMD, uint32_t Timeout)
    {
     uint32_t response_r1;
     uint32_t sta_reg;
     
     /* 8 is the number of required instructions cycles for the below loop statement.
     The Timeout is expressed in ms */
     register uint32_t count = Timeout * (SystemCoreClock / 8U /1000U);
     
     do
     {
     if (count-- == 0U)
     {
     return SDMMC_ERROR_TIMEOUT;
     }
     sta_reg = SDMMCx->STA;
     }while(((sta_reg & (SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT | SDMMC_FLAG_BUSYD0END)) == 0U) ||
     ((sta_reg & SDMMC_FLAG_CMDACT) != 0U ));
    ....

    If you have any feedback, please don't hesitate to share it with us.

    Khouloud.

    Visitor II
    May 6, 2019

    I tested this one change (without taking all of the V1.4.0 update) and all of my DMA-based reads now time out. I am still tracking down why...

    It seems to work correctly for retrieving CSD, etc, but not for doing Multi-block DMA reads

    Visitor II
    May 6, 2019

    The SDMMC_FLAG_CMDACT bit never goes low, when I do a DMA-based single or multi-block read, so it always exits the while loop with a timeout.

    Is there something else required?

    AHiggAuthorAnswer
    Explorer
    May 6, 2019

    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;
    }

    Visitor II
    May 6, 2019

    Hi Aaron,

    I don't think your solution will work if DMA is used. It looks like you are disabling all interrupts by setting the MASKR register to all 0's.

    In my case, CRC problem isn't really a CRC problem. In the call to GetCMDResp1, the following call fails:

     /* Check response received is of desired command */
     if((response_r1 = SDMMC_GetCommandResponse(SDMMCx)) != SD_CMD)
     {
    	 DBGprintf("cmd sent: %x response: %x\n", SD_CMD, response_r1);
     return SDMMC_ERROR_CMD_CRC_FAIL;
     }

    In my case, the command (SD_CMD) is 0x10 to set the block length and the response returned is 0x0d. The function does return the SDMMC_ERROR_CMD_CRC_FAIL error, but it is really a command request/response mismatch.

    If I put an ITM trace call in the main GetCMDResp1() call, the CRC problem also goes away, which points to a timing issue.

    ...Keith

    Graduate II
    March 14, 2020

    Hi All,

    I've been having trouble with CMD CRC errors with multi block writes. (I don't do much reading as I am logging data into an sqlite db. The error is infrequent and seems random. it occurs in the following part of the sd card driver:

    /**
     * @brief Send the Write Multi Block command and check the response
     * @param SDMMCx: Pointer to SDMMC register base
     * @retval HAL status
     */
    uint32_t SDMMC_CmdWriteMultiBlock(SDMMC_TypeDef *SDMMCx, uint32_t WriteAdd)
    {
     SDMMC_CmdInitTypeDef sdmmc_cmdinit;
     uint32_t errorstate;
     
     /* Set Block Size for Card */
     sdmmc_cmdinit.Argument = (uint32_t)WriteAdd;
     sdmmc_cmdinit.CmdIndex = SDMMC_CMD_WRITE_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_WRITE_MULT_BLOCK, SDMMC_CMDTIMEOUT);
     seggerError(5, errorstate, sdmmc_cmdinit);	
     
     return errorstate;
    }

    I have looked at the sd card bus signals and they look fine.

    Arron, how does the mod you made fix the problem and do you think it would work for block writes as well as block reads.

    I am thinking of giving it a try, but I would like to understand what it is doing.

    Best regards

    Rob

    Graduate II
    March 15, 2020

    Hi All

    I tried out Arron's "turn off SDMMC controller interrupts" patch for the SD Card erros. I put his patch in the write/read multiple blocks functions and it has worked.

    /**
     * @brief Send the Read Multi Block command and check the response
     * @param SDMMCx: Pointer to SDMMC register base
     * @retval HAL status
     */
    uint32_t SDMMC_CmdReadMultiBlock(SDMMC_TypeDef *SDMMCx, uint32_t ReadAdd)
    {
    	uint32_t maskReg = SDMMCx->MASK; /* rjgMod per AHigg */
     SDMMCx->MASK = 0; /* rjgMod per AHigg */
    	
     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; /* rjgMod per AHigg */
     seggerError(3, errorstate, sdmmc_cmdinit);	
     
     return errorstate;
    } ...
     
    ...
    /**
     * @brief Send the Write Multi Block command and check the response
     * @param SDMMCx: Pointer to SDMMC register base
     * @retval HAL status
     */
    uint32_t SDMMC_CmdWriteMultiBlock(SDMMC_TypeDef *SDMMCx, uint32_t WriteAdd)
    {
    	uint32_t maskReg = SDMMCx->MASK; /* rjgMod per AHigg */
     SDMMCx->MASK = 0; /* rjgMod per AHigg */
    	
     SDMMC_CmdInitTypeDef sdmmc_cmdinit;
     uint32_t errorstate;
     
     /* Set Block Size for Card */
     sdmmc_cmdinit.Argument = (uint32_t)WriteAdd;
     sdmmc_cmdinit.CmdIndex = SDMMC_CMD_WRITE_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_WRITE_MULT_BLOCK, SDMMC_CMDTIMEOUT);
    	SDMMCx->MASK = maskReg; /* rjgMod per AHigg */
     seggerError(5, errorstate, sdmmc_cmdinit);	
     
     return errorstate;
    }

    Ignore the  seggerError(5, errorstate, sdmmc_cmdinit);    These were added to debug the driver using my Segger j-link debugger.

    If you have a j-link debugger then the function I this calls may be found below:

    #if DEBUG_SDMMC	== 1
    #include "seggerPrintRTC.h"
    SDMMC_CmdInitTypeDef _sdmmc_cmdinit;
    #endif
     
    void seggerError(int8_t itemNo, uint32_t errorstate, SDMMC_CmdInitTypeDef sdmmc_cmdinit)
    {
    	#if DEBUG_SDMMC	== 1
    	
    	if (errorstate != SDMMC_ERROR_NONE)
    	{
    		SEGGER_RTT_printf(0,RTT_CTRL_TEXT_BRIGHT_MAGENTA"************ SDMMC Error: Item = %d Error State = %x ************\n", itemNo, errorstate);	
     
    		if(itemNo < 100)
    		{		
    		sdmmc_cmdinit.Argument = (uint32_t)sdmmc_cmdinit.Argument;
    		sdmmc_cmdinit.CmdIndex = _sdmmc_cmdinit.CmdIndex;
    		sdmmc_cmdinit.Response = _sdmmc_cmdinit.Response;
    		sdmmc_cmdinit.WaitForInterrupt = _sdmmc_cmdinit.WaitForInterrupt;
    		sdmmc_cmdinit.CPSM = _sdmmc_cmdinit.CPSM;
     
    		SEGGER_RTT_printf(0,RTT_CTRL_TEXT_BRIGHT_MAGENTA "Agument = %x\nCmdIndex = CDM%d\nResponse = %x\nWaitForInt = %x\nCPSM = %x\n\n", 
    											_sdmmc_cmdinit.Argument, errorstate, _sdmmc_cmdinit.CmdIndex, _sdmmc_cmdinit.Response, _sdmmc_cmdinit.WaitForInterrupt, _sdmmc_cmdinit.CPSM);	
    		}	
    		
    		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_SET); /* rjgBebug */
    		HAL_Delay(1);
    		HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, GPIO_PIN_RESET); /* rjgBebug */
    	}	
    	#endif
    }

    Best regards

    Rob

    Graduate
    May 26, 2020

    Hi all,

    I also had issues when writing to files and randomly got a "FR_DISK_ERR", which was originally caused by the SDMMC_ERROR_CMD_CRC_FAIL error described above.

    Setting SDMMCx->MASK = 0 in SDMMC_CmdReadMultiBlock and SDMMC_CmdWriteMultiBlock actually solved the problem!

    Thank you for posting this solution!