Open dima-kapustin opened 2 weeks ago
Hello @dima-kapustin,
Thank you for the report. Could you please, share your IOC file or an extract of the config or project, at least for SDMMC and DMA. So, I can use it to reproduce the issue.
In the meanwhile, I will try to analyze your fix or workaround.
With regards.
Hi @KRASTM !
Here you go (it is almost standard-generated by CubeIDE):
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief MMC MSP Initialization
* This function configures the hardware resources used in this example
* @param hmmc: MMC handle pointer
* @retval None
*/
void HAL_MMC_MspInit(MMC_HandleTypeDef* hmmc)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(hmmc->Instance==SDMMC1)
{
/* USER CODE BEGIN SDMMC1_MspInit 0 */
LL_GPIO_SetOutputPin(SdCard_D0_GPIO_Port, SdCard_D0_Pin);
LL_GPIO_SetOutputPin(SdCard_CK_GPIO_Port, SdCard_CK_Pin);
LL_GPIO_SetOutputPin(SdCard_CMD_GPIO_Port, SdCard_CMD_Pin);
LL_RCC_SetSDMMCClockSource(LL_RCC_SDMMC1_CLKSOURCE_MSI);
SdCardPowerOnPin::reset();
LL_mDelay(50);
/* USER CODE END SDMMC1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_SDMMC1_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
/**SDMMC1 GPIO Configuration
PC8 ------> SDMMC1_D0
PC12 ------> SDMMC1_CK
PD2 ------> SDMMC1_CMD
*/
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
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_MEDIUM;
GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
/* SDMMC1 DMA Init */
/* SDMMC1 Init */
hdma_sdmmc1.Instance = DMA2_Channel5;
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_VERY_HIGH;
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(hmmc,hdmarx,hdma_sdmmc1);
__HAL_LINKDMA(hmmc,hdmatx,hdma_sdmmc1);
/* SDMMC1 interrupt Init */
HAL_NVIC_SetPriority(SDMMC1_IRQn, 3, 0);
HAL_NVIC_EnableIRQ(SDMMC1_IRQn);
/* USER CODE BEGIN SDMMC1_MspInit 1 */
SdCardResetPin::set();
LL_mDelay(50);
/* USER CODE END SDMMC1_MspInit 1 */
}
}
static void MX_SDMMC1_MMC_Init(void)
{
/* USER CODE BEGIN SDMMC1_Init 0 */
/* USER CODE END SDMMC1_Init 0 */
/* USER CODE BEGIN SDMMC1_Init 1 */
/* USER CODE END SDMMC1_Init 1 */
hmmc1.Instance = SDMMC1;
hmmc1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING;
hmmc1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE;
hmmc1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_ENABLE;
hmmc1.Init.BusWide = SDMMC_BUS_WIDE_1B;
hmmc1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
hmmc1.Init.ClockDiv = 0;
if (HAL_MMC_Init(&hmmc1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SDMMC1_Init 2 */
/* USER CODE END SDMMC1_Init 2 */
}
Hello @dima-kapustin,
I tried using the config that you shared, but unfortunately, I didn't manage to reproduce the problem on our board (not the same µc, the L496). If you have ST board that you can use it to test an example based on your config, or if you can share some screenshots of the debug mode while the problem occurs, it can help us to confirm the issue.
In the other hand, I shared your fix and proposal with our team in order to analyze it and confirm it.
With regards,
Hi @KRASTM!
Thanks for pushing it through!
I am afraid I cannot provide more details about the setup at the moment.
We faced the issue when increased SDMMC clock rate over 16 MHz, i.e. 24 MHz and higher. At clock rates lower than or equal to 16 MHz the issue did not appear for years (!).
I think there is fundamental issue in the irq processing flow:
in write direction (DMA -> SDMMC -> SdCars) cleanup shall be done when SDMMC reports end of data transmission
in read direction (SdCard -> SDMMC -> DMA) cleanup shall be done after DMA reports end of data transmission.
However, in the current implementation the cleanup is done after SDMMC reports end of data transmission in both directions - write and read. When SDMMC clock is low enough, everything works fine. But as soon as SDMMC clock rate increases (24+ MHz in our case) the cleanup fails because DMA gets disabled before it completes data transfer and reports end of the transmission.
Beat regards, Dima.
Hello @dima-kapustin,
There is a section in the datasheet DS11453 page174, about SDMMC characteristics:
Could you have a look at it, and I suggest you change or set the Speed mode into: OSPEEDRy[1:0] = 11, High or very High
and give it a try. It may help you.
With regards,
This is one of the first things we tested... No, it does not help with the issue.
Thanks, Dima.
Describe the set-up
Describe the bug Reading from an SdCard hangs with the following conditions: SDMMC_DCTRL.DMAEN = 0 SDMMC_DCTRL.DTEN = 0 SDMMC_DCOUNT = 0
DMA_CCR5.EN = 1 DMA_CNDTR5 = 1 (!) which means no transfer complete interrupt will be generated ever
The issue is similar to https://community.st.com/t5/stm32-mcus-products/stm32l4-sd-dma-8-mhz-read-failure-due-to-missing-byte/td-p/385880.
How To Reproduce
SDMMC interface is configured with DMA 2 Channel 5, 1 bit data line SDMMC clock is sourced form MSI @ 48 MHz, NO devider bypass, HW flow control is ON. PCLK2 clock is 8.192 MHz and sourced from HSE via PLL
Call HAL_MMC_ReadBlocks_DMA() in a loop to read chunks of 1 or 8 blocks waiting until read completes, i.e. HAL_MMC_GetCardState() returns HAL_MMC_CARD_TRANSFER, after each HAL_MMC_ReadBlocks_DMA() call.
After some successful reads the next reading hangs with the conditions (register values) described above.
HAL driver for SDMMC
Additional context
The root cause is how read completion (SDMMC_STA.DATAEND = 1) is handled in function HAL_MMC_IRQHandler() in stm32l4xx_hal_mmc.c
I did two things in HAL_MMC_IRQHandler() to fix the issue:
As per the reference manual:
-- It is not necessary to clear the enable bit (SDMMC_DCTRL.DTEN) after the end of a data transfer but the SDMMC_DCTRL must be updated to enable a new data transfer
The code in lines 1709-1736 is ALSO present in MMC_DMAReceiveCplt() where it should be executed when DMA reports transfer complete for reads.