Skip to main content
RBamf.1
Associate III
June 7, 2021
Question

How do I change the direction of a DMA request for the SDMMC device?

  • June 7, 2021
  • 1 reply
  • 1276 views

Hi, i'm trying to use a single DMA channel to both read/write to the SDMMC. See here (https://community.st.com/s/question/0D50X00009XkWO5/getting-sdmmc-to-work-with-dma2-channel-4).

When generating the SDMMC DMA configuration using cubeMX it results in this comment, but i can't figure out how to change the transfer direction properly?

/* 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);
 
 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;

The problem is that it will correctly write data but it doesn't read correctly.

I suspect something is wrong with the way i'm changing the DMA's direction before reads and writes. Here is my Read and Write code. Are these correct?

/* USER CODE BEGIN BeforeReadDMABlocksSection */
/* can be used to modify previous code / undefine following code / add code */
/* 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)
{
 // Since we are only using 1 DMA channel for SDIO
 
 // Change DMA direction before calling SD Read
 
 // Direction can only be changed when DMA is disabled
 
 __HAL_DMA_DISABLE(hsd1.hdmarx);
 
 hsd1.hdmarx->Init.Direction = DMA_PERIPH_TO_MEMORY;
 
 hsd1.hdmarx->Instance->CCR &= ~DMA_CCR_DIR;
 
 __HAL_DMA_ENABLE(hsd1.hdmarx);
 
 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)
{
 __HAL_DMA_DISABLE(hsd1.hdmatx);
 
 hsd1.hdmatx->Init.Direction = DMA_MEMORY_TO_PERIPH;
 
 hsd1.hdmatx->Instance->CCR |= (uint32_t)DMA_CCR_DIR;
 
 __HAL_DMA_ENABLE(hsd1.hdmatx);
 
 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;
}

Thanks!

This topic has been closed for replies.

1 reply

RBamf.1
RBamf.1Author
Associate III
June 7, 2021

The code above works fine, i just forgot to set the FatFS instance into read and write mode instead of just read mode.