cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4: 4-bits SDIO DMA - Data Corruption in SD card

ZTan.2
Associate II

Hi, I'm currently using STM32F401RE Nucleo-64 Board.

My current objective is to store all the data collected from ISM330DLC Accelerometer, into SD card through SDIO protocol.

Background

Most of the setup is based on Code generation, using STM32CubeIDE Device Configuration Tool. I've selected SD 4 bits Wide Mode, with DMA settings enabled.

PCLK2 = 84MHz, SDIOCLK = PLL48CLK and SDIO_CK = 24Mhz (Taking CLKDIV = 0)

For my SD card, I'm using SanDisk 32Gb SDHC Class 10 microSD.

I was initially met with a problem of having f_write stuck in BSP_SD_WriteBlocks_DMA. But it was resolved after following this post (https://community.st.com/s/feed/0D50X00009XkVtKSAV) Therefore, I'm using only DMA2_Stream3 for both RX and TX.

As for the priority (SDIO has a stronger pre-empt priority than DMA)

HAL_NVIC_SetPriority(SDIO_IRQn, 4, 0);

HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 5, 0);

Summary of the Problem

Whenever the readings from the accelerometer is collected (upon each interrupt), it will set a flag "dataReceived = 1;". In the main loop, it will keep polling for the flag.

If the flag is raised, then format the data using snprintf() and store it into an array of size 9216 (9k bytes). After which, Use FATFS - f_write() to send all the contents in the array to the SD card. (Assumption: f_write() will instruct DMA controller to send the data properly; such that f_write -> disk_write() -> SD_write()-> BSP_SD_WriteBlocks_DMA)

Problem

The data in my SD card seems proper, except that some lines are kind of corrupted (usually with some random numbers or newline character) in a consistent fashion (e.g. between 27th & 28th reading of sample 1, around 382th reading of sample 1, etc)

I've attached 2 TXTs (ODR_FIFO1 & ODR_FIFO2) for a better understanding.

So I'm really at a lost of what the problem actually is. I've placed a breakpoint before f_write and it seems the formatted string in the 9k buffer is correct. So I assume the problem lies in f_write() and DMA.

I've checked the errata sheet, and I'm suspicious of "No underrun detection with wrong data transmission" under SDIO section. I've tried to reduce SDIO_CK by increasing CLKDIV but doesn't seem to work.

Details of my configuration

In my main loop():

MX_SDIO_SD_Init();
MX_FATFS_Init();
BSP_SD_Init();

In main.c

static void MX_SDIO_SD_Init(void)
{
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd.Init.ClockDiv = 0;
}

DMA Settings in HAL_SD_MspInit()

/* SDIO_RX Init */
    hdma_sdio_rx.Instance = DMA2_Stream3;
    hdma_sdio_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_sdio_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_sdio_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdio_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdio_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdio_rx.Init.Mode = DMA_PFCTRL;
    hdma_sdio_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_sdio_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_sdio_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_sdio_rx.Init.MemBurst = DMA_MBURST_INC4;
    hdma_sdio_rx.Init.PeriphBurst = DMA_PBURST_INC4;
    if (HAL_DMA_Init(&hdma_sdio_rx) != HAL_OK)
    {
      Error_Handler();
    }
    __HAL_LINKDMA(hsd,hdmarx,hdma_sdio_rx);
 
    /* SDIO_TX Init */
    hdma_sdio_tx.Instance = DMA2_Stream3;
    hdma_sdio_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_sdio_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_sdio_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdio_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdio_tx.Init.Mode = DMA_PFCTRL;
    hdma_sdio_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_sdio_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_sdio_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_sdio_tx.Init.MemBurst = DMA_MBURST_INC4;
    hdma_sdio_tx.Init.PeriphBurst = DMA_PBURST_INC4;
    if (HAL_DMA_Init(&hdma_sdio_tx) != HAL_OK)
    {
      Error_Handler();
    }
    __HAL_LINKDMA(hsd,hdmatx,hdma_sdio_tx);

Let me know if other details is required.

I would appreciate any kind advice to work on this problem.

I've tried to understand SDIO and FATFS a little more in-depth (E.g. cmd index, block size, etc), but it's a little overwhelming at the moment. So I'll like some direction to work on this issue.

Thank you!

1 ACCEPTED SOLUTION

Accepted Solutions

Seems a bit subtle.

Might want to generate a CRC for each block of data you write, and compare that to an equivalent PC side program when you read back the same blocking. Do it real-time rather than via debugger.

Double check the buffer is aligned (32-bit for DMA)

Check stack usage

Review code generating the data in the buffer

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

View solution in original post

6 REPLIES 6
TDK
Guru

I would verify that the 9kB buffer isn't being corrupted by a rogue write.

SD communication has a CRC type self-check on data sent, so it's unlikely the data is corrupted after it's sent.

You could try 1-bit communication to see if it has the same issue.

If you feel a post has answered your question, please click "Accept as Solution".

Seems a bit subtle.

Might want to generate a CRC for each block of data you write, and compare that to an equivalent PC side program when you read back the same blocking. Do it real-time rather than via debugger.

Double check the buffer is aligned (32-bit for DMA)

Check stack usage

Review code generating the data in the buffer

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

Hi!

I have a question about the "4-bit" part.

CubeMX ALWAYS sets buswide parameter as 1B.

hsd.Init.BusWide = SDIO_BUS_WIDE_1B;

Are you sure that you are working in 4-bits?

I'm asking because I have the same problem and I'm looking for a solution for a long time now haha.

TDK
Guru

SD communications always start in 1 bit mode and later switch to 4-bit mode through the use of a command. If you have it set up in 4-bit mode and search your program, you will find it.

If you feel a post has answered your question, please click "Accept as Solution".

Thanks!

ZTan.2
Associate II

@TDK​ @Community member​  Thanks for the response.

It has definitely narrowed my search to resolve the issue.

In fact, this issue was resolved last week with the help from this thread:

(https://community.st.com/s/question/0D50X0000BDoJ5a/fatfs-fwrite-writes-wrong-data-to-file-when-writing-odd-number-of-bytes)

I believe the issue has to do with the buffer not 32-bits aligned.

After all, the contents in the buffer varies depending on the readings from the accelerometer.

I hate to admit that I've yet to understand what actually transpired in the lower levels (due to my limited understanding of the SDIO protocol and FATFS).

But I'm especially grateful for the kind response on this matter.