cancel
Showing results for 
Search instead for 
Did you mean: 

Corrupt data every 4096 bytes writing to SD card using FatFS (STM32L4, CMSIS V2 RTOS)

FZhen.4
Associate

Dear community,

I'm using an STM32L4 with SDIO 4 bit, FATFS, STM32L4 HAL and CMSIS V2 FreeRTOS. Data is written from sensors from interrupt routines and queued into one of the two buffers. When the current buffer has insufficient space to accommodate the incoming data, the remaining part of the data is stored in the next buffer. Then, the two buffers are swapped so that the next buffer becomes the current buffer.

When reading the data that has been written to the SD card successfully, I notice, that every 4096 bytes, the value at that address is 0x00. Do you see obvious mistakes made in this code that is the cause of this problem? I can't seem to find what is wrong.

Thank you so much for having a look into this.

Kind regards.

#include "stm32l4xx.h"
#include "stm32l4xx_hal.h"
 
#include "cmsis_os.h"
#include "fatfs.h"
 
#include <stdint.h>
#include <stdbool.h>
 
#define IO_SD_BUF_SIZE 2048
#define IO_SYNC_SIZE (1 << 20) // 1 MB file size per sync (max)
#define IO_TIMEOUT 500
 
FATFS sd_fs;
FIL sd_file;
bool sd_mounted;
bool sd_file_open;
 
UINT sd_bytes_written;
uint32_t sd_bytes_synced;
uint32_t sd_total_bytes_written;
 
uint8_t sd_buf_1[IO_SD_BUF_SIZE];
uint8_t sd_buf_2[IO_SD_BUF_SIZE];
 
uint_fast16_t sd_buf_1_pos;
uint_fast16_t sd_buf_2_pos;
 
uint8_t *sd_buf_cur;
 
static inline void _IO_SD_Transmit(uint8_t *data, uint8_t data_len) {
    // Serialize access to buffer, as multiple print tasks access this function
    osMutexAcquire(mutex_sd_buffering, IO_TIMEOUT);
 
    uint8_t *next_buf = (sd_buf_cur == sd_buf_1) ? sd_buf_2 : sd_buf_1;
    uint_fast16_t *cur_buf_pos = (sd_buf_cur == sd_buf_1) ? &sd_buf_1_pos : &sd_buf_2_pos;
    uint_fast16_t *next_buf_pos = (sd_buf_cur == sd_buf_1) ? &sd_buf_2_pos : &sd_buf_1_pos;
    uint_fast16_t cur_buf_space = IO_SD_BUF_SIZE - *cur_buf_pos;
 
    // Check if current buffer has enough space
    if (cur_buf_space >= data_len) {
        memcpy(sd_buf_cur + *cur_buf_pos, data, data_len);
        *cur_buf_pos += data_len;
    }
    else {
        // Fill current buffer to its last byte
        memcpy(sd_buf_cur + *cur_buf_pos, data, cur_buf_space);
        uint32_t remaining_data_len = data_len - cur_buf_space;
        // Put the remaining part into the next buffer
        memcpy(next_buf + *next_buf_pos, data + cur_buf_space, remaining_data_len);
        *next_buf_pos += remaining_data_len;
 
        // Swap buffers
        if (sd_buf_cur == sd_buf_1)
            sd_buf_1_pos = 0;
        else
            sd_buf_2_pos = 0;
        sd_buf_cur = next_buf;
        osSemaphoreRelease(io_sync_semaphore);
    }
    osMutexRelease(mutex_sd_buffering);
}
 
static void _IO_Sync_Task(void *arg) {
	io_sync_semaphore = osSemaphoreNew(1, 0, NULL);
	for ever {
		osSemaphoreAcquire(io_sync_semaphore, osWaitForever);
		FRESULT fres;
		if(sd_mounted) {
			if(sd_file_open) {
				osMutexAcquire(mutex_sd, IO_TIMEOUT);
				// If sd_buf_1 is active, write sd_buf_2
				if(sd_buf_cur == sd_buf_1)
					fres = f_write(&sd_file, sd_buf_2, IO_SD_BUF_SIZE, &sd_bytes_written);
				else
					fres = f_write(&sd_file, sd_buf_1, IO_SD_BUF_SIZE, &sd_bytes_written);
				osMutexRelease(mutex_sd);
 
				if(fres == FR_OK) {
					sd_bytes_synced += IO_SD_BUF_SIZE;
					// If total bytes exceed sync size, synchronize and continue logging
					if(sd_bytes_synced > IO_SYNC_SIZE) {
						osMutexAcquire(mutex_sd, IO_TIMEOUT);
						sd_total_bytes_written += sd_bytes_synced;
						sd_bytes_synced = 0;
						f_sync(&sd_file);
						osMutexRelease(mutex_sd);
					}
				}
			}
		}
	}
}

0 REPLIES 0