[英]No interrupt in SDcard with DMA on STM32L476 and CubeMX
I have an unsolved issue with SDcard.我有一个未解决的 SD 卡问题。
The project is based on STM32L476, the IDE is Atollic and configuration is made by STM32CucbeMX (as I do with all my designs).该项目基于 STM32L476,IDE 是 Atollic,配置是由 STM32CucbeMX 完成的(就像我所有的设计一样)。
Without DMA (no DMA template in FATFS and no configured DMA channels) the SDcard works.如果没有 DMA(FATFS 中没有 DMA 模板,也没有配置的 DMA 通道),SD 卡可以工作。 When I use the DMA (see screenshot), the very first read operation stucks and after the 30s timeout I get an error.当我使用 DMA 时(见屏幕截图),第一次读取操作卡住了,在 30 秒超时后出现错误。
I have investigated inside the code and I have the evidence that there is not any interrupt after the HAL_SD_ReadBlocks_DMA().我已经在代码内部进行了调查,并且有证据表明在 HAL_SD_ReadBlocks_DMA() 之后没有任何中断。 This is the cause of the timeout.这就是超时的原因。 The function itself returns no error, so it believes the data transfer is running, but it is not.该函数本身没有返回错误,因此它认为数据传输正在运行,但事实并非如此。
The interrupts are so configured:中断是这样配置的:
The CubeMX is version 6.2.1. CubeMX 是 6.2.1 版。 and the STM32L4 packages are updated.并且更新了 STM32L4 包。
My opinion is that there is some error in libraries or in the Cube generated code.我的观点是库或 Cube 生成的代码中存在一些错误。 I have seen other (rare) posts about a similar issue suspecting a libray error.我看过其他(罕见的)关于类似问题的帖子,怀疑是库错误。
This is very imbarassing for me because I have an important design that is waiting for the SD card working at full speed.这对我来说很尴尬,因为我有一个重要的设计,就是等待 SD 卡全速工作。
Without DMA, as I told, the SDcard works but the writing speed is too low and I must run the interface at very low frequency to avoid writing errors.没有 DMA,正如我所说,SD 卡可以工作,但写入速度太低,我必须以非常低的频率运行接口以避免写入错误。 I suppose that read/write operations via DMA will give me the needed speed, but this interrupt problem keeps all the things in stall.我想通过 DMA 的读/写操作会给我所需的速度,但是这个中断问题使所有事情都停滞不前。
Is there some idea about the non-working interrupt?对非工作中断有什么想法吗?
Thank you very much非常感谢
I had the same issue, here is how I fixed it.我有同样的问题,这是我修复它的方法。
This solution is base a solution I found on the stm32 forums but I tried to move stuff to make it simple to implement and so that no everything gets lost each time you regenerate with cube mx.这个解决方案是我在 stm32 论坛上找到的一个解决方案的基础,但我试图移动一些东西以使其易于实现,这样每次使用多维数据集 mx 重新生成时都不会丢失任何东西。 I put override functions in the main but they could be in the user section of the bsp file as well I think.我将覆盖函数放在 main 中,但我认为它们也可以放在 bsp 文件的用户部分。
For reference, I started from this example then applied the fix below https://community.st.com/s/article/how-to-create-a-file-system-on-a-sd-card-using-stm32bubeide?t=1637759710161作为参考,我从这个例子开始,然后应用下面的修复https://community.st.com/s/article/how-to-create-a-file-system-on-a-sd-card-using-stm32bubeide ?t=1637759710161
Fix steps:修复步骤:
In cubeMX use a single DMA on channel 4 instead of 1 for Rx and 1 for Tx.在cubeMX 中,在通道4 上使用单个DMA,而不是1 用于Rx,1 用于Tx。
In main.c在 main.c
/* USER CODE BEGIN PFP */
//Create config functions for rx and tx dma
static HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd);
static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd);
/* USER CODE END PFP */
/* USER CODE BEGIN 4 */
/**
* @brief Configure the DMA to receive data from the SD card
* @retval
* HAL_ERROR or HAL_OK
*/
static HAL_StatusTypeDef SD_DMAConfigRx(SD_HandleTypeDef *hsd)
{
static DMA_HandleTypeDef hdma_rx;
HAL_StatusTypeDef status = HAL_ERROR;
/* Configure DMA Rx parameters */
hdma_rx.Init.Request = DMA_REQUEST_7;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_rx.Instance = DMA2_Channel4;
/* Associate the DMA handle */
__HAL_LINKDMA(hsd, hdmarx, hdma_rx);
/* Stop any ongoing transfer and reset the state*/
HAL_DMA_Abort(&hdma_rx);
/* Deinitialize the Channel for new transfer */
HAL_DMA_DeInit(&hdma_rx);
/* Configure the DMA Channel */
status = HAL_DMA_Init(&hdma_rx);
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
return (status);
}
/**
* @brief Configure the DMA to transmit data to the SD card
* @retval
* HAL_ERROR or HAL_OK
*/
static HAL_StatusTypeDef SD_DMAConfigTx(SD_HandleTypeDef *hsd)
{
static DMA_HandleTypeDef hdma_tx;
HAL_StatusTypeDef status;
/* Configure DMA Tx parameters */
hdma_tx.Init.Request = DMA_REQUEST_7;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;
hdma_tx.Instance = DMA2_Channel4;
/* Associate the DMA handle */
__HAL_LINKDMA(hsd, hdmatx, hdma_tx);
/* Stop any ongoing transfer and reset the state*/
HAL_DMA_Abort(&hdma_tx);
/* Deinitialize the Channel for new transfer */
HAL_DMA_DeInit(&hdma_tx);
/* Configure the DMA Channel */
status = HAL_DMA_Init(&hdma_tx);
/* NVIC configuration for DMA transfer complete interrupt */
HAL_NVIC_SetPriority(DMA2_Channel4_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(DMA2_Channel4_IRQn);
return (status);
}
//Override DMA write functions
uint8_t BSP_SD_WriteBlocks_DMA(uint32_t *pData, uint32_t WriteAddr, uint32_t NumOfBlocks)
{
uint8_t sd_state = MSD_OK;
// Invalidate the dma rx handle
hsd1.hdmarx = NULL;
// Prepare the dma channel for a read operation
sd_state = SD_DMAConfigTx(&hsd1);
if(sd_state == HAL_OK)
{
/* Write block(s) in DMA transfer mode */
sd_state = HAL_SD_WriteBlocks_DMA(&hsd1, (uint8_t *)pData, WriteAddr, NumOfBlocks);
}
if( sd_state == HAL_OK)
{
return MSD_OK;
}
else
{
return MSD_ERROR;
}
return sd_state;
}
//Override DMA read functions
uint8_t BSP_SD_ReadBlocks_DMA(uint32_t *pData, uint32_t ReadAddr, uint32_t NumOfBlocks)
{
uint8_t sd_state = MSD_OK;
/* Invalidate the dma tx handle*/
hsd1.hdmatx = NULL;
/* Prepare the dma channel for a read operation */
sd_state = SD_DMAConfigRx(&hsd1);
if(sd_state == HAL_OK)
{
/* Read block(s) in DMA transfer mode */
sd_state = HAL_SD_ReadBlocks_DMA(&hsd1, (uint8_t *)pData, ReadAddr, NumOfBlocks);
}
if( sd_state == HAL_OK)
{
return MSD_OK;
}
else
{
return MSD_ERROR;
}
}
/**
* @brief This function handles DMA2 channel4 global interrupt.
*/
void DMA2_Channel4_IRQHandler(void)
{
/* USER CODE BEGIN DMA2_Channel4_IRQn 0 */
/* USER CODE END DMA2_Channel4_IRQn 0 */
//DMAFIX comment or delete HAL_DMA_IRQHandler(&hdma_sdmmc1);
/* USER CODE BEGIN DMA2_Channel4_IRQn 1 */
//DMAFIX separate irq handler by tx/rx, new code in irq handler
if((hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_READ_SINGLE_BLOCK)) ||
(hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_READ_MULTIPLE_BLOCK)))
{
//BSP_SD_DMA_Rx_IRQHandler();
HAL_DMA_IRQHandler(hsd1.hdmarx);
}
else if((hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_WRITE_SINGLE_BLOCK)) ||
(hsd1.Context == (SD_CONTEXT_DMA | SD_CONTEXT_WRITE_MULTIPLE_BLOCK)))
{
//BSP_SD_DMA_Tx_IRQHandler();
HAL_DMA_IRQHandler(hsd1.hdmatx);
}
/* USER CODE END DMA2_Channel4_IRQn 1 */
}
note: each time yo regenerate with Cube Mx, you will need to go back and comment or delete the call to HAL_DMA_IRQHandler(&hdma_sdmmc1);注意:每次使用 Cube Mx 重新生成时,您都需要返回注释或删除对 HAL_DMA_IRQHandler(&hdma_sdmmc1); 的调用。
Hope it helps, I am not finish with that project, there might be a better way but so far this is what unblocked me.希望它会有所帮助,我还没有完成那个项目,可能有更好的方法,但到目前为止,这就是我解除封锁的原因。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.