Skip to main content
Visitor II
April 17, 2018
Solved

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

  • April 17, 2018
  • 4 replies
  • 3672 views
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
    This topic has been closed for replies.
    Best answer by Lars Beiderbecke

    It's working for me now.

    In CubeMX, you have to enable DMA mode, but then also manually create DMA TX and RX streams, and enable SDMMC1, DMA TX, and DMA RX interrupts.

    No more problems for me, at least when using a soldered uSD connector (not a breakout board).

    4 replies

    Visitor II
    April 18, 2018
    Posted on April 18, 2018 at 21:06

    I upgraded to CubeMX v4.25 with firmware v1.11, as people said it would work out of the box with that version. Alas, not for me.

    Most code changes suggested here in the forum are already present in the code generated by CubeMX. The BSP_SD_Init() was also fixed. As suggested here, I tried both AXI and TCM interface, but no go.

    Right now my setup looks like the one in the SDIO+DMA+FatFs+CubeMX PDF that was posted here somewhere, except for the code changes. I'm also using SDMMC1 and only 1 wire right now.

    Nothing works, the f_mount always fails. Are there any other guides on how to configure DMA with CubeMX? Are there other requirements? Or code changes needed for v.4.25 code?

    Technical Moderator
    April 20, 2018
    Posted on April 20, 2018 at 17:30

    Hello

    pub

    ,

    Please refer to

    https://community.st.com/0D50X00009bMM8bSAG

    and

    https://community.st.com/0D50X00009XkXgUSAV

    discussion, this may help you.

    Best Regards,

    Imen

    Visitor II
    April 21, 2018
    Posted on April 21, 2018 at 13:34

    Thanks for the reply, but I had the correction already applied.  In fact, the lastest CubeMX has this problem fixed.

    Without DMA, FatFs is working fine for me, but with DMA the f_mount fails.

    Visitor II
    July 17, 2019

    I have similar issues with the CubeMX and CubeIDE (that includes CubeMX).

    After updating CubeMX and regenerating the code, my previous fix for STM32L4+SDMMC+FreeRTOS+FatFs+DMA does not work anymore. It looks like ST made an attempt to correct the issue (and probably corrected for some MCUs, but not for L4). Too bad, neither newly generated code nor my previous fix work at the moment. Some posts above are for MCUs with 2 dedicated channels for TX and RX. The L4 MCU I am using has only one dedicated DMA channel, so I am wondering how to address this problem...

    Also, if ST promotes the CubeMX application, why can't they make their Cube firmware packages with all the examples generated by CubeMX (with addition of some code if necessary and *.ioc files provided)? If it is done this way, there wouldn't be any concerns of matching the working "cube" examples with the (not working) code generated by CubeMX application.

    Graduate II
    July 18, 2019

    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

    Visitor II
    April 22, 2020

    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.

    Graduate
    April 22, 2020

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

    Visitor II
    May 28, 2020

    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.

    Visitor II
    March 23, 2021

    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