cancel
Showing results for 
Search instead for 
Did you mean: 

Fatfs DMA transfer skips the end

TGeof.1
Associate

Hi,

I'm having a very strange issue loading bytes from an SD card into an array in RAM, on a STM32F722RE.

In general, it works nicely, but I have several files where the transfer skips some bytes, leaving zeroes in the destination array.

In debug, I have found the following clues:

1. I'm calling f_read:

if (f_read(file, raw_bytes_buffer.data() + write_offset_in_bytes, bytes_to_read, &bytesread) != FR_OK) return;

2. In f_read, the array is correctly filled up until the index 473.

3. At index 474, the FIL->fptr is exactly 512. This triggers a particular branch in f_read:

// ff.c
if (fp->fptr % SS(fs) == 0) {         /* On the sector boundary? */

This particular branch seems to be the culprit in all cases of this "missing bytes" bug.

4. A function pointer is used to read the disk:

// ff.c
if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);

5. disk_read points to the following function

// bsp_driver_sd.cpp
uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)

6. This function in turn calls the following:

HAL_SD_ReadBlocks_DMA(&_HSD, (uint8_t *) pData, ReadAddr, NumOfBlocks)

7. After completion of the transfer in DMA, indices from 474 to 983 are filled, however indices 984 and 985 are still zeroed (note: After checking manually, the file does *not* have zeroes at this position, obviously)

8. f_read increments the write pointer, and now points to index 986.

TL;DR: f_read tries to read a whole SD sector with DMA, and does not write the last two bytes of said sector to the destination array.

1 ACCEPTED SOLUTION

Accepted Solutions

Make sure memory used by DMA is aligned.

If not using DTCMRAM for DMA buffering make sure you correctly handle cache coherency.

Watch for the 32-byte alignment of By_Addr cache coherency functions.​

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

2 REPLIES 2

Make sure memory used by DMA is aligned.

If not using DTCMRAM for DMA buffering make sure you correctly handle cache coherency.

Watch for the 32-byte alignment of By_Addr cache coherency functions.​

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

It was an alignment issue. The destination pointer pointed to

raw_bytes_buffer.data() + write_offset_in_bytes

And write_offset_in_bytes was not a multiple of 8. Changing the code so that it always is fixed the problem.

Thanks !