cancel
Showing results for 
Search instead for 
Did you mean: 

Possible shortcoming in HAL SD library

MClar.3
Associate II

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.

3 REPLIES 3
I.KHACHINE
ST Employee

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

OTedd.1
Associate II

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

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?