Skip to main content
Explorer II
April 5, 2022
Question

FatFS on SDMMC not working with DMA on STM32L4A6ZGT6U

  • April 5, 2022
  • 22 replies
  • 16999 views

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).

    This topic has been closed for replies.

    22 replies

    CKugl.1Author
    Explorer II
    April 13, 2022

    I went to RM0351; Reference manual; STM32L47xxx, STM32L48xxx, STM32L49xxx and STM32L4Axxx

    advanced Arm®-based 32-bit MCUs; June 2021 RM0351 Rev 9, 45.3.2 SDMMC APB2 interface, Example of write procedure using DMA, and implemented it as literally as I could. The behavior is still the same. The SD command (CMD24 WRITE BLOCK) is sent but no data is ever sent. The DMA just doesn't want to run.

    I'm starting to suspect that the STM32L4A6ZGT6U does not work as specified.

    Graduate II
    April 16, 2022

    > implemented it as literally as I could

    I can see a bunch of both - HAL and LL - bloat. Also I see DMA enable=>disable=>enable for some strange reason...

    CKugl.1Author
    Explorer II
    April 17, 2022
    This is throw-away code. I was originally hoping to be able to use HAL for
    this, to save time, but when it didn't work, I started trying to peel the
    onion. Even though I'm trying to work at the register level here, I thought
    macros like
    #define __HAL_DMA_ENABLE(__HANDLE__) ((__HANDLE__)->Instance->CCR |=
    DMA_CCR_EN)
    are pretty obvious and transparent, so why not use them?
    Also I see DMA enable=>disable=>enable for some strange reason...
    This is something I have wondered about. The "Example of write procedure
    using DMA" in *45.3.2 SDMMC APB2 interface* in RM0351 Rev 9 specifically
    says
    *Enable *DMA2 controller and clear any pending interrupts
    but then it goes on to programming the source address register, destination
    address register, and control register (which I would think should be done
    while disabled).
    Then, it says to
    *Enable *DMA2_Channel4 (or DMA2_Channel5)
    I figured they wouldn't need to say that unless it was presumed to be
    disabled at this point. Maybe the distinction I'm missing is the difference
    between enabling the controller and enabling the channel. I know how to
    enable the channel, by turning on bit 0 of CCR. What does the RM mean by
    "Enable DMA2 controller"?
    CKugl.1Author
    Explorer II
    April 18, 2022

    I've opened Case Number 00155966. ST wanted to see it fail with one of their examples, so I ported https://github.com/STMicroelectronics/STM32CubeL4/tree/master/Projects/STM32L476G-EVAL/Applications/FatFs/FatFs_uSD_DMA_RTOS to STM32CubeIDE Version: 1.9.0 Build: 12015_20220302_0855 (UTC), and the NUCLEO-L4A6ZG board. 

    When I run it, it gets as far as this:

    SD_write() at sd_diskio.c:458 0x8009450
    disk_write() at diskio.c:104 0x800966c
    f_mkfs() at ff.c:5,661 0x800c210
    FS_FileOperations() at main.c:510 0x8000c34
    StartDefaultTask() at main.c:608 0x8000dba
    pxPortInitialiseStack() at port.c:214 0x800eb50

    This is the wait in osMessageGet(SDQueueID, SD_TIMEOUT) after 

    BSP_SD_WriteBlocks_DMA((uint32_t*)buff,

                  (uint32_t) (sector),

                  count) == MSD_OK)

    It is waiting for BSP_SD_WriteCpltCallback(void) to osMessagePut(SDQueueID, WRITE_CPLT_MSG, 0), but SDMMC1_IRQHandler is never called because the transmission never completes because the DMA doesn't send any data.

    After a long wait, the SD_TIMEOUT occurs, and it turns on "LED2" indicating an error has occurred. 

    Looking at the TX DMA after the call to BSP_SD_WriteBlocks_DMA, the state is HAL_DMA_STATE_BUSY, "DMA process is ongoing ".

    CCR volatile uint32_t 0x3a9b (Hex) is  Binary:11101010011011:

    • Bits 13:12 PL[1:0]: priority level: 11: very high
    • Bits 11:10 MSIZE[1:0]: memory size: 10: 32 bits
    • Bits 9:8 PSIZE[1:0]: peripheral size: 10: 32 bits
    • Bit 7 MINC: memory increment mode:  1: enabled
    • Bit 6 PINC: peripheral increment mode: 0: disabled
    • Bit 5 CIRC: circular mode: 0: disabled
    • Bit 4 DIR: data transfer direction: 1: read from memory
    • Bit 3 TEIE: transfer error interrupt enable: 1: enabled
    • Bit 2 HTIE: half transfer interrupt enable: 0: disabled
    • Bit 1 TCIE: transfer complete interrupt enable: 1: enabled
    • Bit 0 EN: channel enable: 1: enabled

    ISR volatile uint32_t is all 0. 

    CKugl.1Author
    Explorer II
    April 18, 2022

    Here is a zip archive of the project.

    Visitor II
    July 13, 2022

    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

    CKugl.1Author
    Explorer II
    July 13, 2022

    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.

    Visitor II
    July 14, 2022

    @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?

    Visitor II
    July 13, 2022

    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.

    Visitor II
    July 13, 2022

    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.

    Visitor II
    July 14, 2022

    ** 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

    Visitor II
    July 15, 2022

    @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.

    CKugl.1Author
    Explorer II
    July 15, 2022

    IDMA sounds nice, especially since DMA with SDMMC is somewhat broken on the STM32L496xx/STM32L4A6xx.

    Visitor II
    July 16, 2022

    @Jimmy05​ @CKugl.1​ 

    I used the BSP code for SDMMC available here: \STM32Cube_FW_L5_V1.4.0\Projects\STM32L552E-EV\Applications\FatFs\FatFs_uSD_RTOS and it works perfectly. I will experiment with DMA-based diskio examples later.

    Visitor II
    July 28, 2022

    Hi,

    I would like to share with you about my experiences connected with SDIO and DMA (maybe it will help you with solving your problem).

    I make test with following configuration:

    a) hardware - STM32F767 with connected SDCard (SDIO1, note: lines don't have the pull-up resistors so I used GPIO pull-up's).

    b) software - after SD card initialization is executed test which read and write sector/-s and allow verify reading/writing SD Card procedures.(see function: SDMMC1_SD_Tests)

    Case 1

    Project created by STM32CubeIDE (or CubeMX) - selected only SDIO and DMA.

    Problem was with read and write using DMA.

    Solution - in main.c the initialization DMA and SDIO order was incorrect.

    Correct order:

     MX_DMA_Init();

     MX_SDMMC1_SD_Init();

    Case 2

    Project based on example from STMCube [1] - I tested only from it SDIO with DMA (all USB initializers are disable).

    [1] - STM32Cube_FW_F7_V1.17.0\Projects\STM32746G-Discovery\Applications\USB_Device\MSC_Standalone

    During debugging I observed symptoms similar like in case 1. But in this case the initialization of SDIO and DMA are combine together so the order was OK.

    I found in main.c that CPU cache was enabled (function CPU_CACHE_Enable(void)) when I disable D-Cache (commented line with "SCB_EnableDCache();") everything started work OK.

    I attached working copy of both project. Debug informations are writing to SVO.

    Dont't forget changing priority timebase (if require) - according to description "..care must be taken if HAL_Delay() is called from a peripheral ISR process, the Tick interrupt line must have higher priority (numerically lower) than the peripheral interrupt."