cancel
Showing results for 
Search instead for 
Did you mean: 

FatFS on SDMMC not working with DMA on STM32L4A6ZGT6U

CKugl.1
Senior II

I'm on STM32CubeIDE Version: 1.9.0 Build: 12015_20220302_0855 (UTC), MCU STM32L4A6ZGTx, Firmware STM32Cube FW_L4 V1.17.1. I'm using a NUCLEO-L4A6ZG.

I'm trying to get FatFS working on SDMMC, with DMA, and having problems.

First, the bundled version of FatFS seems to be ancient. It is so old that it doesn't resemble the documented API at http://elm-chan.org/fsw/ff/00index_e.html. Is there a way I can update it such that my changes won't be wiped out each time I run or update the Device Configuration tool?

The big problem is that it won't work if I select "Use dma template" in Device Configuration Tool/Pinout & Configuration/FATFS/Advanced Settings. If I disable "Use dma template", it works OK (with polling).

With DMA enabled, it gets hung up here:

SD_write() at sd_diskio.c:351 0x80081c8

disk_write() at diskio.c:104 0x800837c

f_mkfs() at ff.c:5,661 0x8008af0

test() at test.c:23 0x80011fc

main() at main.c:103 0x8000914

where I see

if(BSP_SD_WriteBlocks_DMA((uint32_t*)buff,
                              (uint32_t)(sector),
                              count) == MSD_OK)
    {
      /* Wait that writing process is completed or a timeout occurs */
 
      timeout = HAL_GetTick();
      while((WriteStatus == 0) && ((HAL_GetTick() - timeout) < SD_TIMEOUT))
      {
      }
      /* in case of a timeout return error */
      if (WriteStatus == 0)
      {
        res = RES_ERROR;
      }

(SD_write() at sd_diskio.c:351 is line 8 in the snippet).

Apparently, it is waiting for BSP_SD_WriteCpltCallback (or HAL_SD_TxCpltCallback, HAL_SD_IRQHandler, SDMMC1_IRQHandler) which is never called:

void BSP_SD_WriteCpltCallback(void)
{
 
  WriteStatus = 1;
}

At this point, if I look at hsd1, I see:

Instance SDMMC_TypeDef * 0x40012800 (Hex)

POWER volatile uint32_t 0x3 (Hex)

CLKCR volatile uint32_t 0x4900 (Hex)

ARG volatile uint32_t 0x3f (Hex)

CMD volatile uint32_t 0x458 (Hex)

RESPCMD const volatile uint32_t 0x18 (Hex)

RESP1 const volatile uint32_t 0x900 (Hex)

RESP2 const volatile uint32_t 0x5b590000 (Hex)

RESP3 const volatile uint32_t 0x76b27f80 (Hex)

RESP4 const volatile uint32_t 0xa404012 (Hex)

DTIMER volatile uint32_t 0xffffffff (Hex)

DLEN volatile uint32_t 0x200 (Hex)

DCTRL volatile uint32_t 0x99 (Hex)

DCOUNT const volatile uint32_t 0x200 (Hex)

STA const volatile uint32_t 0x145000 (Hex)

ICR volatile uint32_t 0x0 (Hex)

MASK volatile uint32_t 0x1a (Hex)

RESERVED0 uint32_t [2] 0x40012840 (Hex)

FIFOCNT const volatile uint32_t 0x80 (Hex)

RESERVED1 uint32_t [13] 0x4001284c (Hex)

FIFO volatile uint32_t 0x4d90feeb (Hex)

I find it interesting that the MASK is Binary:11010, so only bits 1, 3, and 4 are set, which are:

  • Bit 1 DCRCFAILIE: Data CRC fail interrupt enable
  • Bit 3 DTIMEOUTIE: Data timeout interrupt enable
  • Bit 4 TXUNDERRIE: Tx FIFO underrun error interrupt enable

so this list does not include Bit 8 DATAENDIE: Data end interrupt enable.

STA is Binary:101000101000000000000, which is bits 12, 14, 18, and 20:

  • Bit 20 TXDAVL: Data available in transmit FIFO
  • Bit 18 TXFIFOE: Transmit FIFO empty
  • Bit 14 TXFIFOHE: Transmit FIFO half empty: at least 8 words can be written into the FIFO
  • Bit 12 TXACT: Data transmit in progress

It's trying to send a 512 byte block:

  • DLEN volatile uint32_t 0x200 (Hex)
  • DCOUNT const volatile uint32_t 0x200 (Hex)

Since DCOUNT has not decremented, it looks like no data has been transferred.

What could be the problem?

I put the project on GitHub: https://github.com/carlk3/STM32L4A6ZGTx_SDMMC. It should be complete enough to build. (Is that the best way to share code here? It's fairly painless with EGit: the Git integration for Eclipse).

40 REPLIES 40
Zaher
Senior II

Well, I was experimenting with SDMMC<>FATFS <> FreeRTOS for several hours now and I have noticed some strange behavior trying to write/read the uSD card. I have built a custom board with same socket and pull-ups as those mounted on dev board. Target device used is STM32L552ZE. I'm not using the BSP code, but the HAL_SD API. Before proceeding to FatFs, I tested writing a 512 byte buffer to the card using the DMA mode, HAL_SD_WriteBlocks_DMA(), and it works flawlessly. I just setup the DMA2CH4 (memtomem) from CubeMX, but didn't see more settings like those you have for SDIO for Rx and Tx. Like Clive said, the implementation for SDMMC seems different.

Problems started to appear as I have added FatFs. First, MX_SDMMC1_SD_Init(); returns error if no SD card is plugged into socket, but that's only before adding FatFs module. If FatFs was added, MX_SDMMC1_SD_Init(); always returns OK, no matter whether the card is inserted or not. I just can't figure out what has changed since FatFs was added. Even if MX_FATFS_Init was commented out, the behavior stays the same. Reading or writing the card using the HAL_SD API generates a HardFault, but this is only the case when FatFs was added. I removed FatFs, tried again, write/read functions work.

I didn't want to report this before I allow myself plenty of time to experiment and get concrete results. I'm now getting fluctuating results and couldn't tell where is the problem exactly. The funny thing is, last experiment I made, I was able to read card using DMA, but reading blocks without DMA always fires a Hard Fault.

By the way, the SDMMC is fed from 48 Mhz clock. No divider. I tried with different divider settings, but to no avail.

Regards,

Zaher

Zaher
Senior II

Just made another test, and got different result. If I call HAL_SD_ReadBlocks() after I write a 512 bytes buffer to card using HAL_SD_WriteBlocks(), the function works. However, if HAL_SD_ReadBlocks() was called first on its own, the HardFault IRQ fires. HAL_SD_ReadBlocks_DMA() works always even if called first prior to any write calls.

Problems started to appear as I have added FatFs. First, MX_SDMMC1_SD_Init(); returns error if no SD card is plugged into socket, but that's only before adding FatFs module. If FatFs was added, MX_SDMMC1_SD_Init(); always returns OK, no matter whether the card is inserted or not. I just can't figure out what has changed since FatFs was added. Even if MX_FATFS_Init was commented out, the behavior stays the same.

Even though you're not using BSP, you might be indirectly calling

__weak uint8_t BSP_SD_IsDetected(void)

Since it is __weak, adding FatFs might override it with a different implementation.

Reading or writing the card using the HAL_SD API generates a HardFault, but this is only the case when FatFs was added. I removed FatFs, tried again, write/read functions work.

Before attempting to get FatFs running, I highly recommend getting Elm Chan's "Low level disk I/O module function checker" working perfectly. It's a lot easier to debug at the lower level.

Zaher
Senior II

I'm still trying. Just re-generated the project again and started from scratch. For now, I can write/read the uSD card using the DMA. And by the way, in case someone is wondering where is the DMA tab for SDMMC in CubeMX, the SDMMC has an internal DMA and doesn't need any configuration to use it. Here's what I found in the STM32L5xx_hal_sd.c source file: "No general propose DMA Configuration is needed, an Internal DMA for SDMMC Peripheral are used."

So, general (PURPOSE) DMAs are not needed for SDMMC. FatFs has been added again, and I'm now trying to configure some disk IO layers for multiple volumes. Will report any results back here.

Zaher
Senior II

** Update **

f_mount fails when using DMA write/read functions

f_mkfs() always generates a HardFault

Writing to file returns the following: FR_INVALID_OBJECT

@CKugl.1​ Will take a look at the resource you provided. Also, I will try to adapt the BSP code and see if that makes any difference. By the way, is there any known issues when using FatFs with RTOS? Like moving the MX_FATFS initialize, linking drive, and any calls to the FatFs API to RTOS task?

I don't know of any issues. A month ago, I uploaded an example, above, of FreeRTOS and FatFs working together on the STM32L496xx/STM32L4A6xx (on NUCLEO-L496ZG/NUCLEO-L4A6ZG): Cube_FatFs_uSD_DMA_RTOS_1DMA.

I will say that I eventually abandoned the FreeRTOS and FatFs components in the Device Configuration Tool, although I borrowed a lot of code from them, because I wanted to run current versions (https://github.com/FreeRTOS/FreeRTOS-Kernel and http://elm-chan.org/fsw/ff/00index_e.html)*. And then, for one of my projects, I decided that I needed more concurrency support in FAT and directory operations than that provided by FatFs, so I switched to FreeRTOS +FAT (https://github.com/FreeRTOS/Lab-Project-FreeRTOS-FAT).

* among other things

"I will say that I eventually abandoned the FreeRTOS and FatFs components in the Device Configuration Tool,"

I agree. CubeMX generated code can be a source for a lot of discrepancy and confusion at times, however, it's still very helpful tool from ST.

I have downloaded your example project. I was going to test it as is on my device, but it seems they are not pin compatible with the L5. On more thing regarding the SDMMC with DMA. First, as far as I understand, SDMMC has an internal DMA and requires no additional setup to utilize it with SDMMC. However, in your project, I opened the CubeMC IOC file and found that the DMA Settings tab is there where you have added two streams for the peripheral, Rx and Tx. Not only this, but also in the Middleware > FATFS > Advanced Settings, you have the option to use DMA Template, as well as, BSP code for SD. I was wondering why all of these were not available for my device in CubeMx.

Could it be that you started the project for a board and not a device so you had these additional options?

Zaher

By the way, your target device (STM32L4A6ZGT6U) and mine (STM32L552ZE) are both LQFP144 package. I supposed they should be pin compatible. Also, I see that you have used a clock divider of 14 for the SDMMC. Did you have any troubles with faster clocks?

Zaher
Senior II

@CKugl.1​ 

** Update **

Well, referring to the RM of L4, it seems it's using the traditional general purpose DMA, while the L5 uses the IDMA.