高手请进,困扰很久的问题:STM32F7与MMC通讯异常错误
本帖最后由 小小小小强 于 2018-9-6 09:15 编辑我板子的配置是STM32F7 + Sandisk EMMC,软件环境为freertos + fatfs,EMMC驱动为ST HAL库自带的,驱动程序能够正常读写EMMC。在长时间读写后会遇到STM32发送命令后读取不到响应的问题,复现问题的时间有长有短,但是每次都是在HAL_MMC_ReadBlocks_DMA中出错,报错的代码位置为:
do
{
if (count-- == 0)
{
printf("line:%d,sta:0x%x,res_cmd=0x%x,SD_CMD:%d,req_cmd:%d,dctl:0x%x\r\n",__LINE__,SDMMCx->STA,SDMMCx->RESPCMD,SD_CMD,\
SDMMCx->CMD,SDMMCx->DCTRL);
return SDMMC_ERROR_TIMEOUT;
}
}while(!__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT));
都是count=0后超时退出,我把count值修改到非常大也会遇到相同的问题。通过Sandisk实验室的MMC分析仪抓取整个通信过程分析,MMC在收到命令后是正常响应了,是STM32端没有读到响应,由于已经是直接读取寄存器了,所以我这个小白就不知道如何判断为什么STM32没有收到回复了,也不知道改如何修改,既然MMC已经回复了,有哪些原因可能会导致SDMMC STA寄存器相应位的值没有改变?希望各位高手提出建议,感激不尽。
是不是count这个变量在中断函数里面声明错误呢,定义没赋值么,时钟开了么,时钟时间设置过长么
谢谢楼上关注。我贴出更完整代码,都是STM32F7 HAL库自带
static uint32_t SDMMC_GetCmdResp1(SDMMC_TypeDef *SDMMCx, uint8_t SD_CMD, uint32_t Timeout)
{
uint32_t response_r1;
/* 8 is the number of required instructions cycles for the below loop statement.
The Timeout is expressed in ms */
register uint32_t count = Timeout * (SystemCoreClock / 8 /1000);
do
{
if (count-- == 0)
{
printf("line:%d,sta:0x%x,res_cmd=0x%x,SD_CMD:%d,req_cmd:%d,dctl:0x%x\r\n",__LINE__,SDMMCx->STA,SDMMCx->RESPCMD,SD_CMD,\
SDMMCx->CMD,SDMMCx->DCTRL);
return SDMMC_ERROR_TIMEOUT;
}
}while(!__SDMMC_GET_FLAG(SDMMCx, SDMMC_FLAG_CCRCFAIL | SDMMC_FLAG_CMDREND | SDMMC_FLAG_CTIMEOUT));
//省略STA判断
}
count变量值为函数形参根据系统时钟计算出来的。现在系统时钟为208M,MMC CLK为20.48M,通讯为8BIT模式 另外,出错的时候测量,CLK线上一直有时钟,通过sandisk FAE用MMC通讯分析仪查看,STM32付出CMD后,MMC是正确回复了的,是STM32端没有读到。 feixiang20 发表于 2018-9-5 23:27
是不是count这个变量在中断函数里面声明错误呢,定义没赋值么,时钟开了么,时钟时间设置过长么 ...
count值没有在中断函数里声明,出错时测量CLK线上信号正常。 人工顶下 也遇到这个问题了,有没有高手给解决一下:( 请问楼主这个问题解决了吗?我也遇到这个问题 这个问题已经接近,办法是需要在调用MMC的API前先关闭中断,调用返回后重新打开中断 st论坛里有人给出的解释,但是没有给出解决办法,是因为中断的问题。
Do you happen to be using an RTOS and the SDIO in DMA mode? I've just solved what I believe is the same problem in the STM32F4 HAL drivers.
The problem presents itself when an RTOS context switch happens AFTER SDIO_SendCommand() is called (which begins to clock out the CMD), but before the SDMMC_FLAG_CMDREND flag is set. If a task context switch happens at this time, and does not return to the current task before SD_DMAReceiveCplt() is called, the SDMMC_FLAG_CMDREND is cleared, and never "noticed" by the SDMMC_GetCmdResp1() timeout loop.
In the attached Saleae Logic capture:
ERROR is low after an SDIO timeout occurs.
SDIO wait_loop is low when entering the waiting loop in SDMMC_GetCmdResp1(), high when exiting
ClearSDIOFlags is low then high whenever the SDIO flags are cleared.
SD_CMD is the SDIO CMD line
SD_D0 is the SD_D0 line
PJ11 goes low then high each time the loop in SDMMC_GetCmdResp1() checks the flags in the loop.
When the error happens at the end of the capture, an RTOS context switch happens so the CPU executes another task shortly after SDIO_SendCommand() is called. The flags are not being checked at this point, and while they are properly set, they are eventually cleared by the SD_DMAReceiveCplt() ISR function before SDMMC_GetCmdResp1() ever gets back into the execution context.
Hope this helps.
页:
[1]
2