Skip to main content
Visitor II
May 28, 2021
Question

HAL_SD using DMA trigger the HAL_SD_RxCpltCallback() but not the HAL_SD_TxCpltCallback()?

  • May 28, 2021
  • 1 reply
  • 1944 views

I have setup the HAL_SD system to perform DMA transfers, the SD card can be read from but it fails to write.

The program just hangs in a while loop waiting for WaitStatus to equal 1, but the interrupt that sets it to 1 is never called. It's running on an STM32L452RE.

My problem is like this: https://community.st.com/s/question/0D50X00009XkWO5/getting-sdmmc-to-work-with-dma2-channel-4

Only 1 DMA channel is assigned but, it can only receive not transmit?

Here is the DMA setup:

__HAL_RCC_GPIOD_CLK_ENABLE();
 __HAL_RCC_GPIOC_CLK_ENABLE();
 __HAL_RCC_GPIOB_CLK_ENABLE();
 
 __HAL_RCC_DMA2_CLK_ENABLE();
 
 __HAL_RCC_SDMMC1_CLK_ENABLE();
 
 /**SDMMC1 GPIO Configuration
 PD2 ------> SDMMC1_CMD
 PC11 ------> SDMMC1_D3
 PC10 ------> SDMMC1_D2
 PC12 ------> SDMMC1_CK
 PC9 ------> SDMMC1_D1
 PC8 ------> SDMMC1_D0
 */
 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_SDMMC1;
 HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
 
 GPIO_InitStruct.Pin = GPIO_PIN_11 | GPIO_PIN_10 | GPIO_PIN_12 | GPIO_PIN_9
 | GPIO_PIN_8;
 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_SDMMC1;
 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
 
 /* SDMMC1 DMA Init */
/* SDMMC1 Init */
 hdma_sdmmc1.Instance = DMA2_Channel4;
 hdma_sdmmc1.Init.Request = DMA_REQUEST_7;
 hdma_sdmmc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
 hdma_sdmmc1.Init.PeriphInc = DMA_PINC_DISABLE;
 hdma_sdmmc1.Init.MemInc = DMA_MINC_ENABLE;
 hdma_sdmmc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
 hdma_sdmmc1.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
 hdma_sdmmc1.Init.Mode = DMA_NORMAL;
 hdma_sdmmc1.Init.Priority = DMA_PRIORITY_LOW;
 if (HAL_DMA_Init(&hdma_sdmmc1) != HAL_OK)
 {
 Error_Handler();
 }
 
 
 /* Several peripheral DMA handle pointers point to the same DMA handle.
 Be aware that there is only one channel to perform all the requested DMAs. */
 /* Be sure to change transfer direction before calling
 HAL_SD_ReadBlocks_DMA or HAL_SD_WriteBlocks_DMA. */
 __HAL_LINKDMA(&hsd1, hdmarx, hdma_sdmmc1);
 __HAL_LINKDMA(&hsd1, hdmatx, hdma_sdmmc1);
 
 /* SDMMC1 interrupt Init */
 HAL_NVIC_SetPriority(SDMMC1_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
 
 /* DMA interrupt init */
 /* DMA2_Channel4_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
 
 /* DMA2_Channel5_IRQn interrupt configuration */
 HAL_NVIC_SetPriority(DMA2_Channel5_IRQn, 0, 0);
 HAL_NVIC_EnableIRQ(DMA2_Channel5_IRQn);
 
 hsd1.Instance = SDMMC1;
 hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
 hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
 hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
 hsd1.Init.BusWide = SDMMC_BUS_WIDE_1B;
 hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
 hsd1.Init.ClockDiv = SDMMC_TRANSFER_CLK_DIV;

Here are the function definitions in the "bsp_sd.c" of FatFS: Here the HAL_SD_RxCpltCallback is being called, but HAL_SD_TxCpltCallback is never called.

/**
 
 * @brief Tx Transfer completed callback
 
 * @param hsd: SD handle
 
 * @retval None
 
 */
 
void HAL_SD_TxCpltCallback(SD_HandleTypeDef* hsd)
 
{
 
 BSP_SD_WriteCpltCallback();
 
}
 
 
/**
 
 * @brief Rx Transfer completed callback
 
 * @param hsd: SD handle
 
 * @retval None
 
 */
 
void HAL_SD_RxCpltCallback(SD_HandleTypeDef* hsd)
 
{
 
 BSP_SD_ReadCpltCallback();
 
}

 The fatfs bsp_sd.c readblock/writeblock are defined like this:

/**
 
 * @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)
 
{
 
 LL_DMA_SetDataTransferDirection(&hdma_sdmmc1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
 
 
 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 */
 
/* can be used to modify previous code / undefine following code / add code */
 
/* 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)
 
{
 
 LL_DMA_SetDataTransferDirection(&hdma_sdmmc1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
 
 
 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;
 
}

    This topic has been closed for replies.

    1 reply

    Visitor II
    April 13, 2022

    You need to change the direction of the dma in the hsd1 struct as well, otherwise HAL_SD_WriteBlocks_DMA will configure the channel incorrectly.

    hsd1.hdmatx->Init.Direction = DMA_PERIPH_TO_MEMORY;

    or

    hsd1.hdmatx->Init.Direction = DMA_MEMORY_TO_PERIPH;