2022-04-04 10:14 PM
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:
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:
It's trying to send a 512 byte block:
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).
2022-04-06 10:46 PM
I'm still trying to get this working. For now, I've disabled FatFS in the Device Configuration Tool and I'm just trying to work at the HAL level.
First, initialization:
HAL_StatusTypeDef hal_rc = HAL_SD_Init(&hsd1);
if (hal_rc != HAL_OK)
return RES_ERROR;
/* Configure SD Bus width (4 bits mode selected) */
/* Enable wide operation */
if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK)
return RES_ERROR;
Next, to write a block to the SD card:
assert(0 == ((uintptr_t )buff & 0x3)); // Check for WORD alignment for DMA
if (HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t*) buff, sector, count) != HAL_OK) {
return RES_ERROR;
}
At this point I would expect a `HAL_SD_TxCpltCallback` but it never comes.
`HAL_DMA_GetState` just returns HAL_DMA_STATE_BUSY forever.
In hsd1, DLEN and DCOUNT are both 512 (the block size).
DCTRL is Binary:10011001
STA is Binary:100000101000000000000.
MASK is Binary:11010.
In hsd1.hdmatx,
CCR: Binary:10101010011011
CNDTR: Decimal:128 (Hex:0x80)
If I'm reading this right, DCTRL says:
DMA CCR says:
Why isn't my transfer completing?
If I change the code to `HAL_SD_WriteBlocks(&hsd1, (uint8_t*) buff, sector, count, Timeout)` instead of `HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t*) buff, sector, count)` it runs.
I have tried with and without Hardware Flow Control. (If I don't use DMA I get underrun errors without the Flow Control).
2022-04-07 12:21 AM
Hi @CKugl.1
>STM32Cube FW_L4 V1.17.1. I'm using a NUCLEO-L4A6ZG.
AFAIK, this board is not equipped with uSD slot, how are you running the example on it?
are you using an arduino shield?
2022-04-07 08:56 AM
I'm using an Adafruit 4682 Micro SD SPI or SDIO Card Breakout Board wired to SDMMC1. Originally, I used a breadboard and some jumpers. Since then I've moved it to a soldered protoboard plugged into CN8 and CN9 with berg strips (but it doesn't work any better).
2022-04-07 10:14 AM
I can read successfully with DMA, but not write. I.e., HAL_SD_ReadBlocks_DMA works, but HAL_SD_WriteBlocks_DMA does not. If I write with HAL_SD_WriteBlocks and read the data back with HAL_SD_ReadBlocks_DMA, it works, as shown in the attached test case. It produces the following output:
test:152: SD Card State:Card is in transfer state
test:172: SD Card State:Card is in programming state
test:172: SD Card State:Card is in transfer state
test:184: DMA State:DMA initialized and ready for use
test:188: SD Card State:Card is in transfer state
Read data matched.
2022-04-07 01:37 PM
I modified my test case to use HAL_SD_WriteBlocks_DMA. I added some code to print out the SDMMC and DMA registers before and after the call. Here is the output:
test:185: Starting
test:201: SD Card State: Card is in transfer state
test:219: SDMMC registers:
3 2 1 0
10987654321098765432109876543210
POWER : 0b00000000000000000000000000000011
CLKCR : 0b00000000000000000100100100000001
ARG : 0b11100110001001000000000000000000
CMD : 0b00000000000000000000010001001101
RESPCMD: 0b00000000000000000000000000001101
RESP1 : 0b00000000000000000000100100000000
RESP2 : 0b01011011010110010000000000000000
RESP3 : 0b01110110101100100111111110000000
RESP4 : 0b00001010010000000100000000010010
DTIMER : 0b11111111111111111111111111111111
DLEN : 0b00000000000000000000000000001000
DCTRL : 0b00000000000000000000000000110011
DCOUNT : 0b00000000000000000000000000000000
STA : 0b00000000000000000000000000000000
ICR : 0b00000000000000000000000000000000
MASK : 0b00000000000000000000000000000000
FIFOCNT: 0b00000000000000000000000000000000
FIFO : 0b00000011100000000011010100000010
test:221: TX DMA State: DMA initialized and ready for use
test:223: TX DMA registers:
3 2 1 0
10987654321098765432109876543210
CCR : 0b00000000000000000011101010010000
CNDTR : 0b00000000000000000000000000000000
CPAR : 0b00000000000000000000000000000000
CMAR : 0b00000000000000000000000000000000
test:226: Writing
test:233: SDMMC registers:
3 2 1 0
10987654321098765432109876543210
POWER : 0b00000000000000000000000000000011
CLKCR : 0b00000000000000000100100100000001
ARG : 0b00000000000000000000000000000000
CMD : 0b00000000000000000000010001011000
RESPCMD: 0b00000000000000000000000000011000
RESP1 : 0b00000000000000000000100100000000
RESP2 : 0b01011011010110010000000000000000
RESP3 : 0b01110110101100100111111110000000
RESP4 : 0b00001010010000000100000000010010
DTIMER : 0b11111111111111111111111111111111
DLEN : 0b00000000000000000000001000000000
DCTRL : 0b00000000000000000000000010011001
DCOUNT : 0b00000000000000000000001000000000
STA : 0b00000000000101000101000000000000
ICR : 0b00000000000000000000000000000000
MASK : 0b00000000000000000000000000011010
FIFOCNT: 0b00000000000000000000000010000000
FIFO : 0b00000011000000100000000100000000
test:236: TX DMA State: DMA process is ongoing
test:238: TX DMA registers:
3 2 1 0
10987654321098765432109876543210
CCR : 0b00000000000000000011101010011011
CNDTR : 0b00000000000000000000000010000000
CPAR : 0b01000000000000010010100010000000
CMAR : 0b00100000000001001111011111001100
test:245: SD Card State: Card is receiving operation information
test:245: SD Card State: Card is receiving operation information
test:245: SD Card State: Card is receiving operation information
test:245: SD Card State: Card is receiving operation information
test:245: SD Card State: Card is receiving operation information
test:245: SD Card State: Card is receiving operation information
Here is a diff of before and after the HAL_SD_WriteBlocks_DMA call:
1c1
< test:219: SDMMC registers:
---
> test:233: SDMMC registers:
6,8c6,8
< ARG : 0b11100110001001000000000000000000
< CMD : 0b00000000000000000000010001001101
< RESPCMD: 0b00000000000000000000000000001101
---
> ARG : 0b00000000000000000000000000000000
> CMD : 0b00000000000000000000010001011000
> RESPCMD: 0b00000000000000000000000000011000
14,17c14,17
< DLEN : 0b00000000000000000000000000001000
< DCTRL : 0b00000000000000000000000000110011
< DCOUNT : 0b00000000000000000000000000000000
< STA : 0b00000000000000000000000000000000
---
> DLEN : 0b00000000000000000000001000000000
> DCTRL : 0b00000000000000000000000010011001
> DCOUNT : 0b00000000000000000000001000000000
> STA : 0b00000000000101000101000000000000
19,23c19,23
< MASK : 0b00000000000000000000000000000000
< FIFOCNT: 0b00000000000000000000000000000000
< FIFO : 0b00000011100000000011010100000010
< test:221: TX DMA State: DMA initialized and ready for use
< test:223: TX DMA registers:
---
> MASK : 0b00000000000000000000000000011010
> FIFOCNT: 0b00000000000000000000000010000000
> FIFO : 0b00000011000000100000000100000000
> test:236: TX DMA State: DMA process is ongoing
> test:238: TX DMA registers:
26,29c26,29
< CCR : 0b00000000000000000011101010010000
< CNDTR : 0b00000000000000000000000000000000
< CPAR : 0b00000000000000000000000000000000
< CMAR : 0b00000000000000000000000000000000
---
> CCR : 0b00000000000000000011101010011011
> CNDTR : 0b00000000000000000000000010000000
> CPAR : 0b01000000000000010010100010000000
> CMAR : 0b00100000000001001111011111001100
2022-04-08 09:37 PM
I happen to have a NUCLEO-F413ZH lying around, so I unplugged my SD card adapter from the NUCLEO-L4A6ZG and plugged it into that, then ported my test case. It runs great, reading and writing with DMA! However, I need to use the L4 chip (for the low power consumption). So, I'm still trying to figure out why that gets hung up in HAL_SD_WriteBlocks_DMA .
2022-04-11 09:57 AM
I'm back on the NUCLEO-L4A6ZG trying to run the same test case that runs successfully on the NUCLEO-F413ZH.
On the NUCLEO-F413ZH, here's what I see with a logic analyzer on the SD bus when I call HAL_SD_WriteBlocks_DMA:
On the NUCLEO-L4A6ZG, here's what I see with a logic analyzer on the SD bus when I call HAL_SD_WriteBlocks_DMA:
There is no activity at all on the data lines!
Now, again on NUCLEO-L4A6ZG, if I simply change HAL_SD_WriteBlocks_DMA to HAL_SD_WriteBlocks, I get this:
So, when I call HAL_SD_WriteBlocks_DMA on the L4A6ZG, the command is sent but no data is ever sent.
2022-04-11 10:28 AM
Prior to the call to HAL_SD_WriteBlocks_DMA on the L4A6ZG, the TX DMA registers:
TX DMA registers:
3 2 1 0
10987654321098765432109876543210
CCR : 0b00000000000000000011101010010000
CNDTR : 0b00000000000000000000000000000000
CPAR : 0b00000000000000000000000000000000
CMAR : 0b00000000000000000000000000000000
ISR : 0b00000000000000000000000000000000
The DMA channel x configuration register (DMA_CCRx) says:
DMA channel x number of data to transfer register (DMA_CNDTRx) is 0.
DMA channel x peripheral address register (DMA_CPARx) is 0.
DMA channel x memory address register (DMA_CMARx) is 0.
DMA interrupt status register (DMA_ISR) is all 0.
2022-04-11 10:29 AM
The F4 and L4+ have different SDIO vs SDMMC IP, and the L4 has at least 3 implementations, including different approaches to integrating DMA, and using 1 or 2 DMA channels So let's avoid an Apples to Oranges comparison about how thing need to work, because its different between various architectures.
The L496/L4A6 DMA for write should looks something like this, as it has ONE DMA resource, and it must be configured in a directionally appropriate manner.
/**
* @brief Writes block(s) to a specified address in an SD card, in DMA mode.
* @param pData: Pointer to the buffer that will contain the data to transmit
* @param WriteAddr: Address from where data is to be written
* @param NumOfBlocks: Number of SD blocks to write
* @retval SD status
*/
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
HAL_StatusTypeDef sd_state = HAL_OK;
/* Invalidate the dma rx handle*/
uSdHandle.hdmarx = NULL;
/* Prepare the dma channel for a write/tx operation */
sd_state = SD_DMAConfigTx(&uSdHandle);
if (sd_state == HAL_OK)
{
/* Write block(s) in DMA transfer mode */
sd_state = HAL_SD_WriteBlocks_DMA(&uSdHandle, (uint8_t *)pData, WriteAddr, NumOfBlocks);
}
if (sd_state == HAL_OK)
{
return MSD_OK;
}
else
{
return MSD_ERROR;
}
}
...
/**
* @brief Configure the DMA to transmit data to the SD card
* @retval
* HAL_ERROR or HAL_OK
*/
static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd)
{
static DMA_HandleTypeDef hdma_tx;
HAL_StatusTypeDef status;
/* Configure DMA Tx parameters */
hdma_tx.Init.Request = DMA_REQUEST_7;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_tx.Instance = SD_DMAx_STREAM;
/* Associate the DMA handle */
__HAL_LINKDMA(hsd, hdmatx, hdma_tx);
/* Stop any ongoing transfer and reset the state*/
HAL_DMA_Abort(&hdma_tx);
/* Deinitialize the Channel for new transfer */
HAL_DMA_DeInit(&hdma_tx);
/* Configure the DMA Channel */
status = HAL_DMA_Init(&hdma_tx);
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(SD_DMAx_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(SD_DMAx_IRQn);
return (status);
}