Skip to main content
Visitor II
May 14, 2023
Question

Possible shortcoming in HAL SD library

  • May 14, 2023
  • 3 replies
  • 2153 views

Been trying to get an test application working on a STM32F469NIH Discovery board.

Should be fairly simple - Write a file to the SD Card, with FatFS, the read back:

Try as I might, I couldn't get things working.

After a bit of debugging, I think the issue lies with the DMA callback functions. I'm using FW_F4 V1.27.1, on CubeIDE, and it seems that the supplied SD_DMATransmitCplt() function isn't quite complete, when compared to the SD_DMAReceiveCplt() function.

There seems to be a couple of things missing - Firstly the call to the callback function - This is a must for the SD interface, because there's a queue that is waited on. Without the callback function being called, nothing is ever put on the queue, so a timeout error is received.

The other important bit seems to be the line of code that unlocks the HAL. A sensible thing to do, as we've just finished transferring data. Again, without it, some other bits of code later on fail as the HAL is still locked.

So I copied the code from the RX complete, and that seems to make things work - See attached text file

The question is, am I on the right track here? I'd like to help improve things, but at the same time, I don't want to fix things worse. A proper fix is better than a band-aid.

    This topic has been closed for replies.

    3 replies

    ST Employee
    July 7, 2023

    Hello MClar,
    I'm analyzing the issue that you mentioned.
    Could you pls give me the DMA configuration that you are using the both cases Transmit and Receive?
    Best regards,
    Ismail

    MClar.3Author
    Visitor II
    June 17, 2024

    Hi @I.KHACHINE 

    Apologies for the (very long) delay in a reply...

    Here's the SD DMA init from the sdio.c that CubeMX generates:

    /* SDIO DMA Init */
    /* SDIO_RX Init */
    hdma_sdio_rx.Instance = DMA2_Stream3;
    hdma_sdio_rx.Init.Channel = DMA_CHANNEL_4;
    hdma_sdio_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
    hdma_sdio_rx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdio_rx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdio_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdio_rx.Init.Mode = DMA_PFCTRL;
    hdma_sdio_rx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_sdio_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_sdio_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_sdio_rx.Init.MemBurst = DMA_MBURST_INC4;
    hdma_sdio_rx.Init.PeriphBurst = DMA_PBURST_INC4;
    if (HAL_DMA_Init(&hdma_sdio_rx) != HAL_OK)
    {
     Error_Handler();
    }
    
    __HAL_LINKDMA(sdHandle,hdmarx,hdma_sdio_rx);
    
    /* SDIO_TX Init */
    hdma_sdio_tx.Instance = DMA2_Stream6;
    hdma_sdio_tx.Init.Channel = DMA_CHANNEL_4;
    hdma_sdio_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
    hdma_sdio_tx.Init.PeriphInc = DMA_PINC_DISABLE;
    hdma_sdio_tx.Init.MemInc = DMA_MINC_ENABLE;
    hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    hdma_sdio_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    hdma_sdio_tx.Init.Mode = DMA_PFCTRL;
    hdma_sdio_tx.Init.Priority = DMA_PRIORITY_LOW;
    hdma_sdio_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
    hdma_sdio_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
    hdma_sdio_tx.Init.MemBurst = DMA_MBURST_INC4;
    hdma_sdio_tx.Init.PeriphBurst = DMA_PBURST_INC4;
    if (HAL_DMA_Init(&hdma_sdio_tx) != HAL_OK)
    {
     Error_Handler();
    }
    
    __HAL_LINKDMA(sdHandle,hdmatx,hdma_sdio_tx);

    I've just updated the code to the latest I have on CubeIDE 1.15.1, which is STM32F4 MCU package 1.28.0 (previously 1.27.1) and FATFs R0.12c. The SD_DMATransmitCplt() function still looks a bit bare. I've had other issues on the project (with a lithium battery power path / charger IC misbehaving and randomly powering on when it should be off), so it's been back burner for a while.

    @OTedd.1, I'll reload the new MCU package onto the dev board, and see if I can get a better solution - Maybe we can get a proper fix in place. 

    Is it possible to submit changes / pull requests to ST's GIT repo to include a fix?

    Visitor II
    May 24, 2024

    Hi,

    Was there any solution to this issue?


    I think I have a similar issue where within `SD_write` in `sd_diskio.c`, my program hangs on line `status = osMessageQueueGet(SDQueueID, (void *)&event, NULL, SD_TIMEOUT);` (line 463) because nothing ever gets put into the queue `SDQueueID`.

    `BSP_SD_WriteCpltCallback` never gets called.


    Like @MClar.3  I see that `SD_DMATransmitCplt` DOES get called.  Is there some code missing there or is there some other configuration error?

     

    I am using an STM32F427GT6, with STM32CubeIDE 1.12.0.
    I am using FreeRTOS and FatFS.

     

    Here is my `HAL_SD_MspInit` function

     

    /**
    * @brief SD MSP Initialization
    * This function configures the hardware resources used in this example
    * @param hsd: SD handle pointer
    * @retval None
    */
    void HAL_SD_MspInit(SD_HandleTypeDef* hsd)
    {
     GPIO_InitTypeDef GPIO_InitStruct = {0};
     if(hsd->Instance==SDIO)
     {
     /* USER CODE BEGIN SDIO_MspInit 0 */
    
     /* USER CODE END SDIO_MspInit 0 */
     /* Peripheral clock enable */
     __HAL_RCC_SDIO_CLK_ENABLE();
    
     __HAL_RCC_GPIOC_CLK_ENABLE();
     __HAL_RCC_GPIOD_CLK_ENABLE();
     /**SDIO GPIO Configuration
     PC8 ------> SDIO_D0
     PC9 ------> SDIO_D1
     PC10 ------> SDIO_D2
     PC11 ------> SDIO_D3
     PC12 ------> SDIO_CK
     PD2 ------> SDIO_CMD
     */
     GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11
     |GPIO_PIN_12;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
     HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
     GPIO_InitStruct.Pin = GPIO_PIN_2;
     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
     GPIO_InitStruct.Pull = GPIO_NOPULL;
     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
     GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
     HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
    
     /* SDIO DMA Init */
     /* SDIO_RX Init */
     hdma_sdio_rx.Instance = DMA2_Stream3;
     hdma_sdio_rx.Init.Channel = DMA_CHANNEL_4;
     hdma_sdio_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
     hdma_sdio_rx.Init.PeriphInc = DMA_PINC_DISABLE;
     hdma_sdio_rx.Init.MemInc = DMA_MINC_ENABLE;
     hdma_sdio_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
     hdma_sdio_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
     hdma_sdio_rx.Init.Mode = DMA_PFCTRL;
     hdma_sdio_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
     hdma_sdio_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
     hdma_sdio_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
     hdma_sdio_rx.Init.MemBurst = DMA_MBURST_INC4;
     hdma_sdio_rx.Init.PeriphBurst = DMA_PBURST_INC4;
     if (HAL_DMA_Init(&hdma_sdio_rx) != HAL_OK)
     {
     Error_Handler();
     }
    
     __HAL_LINKDMA(hsd,hdmarx,hdma_sdio_rx);
    
     /* SDIO_TX Init */
     hdma_sdio_tx.Instance = DMA2_Stream6;
     hdma_sdio_tx.Init.Channel = DMA_CHANNEL_4;
     hdma_sdio_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
     hdma_sdio_tx.Init.PeriphInc = DMA_PINC_DISABLE;
     hdma_sdio_tx.Init.MemInc = DMA_MINC_ENABLE;
     hdma_sdio_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
     hdma_sdio_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
     hdma_sdio_tx.Init.Mode = DMA_PFCTRL;
     hdma_sdio_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
     hdma_sdio_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
     hdma_sdio_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
     hdma_sdio_tx.Init.MemBurst = DMA_MBURST_INC4;
     hdma_sdio_tx.Init.PeriphBurst = DMA_PBURST_INC4;
     if (HAL_DMA_Init(&hdma_sdio_tx) != HAL_OK)
     {
     Error_Handler();
     }
    
     __HAL_LINKDMA(hsd,hdmatx,hdma_sdio_tx);
    
     /* USER CODE BEGIN SDIO_MspInit 1 */
     // DMA priority above set to VERY_HIGH as suggested by
     // https://community.st.com/t5/stm32-mcus-embedded-software/stm32f4-sdio-fat-write-problem/td-p/406687/page/2
     /* USER CODE END SDIO_MspInit 1 */
     }
    
    }

     

     

    By modifying the `SD_DMATransmitCplt` function in the `stm32f4xx_hal_sd.c` file so that the `Tx` handler is called (similar but not quite the same as @MClar.3 modification)

    static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
    {
     SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
    
     // /* Enable DATAEND Interrupt */
     // __HAL_SD_ENABLE_IT(hsd, (SDIO_IT_DATAEND));
     
     /* Disable the DMA transfer for transmit request by setting the DMAEN bit
     in the SD DCTRL register */
     hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
    
     /* Clear all the static flags */
     __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
    
     hsd->State = HAL_SD_STATE_READY;
     hsd->Context = SD_CONTEXT_NONE;
    
    #if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
     hsd->TxCpltCallback(hsd);
    #else
     HAL_SD_TxCpltCallback(hsd);
    #endif
    }


    then writes are working.

    However is this the proper solution?

     

    Many thanks,
    Ollie

    Explorer
    September 30, 2025

    Thanks! You are saving my days! We just repair the stm32f4xx_hal_sd.c function just like this.

    /**
     * @brief DMA SD transmit process complete callback
     * @PAram hdma: DMA handle
     * @retval None
     */
    static void SD_DMATransmitCplt(DMA_HandleTypeDef *hdma)
    {
     SD_HandleTypeDef* hsd = (SD_HandleTypeDef* )(hdma->Parent);
    	uint32_t errorstate;
    	
    	/* Send stop command in multiblock write */
     if(hsd->Context == (SD_CONTEXT_WRITE_MULTIPLE_BLOCK | SD_CONTEXT_DMA))
     {
     errorstate = SDMMC_CmdStopTransfer(hsd->Instance);
     if(errorstate != HAL_SD_ERROR_NONE)
     {
     hsd->ErrorCode |= errorstate;
    #if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
     hsd->ErrorCallback(hsd);
    #else
     HAL_SD_ErrorCallback(hsd);
    #endif
     }
     }
    	
    	/* Disable the DMA transfer for transmit request by setting the DMAEN bit
     in the SD DCTRL register */
     hsd->Instance->DCTRL &= (uint32_t)~((uint32_t)SDIO_DCTRL_DMAEN);
    
     /* Clear all the static flags */
     __HAL_SD_CLEAR_FLAG(hsd, SDIO_STATIC_DATA_FLAGS);
    
     hsd->State = HAL_SD_STATE_READY;
     hsd->Context = SD_CONTEXT_NONE;
    
    #if (USE_HAL_SD_REGISTER_CALLBACKS == 1)
     hsd->TxCpltCallback(hsd);
    #else
     HAL_SD_TxCpltCallback(hsd);
    #endif
    }

     

    Super User
    October 1, 2025

    Consider opening an issue/bug against the 'F4 library: https://github.com/STMicroelectronics/stm32f4xx-hal-driver/issues

     

     

     

    Explorer
    October 1, 2025

    OK, I will open this issue.