2022-06-23 08:08 AM
Hello,
I am currently trying to get an Adafruit Feather STM32F405 board to write to files on an SD card using DMA. I'm using CubeIDE, not STM32duino, and I have tried DMA configurations with both a single stream and two streams (one RX and one TX). No matter how I have the hardware configured, I am unable to ever complete more than one operation with the SD card.
For example, if I try writing or reading blocks with the raw HAL_SD_ReadBlocks_DMA or WriteBlocks_DMA function, only one call will ever succeed. All the following calls will return an error, usually that the "card is not ready". The same happens when I try to use FatFs: I can open a file (including creating it if necessary), but I can never write to it.
I need SD DMA because I'm using ADC DMA to capture multiple channels at high speed, and I think using polling mode interferes with the ADC HalfCplt and Cplt interrupts.
I do know that the SD card and SD peripheral work, because I can configure CubeIDE to generate code for polling mode.
This is my DMA stream configuration. I have also tried using a single stream and modifying the BSP code (for FatFs) to change the direction of the streams before calling Read/Write_DMA() functions, with no effect. I have the clock divider bypass, the clock power save, and the hardware flow control on the peripheral all disabled, and my clock divide factor is set to 8 (which seems to be a reliable value based on my own polling mode reliability tests). The pins themselves are configured pull-up at medium speed.
What am I doing wrong? I have seen numerous examples where SD DMA "just works", and yet I have had no success ever.
This is the FatFs code I'm trying to run which always fails at the f_write() call (blink() is a function I wrote that just blinks the built-in LED on the Feather board, because I haven't gotten USB set up yet):
FATFS fs = {0};
FRESULT res;
FIL fil;
UINT written;
res = f_mount(&fs, "", 0);
if (res != FR_OK) {
blink(100);
}
res = f_open(&fil, "speed.bin", FA_WRITE|FA_CREATE_ALWAYS);
if (res != FR_OK) {
blink(500);
}
const char data[512] = {0};
res = f_write(&fil, data, sizeof(data), &written);
if (res != FR_OK) {
// it's blinking 1 sec, and error 1 means FatFs error "low level disk error"
blink(res*1000);
}
if (written != sizeof(data)) {
blink(1500);
}
res = f_sync(&fil);
if (res != FR_OK) {
blink(2000);
}
res = f_close(&fil);
if (res != FR_OK) {
blink(3000);
}
2022-06-23 12:23 PM
Top level FsFat code is mostly irrelevant to its underlying function.
What memory addresses are you using? 0x10000000 CCM doesn't support DMA
The memory also needs to be aligned, ie 4-byte / 32-bit aligned
What error status does the DMA unit indicate?
The stuff you need to get right is in DISKIO, ST often provides some examples under the middleware's directory in CubeF4
2022-06-24 08:15 AM
So far, I've gotten FatFs with SD DMA to work exactly once. I used two DMA streams, one for SDIO_TX and one for SDIO_RX, selected in the IOC editor. I also started using USB for debugging, and I think configuring the clocks to make that work might have helped with the SD card, but I'm not sure. Put simply, I don't know why SD DMA worked properly that time.
I don't know what memory addresses I'm using, but my data buffer is defined and aligned with
#define NSAMPLES 32768
uint16_t sampleData[NSAMPLES] __attribute__((aligned (4))) = {0};
I'm using a large number of samples because of what I've read about the sizes needed to have an efficient SD write. I intend to use a ping-pong buffer approach to write ADC data once I have the SD card working. However, even with ADC DMA and interrupts disabled, and the ADC not running, the SD DMA still fails as I explained initially.
After the first and only successful SD transfer, the SD state is HAL_SD_CARD_TRANSFER. The very sparse information I've found about HAL_SD_CardStateTypeDef says that TRANSFER indicates that the card is ready for data transfer, so why would there be any error at all?
2022-06-27 03:59 PM
Using a single DMA stream and adapting the code from here (https://community.st.com/s/question/0D53W00000rXmp7SAC/how-do-i-change-the-direction-of-a-dma-request-for-the-sdmmc-device) to change the DMA direction in the BSP functions makes reading any number of blocks with HAL_SD_ReadBlocks_DMA() work, but no data is actually transferred---or it isn't correct, at least.
On another note, I can't get CDC_Transmit_FS() to write data from a memory buffer. Much less of an issue, but still odd.