cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H7 SDMMC IDMA write multiple blocks error

luke.herbschleb
Associate II

Dear all,

I am working with the sdmmc lib from STM and i am trying to get it working in DS (Default Speed @25Mhz) with a CARD_SDHC_SDXC, CARD_ULTRA_HIGH_SPEED sd card.

When I write multiple blocks with the IDMA for the first time it’s no problem and everything works fine. But when I try it for a second time it fails on the first command I sent SDMMC_CmdBlockLength() (file: stm32h7xx_hal_sd.c line:737) with a SDMMC_ERROR_CMD_CRC_FAIL

I am thinking that the CMD12 (stop commando) is not acknowledged by the sdcard. Thus, it goes to Idle state and is only able to write again after a new write commando.

I do not have a voltage switch on my prototype (this is why i want DS speed) so i disabled USE_SD_TRANSCEIVER = 0. But in the hall (HAL_SD_Init file: stm32h7xx_hal_sd.c line:2147) you have a condisinal statement:

#if (USE_SD_TRANSCEIVER != 0U)
// switch to low voltage
#ELSE
 if((hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) ||
    (hsd->SdCard.CardSpeed == CARD_HIGH_SPEED) ||
      (hsd->SdCard.CardType == CARD_SDHC_SDXC))
 {
   /* Enable High Speed */
 
   if(SD_HighSpeed(hsd) != HAL_SD_ERROR_NONE)
   {
     return HAL_ERROR;
   }
 }
 
#endif /* USE_SD_TRANSCEIVER */

This seems to me that you need to switch if you do not have a “normal�? sd card.

if I try to use HS @ 50Mhz i get the same problem. this is maby because the SD_HighSpeed() (file: stm32h7xx_hal_sd.c line:2779) functions sets the pattern to SDMMC_SDR25_SWITCH_PATTERN

Does anybody less has the same problem and is my multiple blocks write with IDMA as it should be (see picture)?

8 REPLIES 8

With DMA writes you need to ensure the card has completed the operation, the DMA will end once the FIFO is full, but will take time to clear the interface.

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

Most, it not all, MicroSD cards should be capable of 50 MHz signalling, without the transceiver. The transceiver comes into play for low voltage Ultra/DDR modes.

The ST library code has generally been hacked enough to be workable on the developer's individual test system/scenario, it will likely need to be reviewed/reworked for commercial use.

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

The interrupt handler from the hal (HAL_SD_IRQHandler()) has a call-back HAL_SD_TxCpltCallback() and i used this to check if i am able to write again.

This call back is based on the SDMMC_FLAG_DATAEND but to be sure I also tried SDMMC_IT_IDMABTC

Also in blocking mode (HAL_SD_WriteBlocks() ) I get the same error. This means that there is someting wrong with my init. But i cant figure out wat it is.

luke.herbschleb
Associate II

I have fount the solution!

The problem was with the HAL_SD_WriteBlocks_DMA().

The HAL_SD_WriteBlocks_DMA() will try to set the block length of the write command.

For SD is this size fixed(512 bytes) and this will trow the state-machine off.

The solution is to remove this part from the code.

/* Remove set Block Size for Card */
    errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
      hsd->ErrorCode |= errorstate;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }

Garnett.Robert
Senior III

Hi,

I had a problem with random write and read block failures and tracked them down to the SDMMC_ERROR_CMD_CRC_FAIL.

It didn't make much sense as I was only driving the cards at 50 MHz (It's a Sandisk High Speed card) and I carefully kept the buss lengths equal (19 mm). This gives a transmission delay of about 0.3 ns of clock skew on the receive clock. I am not using a transceiver mainly because they only come in BGA which makes for expensive pcb's.

I have done as you suggested. I used a compiler directive to remove the block length function vis:

    /* Set Block Size for Card */
