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
CKugl.1
Senior II

After the call to HAL_SD_WriteBlocks_DMA on the L4A6ZG, the TX DMA registers:

TX DMA registers:
                    3         2         1         0
                   10987654321098765432109876543210
        CCR    : 0b00000000000000000011101010011011
        CNDTR  : 0b00000000000000000000000010000000
        CPAR   : 0b01000000000000010010100010000000
        CMAR   : 0b00100000000000000001110101110000
        ISR    : 0b00000000000000000000000000000000

The DMA channel x configuration register (DMA_CCRx) says:

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

DMA channel x number of data to transfer register (DMA_CNDTRx): Decimal:128 (Hex:0x80) (which I assume is the number of WORDS).

DMA channel x peripheral address register (DMA_CPARx) is Hex:0x40012880.

DMA channel x memory address register (DMA_CMARx) is 0x20001d70.

DMA interrupt status register (DMA_ISR) is all 0.

If channel enable is 1: enabled, what's stopping it from running?

Thanks. I tried your code, but it still hangs up:

test:334: Starting

test:339: SD State: SD initialized and ready for use  

test:340: SD Card State: Card is in transfer state        

test:387: TX DMA registers:
                    3         2         1         0
                   10987654321098765432109876543210
        CCR    : 0b00000000000000000011101010011011
        CNDTR  : 0b00000000000000000000000010000000
        CPAR   : 0b01000000000000010010100010000000
        CMAR   : 0b00100000000000000001110101110000
        ISR    : 0b00000000000000000000000000000000

test:394: SD Card State: Card is receiving operation information 

test:396: TX DMA State: DMA process is ongoing       

SD State: SD process ongoing         

test:394: SD Card State: Card is receiving operation information 

test:396: TX DMA State: DMA process is ongoing       

SD State: SD process ongoing         

test:394: SD Card State: Card is receiving operation information 

test:396: TX DMA State: DMA process is ongoing       

SD State: SD process ongoing         

test:394: SD Card State: Card is receiving operation information 

test:396: TX DMA State: DMA process is ongoing       

SD State: SD process ongoing         

test:394: SD Card State: Card is receiving operation information 

test:396: TX DMA State: DMA process is ongoing       

SD State: SD process ongoing         

CKugl.1
Senior II

Do these interrupt priorities seem reasonable?

NVIC Interrupt Table	Enabled	Preemption Priority	Sub Priority																						
Non maskable interrupt	TRUE	0	0																						
Hard fault interrupt	TRUE	0	0																						
Memory management fault	TRUE	0	0																						
Prefetch fault, memory access fault	TRUE	0	0																						
Undefined instruction or illegal state	TRUE	0	0																						
System service call via SWI instruction	TRUE	0	0																						
Debug monitor	TRUE	0	0																						
Pendable request for system service	TRUE	0	0																						
System tick timer	TRUE	15	0																						
PVD/PVM1/PVM2/PVM3/PVM4 interrupts through EXTI lines 16/35/36/37/38	FALSE	0	0																						
Flash global interrupt	FALSE	0	0																						
RCC global interrupt	FALSE	0	0																						
Time base: TIM1 trigger and commutation interrupts and TIM17 global interrupt	TRUE	15	0																						
EXTI line[15:10] interrupts	FALSE	0	0																						
SDMMC1 global interrupt	TRUE	7	0																						
DMA2 channel4 global interrupt	TRUE	6	0																						
DMA2 channel5 global interrupt	TRUE	6	0																						
USB OTG FS global interrupt	FALSE	0	0																						
LPUART1 global interrupt	TRUE	10	0																						
FPU global interrupt	FALSE	0	0																						

In case that's too hard to read:

0693W00000Lxe7dQAB.png

Look to be reasonable.

I'd avoid printing the FIFO register, no good is likely to occur.

I'm not looking to put engineering hours into this.

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

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.

Piranha
Chief II

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

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.1
Senior II

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. 

Here is a zip archive of the project.

ST suggested a workaround (https://community.st.com/s/case/5003W00000HN3wtQAD):

"The issue is not related to SDMMC HAL driver, it's related to the HW link between DMA2 Channel 4 and SDMMC ( this issue to be investigated by the HW team). As a workaround , please only use Channel 5 for read and write operation."

It does work, and saves me a DMA channel, I guess. Here is the reworked example: