cancel
Showing results for 
Search instead for 
Did you mean: 

FatFs on SDMMC1 configured by CubeMX not working with DMA (F722)

Lars Beiderbecke
Senior III
Posted on April 17, 2018 at 18:46

I'm using FatFs on SDMMC1 configured by CubeMX (v.4.23) on a STM32F722. Everything runs perfectly fine.

But when I activate DMA by

  • enabling DMA template in FatFs
  • creating DMA channel for SDMMC1 RX and TX
  • enabling the DMA and SDMMC1 interrupts

I can see that the code in sd_diskio.c has changed, and two IRs have been generated.

But the mounting and/or reading of the SD card fails.

This worked with v.4.22 (even without creating DMA channels), but now doesn't.

What is missing here?

#fatfs #dma
14 REPLIES 14

They just need workable board templates, and to thoroughly test the output. The WHOLE point is to be able check box the features/functions you want from a menu and working code comes out the end. The examples shouldn't need .IOC files, you should be able to click a board and a list of standard examples, and a few more buttons if you want to order a-la-carte. It should be possible to make a template for a custom board, simply, and then use the exact same examples. And board vendors should be encouraged to build/submit templates.

I personally don't care for the way CubeMX obfuscates things, it really should just keep the unique stuff in a single include file, ideally that file should be the "Project" description, replacing the .IOC, and having all the parameters within the comments, like other wizards

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

Hi,

Me too facing similar issue and have some debugging information.

I am working on interfacing the SD card with the following requirement :

CMSIS V2 + FATFS + SDMMC with DMA on STM32L462.

I have configured the project in CubeMX Version 1.3.0. The CMSIS V2 with FREERTOS has been selected from the CUBEMX configuration and using FATFS system for handling data on SD card.

The SDMMC has been configures with DMA having two separate channels for Rx and Tx.

The f_mkfs is working but after that when i call f_mount it is failing.

Following are my observations:

when the f_mount function is called, as part of this functionality the FATFS reads the data from the SD card. Here the function BSP_SD_ReadBlocks_DMA() is called. In the further debugging it is observed that the read data command has been sent to the sd card by sdmmc and upon response from sd card the read data has been stored into the FIFO of the sdmmc peripheral. But the configured DMA is not at all copying the data from sdmmc FIFO to the buffer and since the FATFS is not getting the data on timeout it is resulting in error.

Played with multiple configurations of DMA but no Luck.

Please help me out since its been long days i am trying to debug and figure out the issue.

I don´t know the contents of your fw package for L4. I work with F7 cpu´s... As far, as i´ve recognized, in the fatfs code of my fw package the functions depend on the used cmsis version (v1 or v2...). Maybe give it a try to change to cmsis v1.

You also can check this out:

https://www.youtube.com/watch?v=sVgKUhkwnAQ

It´s based on the f746 discovery, but should basically cover all of the necessary settings for dma, nvic and so on ...

Hi Chaaalyy,

I tried for the changes you suggested but the same issue.

One of the solution to enable Rx and Tx channels separate and alter the DMA stream functions as given in the answer above works but re configuring the DMA Rx and Tx for each transfer is not efficient way. Since i am storing data on SD card at high frequency, the re configuring DMA each time will cost in delay.

ALest
Associate II

I had the same issue. I could read from the SD card if I configured it to use a single DMA channel, but wasn't able to write to the card.

I got it working by configuring 2 DMA channels (RX and TX) in CubeMX under DMA and then enabling them SDMMC1. I then generated the code and modified bsp_driver_sd.c as follows to replace the existing BSP_SD_ReadBlocks_DMA() and BSP_SD_WriteBlocks_DMA() functions. The issue was that the SDMMC1 peripheral is not full duplex, so you can't have both the TX and RX channels selected at the same time. You need to update DMA channel selection register (DMA_CSELR) with the DMA you want to use for that transfer.

/* USER CODE BEGIN BeforeReadDMABlocksSection */
/* can be used to modify previous code / undefine following code / add code */
__weak uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
  uint8_t sd_state = MSD_OK;
 
  /* Reset request selection for DMA2 Channelx - only 1 can be active for SDMMC at a time */
  DMA2_CSELR->CSELR &= ~(DMA_CSELR_C1S << (hsd1.hdmarx->ChannelIndex & 0x1cU));
  DMA2_CSELR->CSELR &= ~(DMA_CSELR_C1S << (hsd1.hdmatx->ChannelIndex & 0x1cU));
 
  /* Configure request selection for DMA2 Channelx */
  DMA2_CSELR->CSELR |= (uint32_t) (hsd1.hdmarx->Init.Request << (hsd1.hdmarx->ChannelIndex & 0x1cU));
 
  /* Read block(s) in DMA transfer mode */
  if (HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK)
  {
    sd_state = MSD_ERROR;
  }
 
  return sd_state;
}
#if 0
/* USER CODE END BeforeReadDMABlocksSection */
/**
  * @brief  Reads block(s) from a specified address in an SD card, in DMA mode.
  * @param  pData: Pointer to the buffer that will contain the data to transmit
  * @param  ReadAddr: Address from where data is to be read
  * @param  NumOfBlocks: Number of SD blocks to read
  * @retval SD status
  */
__weak uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
  uint8_t sd_state = MSD_OK;
 
  /* Read block(s) in DMA transfer mode */
  if (HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks) != HAL_OK)
  {
    sd_state = MSD_ERROR;
  }
 
  return sd_state;
}
 
/* USER CODE BEGIN BeforeWriteDMABlocksSection */
#endif
/* can be used to modify previous code / undefine following code / add code */
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
  uint8_t sd_state = MSD_OK;
 
  /* Reset request selection for DMA2 Channelx - only 1 can be active for SDMMC at a time */
  DMA2_CSELR->CSELR &= ~(DMA_CSELR_C1S << (hsd1.hdmarx->ChannelIndex & 0x1cU));
  DMA2_CSELR->CSELR &= ~(DMA_CSELR_C1S << (hsd1.hdmatx->ChannelIndex & 0x1cU));
 
  /* Configure request selection for DMA2 Channelx */
  DMA2_CSELR->CSELR |= (uint32_t) (hsd1.hdmatx->Init.Request << (hsd1.hdmatx->ChannelIndex & 0x1cU));
 
  /* Write block(s) in DMA transfer mode */
  if (HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK)
  {
    sd_state = MSD_ERROR;
  }
 
  return sd_state;
}
#if 0
/* USER CODE END BeforeWriteDMABlocksSection */
/**
  * @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
  */
__weak uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
  uint8_t sd_state = MSD_OK;
 
  /* Write block(s) in DMA transfer mode */
  if (HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks) != HAL_OK)
  {
    sd_state = MSD_ERROR;
  }
 
  return sd_state;
}
 
/* USER CODE BEGIN BeforeEraseSection */
#endif