#if SD_CARD_BLOCKSIZE_SET_CMD16_INCL == 1		
    errorstate = SDMMC_CmdBlockLength(hsd->Instance, BLOCKSIZE);
    if(errorstate != HAL_SD_ERROR_NONE)
    {
      /* Clear all the static flags */
      __HAL_SD_CLEAR_FLAG(hsd, SDMMC_STATIC_FLAGS);
      hsd->ErrorCode |= errorstate;
      hsd->State = HAL_SD_STATE_READY;
      return HAL_ERROR;
    }
 #endif

This makes it easy to put it back in if required.

I had a look at the SD Card standard and found the following excepts regarding using CMD16 - SET_BLOCKLEN:

"Parameter set commands are not allowed while the card is programming. Parameter set commands are:

set block length (CMD16), erase block start (CMD32) and erase block end (CMD33). "

"The default block length is as specified in the CSD (512 bytes). A set block length of less than 512 bytes will

cause a write error. The only valid write set block length is 512 bytes. CMD16 is not mandatory if the default is

accepted. "

"The default block length is as specified in the CSD (512 bytes). A set block length of less than 512 bytes will

cause a write error. The only valid write set block length is 512 bytes. CMD16 is not mandatory if the default is

accepted"

I had a look at the SD Card timing and waveform right at the sd card socket for reads and writes and got the following pix:

Write to card:

Read from card:

As you can see the waveforms good and the data setup and hold times are good, so I couldn't see how the CRC errors could be caused by poor data on the bus. And I only seem to get these errors on the SDMMC_GetCmdResp1(... commands and not during the far longer card data streams on the 4 bit bus. I wasn't getting data CRC errors only command line errors.

Another odd thing is that I can do a thousand or more database insert commands before I get an error; so it works most of the time. A database insert does reads and writes to a couple of different files with fairly long data streams.

When I did the tests shown in the pix I was running the card at 33 MHz as I was clutching at straws before I read you post. I can't say removing the block length commands has worked yet, but I'm hopefull.

In any event it would appear from the SD card standard info that you don't have to use the cmd16 anyway if you are using the standard 512 byte blocksize. Which of course I am.

Best regards

Rob

Garnett.Robert
Senior III

Sorry pix not included.

Pls find attached here.

Garnett.Robert
Senior III

Read Pix

Hi all

Removing the set block size command did not fix my random read/write failures. I have not reinstated this code.

I suspected that fatFS was having trouble with cards of 64G or greater, so I tried an 8G card. This worked fine with over 10000 transactions and no errors.

I then thought that my fatFS config might be wrong so I went to the fatFS website and found that you have to have the Logical Block Addressing (LBA) set to 64 Bits. Viz

#define FF_LBA64		1
/* This option switches support for 64-bit LBA. (0:Disable or 1:Enable)

I had this turned on, but it needed a GPT disk rather than an MBR disk formatted with exFat.

I used MiniTool Partition Wizard which may be found at https://www.partitionwizard.com/

This is a very nice tool.

Using a 128 GB Sandisk Extreme uSD Card I created a GPT disk formatted with exFat with a unit (cluster) size of 16 k.

I copied my empty databases onto this disk and mounted the card on my embedded system.

Voila! It worked straight away. It has currently processed 7,000 transactions without a failure.

So it would seem for SD Cards >32GB

  1. Partition the sd card as GPT using a partition program or if you like command line use diskpart with the convert command. Or you can write the fatFS code for disk partitioning/formatting on the embedded system
  2. Format the disk as exFat setting the unit size to an appropriate one for your data
  3. Make sure fatFS has the following configs:

#define FF_FS_EXFAT		1  
#define FF_LBA64		1     /* 64 Bit */
#define FF_USE_LFN		3      /* Enable LFN with dynamic working buffer on the HEAP */
#define FF_MAX_LFN		255  /* Don't change this as I did and it ended badly */

I have attached the config file to this post.

I use freeRTOS and I make the SD Card tasks high priority and I also make the SDMMC1 interrupt one of the highest. This reduces the liklihood of other interrupts and tasks causing delays in sd card processing that could cause timeouts of the drivers.

Hope this is useful to someone.

I hope to post the entire project in a couple of weeks so you can see how it fits together.

Best regards

Rob