STM32F4: 4-bits SDIO DMA - Data Corruption in SD card
- July 22, 2021
- 6 replies
- 5396 views
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!
