专家
公告
财富商城
电子网
旗下网站
首页
问题库
专栏
标签库
话题
专家
NEW
门户
发布
提问题
发文章
STM32
STM32的SDIO的DMA模式死循环
2019-08-13 22:49
发布
×
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
站内问答
/
STM32/STM8
7923
11
1731
原子哥我的SD卡采用是DMA方式为什么一次写入1KB程序正常,当一次写入10KB时就不稳定经常会在while (DMA_GetFlagStatus(DMA2_FLAG_TC4) == RESET)这里死循环,这是怎么回事?是程序写的不稳定,我是从官网下的程序修改的。请原子哥指点!!
友情提示:
此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
11条回答
cornrn
1楼-- · 2019-08-13 22:55
这几天研究stm32操作sd卡,使用的是ST给的例程stm32_eval_sdio_sd.c,版本V4.5.0,遇到了如下问题,现一一解决。
1:SD_WaitReadOperation()或者SD_WaitWriteOperation()函数死循环
原因:数据传输错误导致传输中断,无法满足退出等待的判断条件。
代码分析:
SD_Error SD_WaitReadOperation(void)
{
SD_Error errorstatus = SD_OK;
while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
{}
if (TransferError != SD_OK)
{
return(TransferError);
}
return(errorstatus);
}
代码中用了while()是导致死循环的原因。TransferEnd ,TransferError 这两个参数是在中断中修改的, SD_DMAEndOfTransferStatus() 的结束条件是DMA传输结束。
看中断例程:
SD_Error SD_ProcessIRQSrc(void)
{
if (StopCondition == 1)
{
SDIO->ARG = 0x0;
SDIO->CMD = 0x44C;
TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
}
else
{
TransferError = SD_OK;
}
SDIO_ClearITPendingBit(SDIO_IT_DATAEND);
SDIO_ITConfig(SDIO_IT_DATAEND, DISABLE);
TransferEnd = 1;
return(TransferError);
}
中断配置为数据传输结束中断SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
数据传输出错导致传输中断的情况下,SD_DMAEndOfTransferStatus的判断为false,TransferEnd 和TransferError 的状态也不会改变,导致while循环无法退出。
解决:
中断配置为SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND, ENABLE);
中断例程修改:
SD_Error SD_ProcessIRQSrc(void)
{
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
TransferError = SD_DATA_TIMEOUT;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
TransferError = SD_DATA_CRC_FAIL;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
TransferError = SD_RX_OVERRUN;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
TransferError = SD_START_BIT_ERR;
}
else
{
if (StopCondition == 1)
{
SDIO->ARG = 0x0;
SDIO->CMD = 0x44C;
TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
}
else
{
TransferError = SD_OK;
}
}
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND, DISABLE);
TransferEnd = 1;
return(TransferError);
}
这么做的作用是发生错误时也会进入中断,即使dma没有结束,也能退出while循环。
2:sd_init()过程失败
可能性1:按照SD规范,初始化之前需要有74个或更多个clock让sd卡同步,例程中把clock开起来后直接发送cmd0,没有同步clock,所以先修改SD_PowerON函数内SDIO_ClockCmd(ENABLE);调用之后增加200us延时。
可能性2:发生SDIO_FLAG_DCRCFAIL错误。
修改SDIO_TRANSFER_CLK_DIV 来修改数据传输速率。
按照ST例程的注释,数据传输速率不能超过25M,但是原先配置SDIO_TRANSFER_CLK_DIV=0,按照72M主频计算的话传输速度达到72/2=36M,不出错就怪了。
我现在配置SDIO_TRANSFER_CLK_DIV=2后正常。
可能性3:固件库使用不正确。使用V4.5的例程,固件库需要用V3.5.0的,试过3.2的固件库会失败。
3:SD_DMAEndOfTransferStatus函数内没有清标志位,按照datasheet,标志位是由手动清除的。
4:SD_ReadBlock()发生SDIO_FLAG_DCRCFAIL错误。
一开始是实践发现,先执行一下SD_ReadMultiBlocks函数,以后再执行SD_ReadBlock就正常了。很奇怪的现象吧。后来查阅了一些资料,发现SD卡的block大小并不是固定的,可以配置为512,1024等,于是怀疑是block大小配置不正确导致。检查发现SD_ReadBlock操作之前没有设置sd卡block大小,也就是cmd16,加入这个代码就像行了
/*!< Set Block Size for Card */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
if (SD_OK != errorstatus)
{
return(errorstatus);
}
其实这个操作并不是每次读操作都要执行的,如果中途不改变block大小,只要初始化的时候设置一次就可以了。
加载中...
正点原子
2楼-- · 2019-08-13 23:39
SDIO DMA bug多,我也没有解决方法,你问问ST去吧。
加载中...
lxp89
3楼-- · 2019-08-14 03:12
改了好几天好远原子哥的程序比较稳定
加载中...
cornrn
4楼-- · 2019-08-14 08:43
请看勘误手册,哪些小问题根本不影响,只能是你代码写的不规范,官方好多应用AN系列的文章看看就知道了
加载中...
cornrn
5楼-- · 2019-08-14 14:24
精彩回答 2 元偷偷看……
加载中...
lxp89
6楼-- · 2019-08-14 18:23
回复【5楼】cornrn:
---------------------------------
求指点,你的程序能否参考一下,直说的勘误我怎么没有找到?
加载中...
1
2
下一页
一周热门
更多
>
相关问题
STM32F4上I2C(在PROTEUS中模拟)调试不通的问题
6 个回答
芯片供应紧张,准备换个MCU,MM32L系列替换STM32L系列的怎么样?
7 个回答
STM32同时使用两个串口进行数据收发时数据丢包的问题
5 个回答
STM32F103串口通信死机问题
4 个回答
STM32WLE5CC连接SX1268在LoRa模式下能与 SX1278互通吗?
2 个回答
STM32开发板免费用活动
7 个回答
stm32 处理 DHT11占用太多时间,大家程序是怎么设计的
8 个回答
分享一个STM32单片机做的离线编程器代码
9 个回答
相关文章
ST公司第一款无线低功耗单片机模块有效提高物联网设计生产效率
0个评论
如何实现对单片机寄存器的访问
0个评论
通过USB用STM32片内自带Bootloader下载程序及注意事项
0个评论
欲练此功必先自宫之STM32汇编启动,放慢是为了更好的前行
0个评论
×
关闭
采纳回答
向帮助了您的网友说句感谢的话吧!
非常感谢!
确 认
×
关闭
编辑标签
最多设置5个标签!
STM32
保存
关闭
×
关闭
举报内容
检举类型
检举内容
检举用户
检举原因
广告推广
恶意灌水
回答内容与提问无关
抄袭答案
其他
检举说明(必填)
提交
关闭
×
关闭
您已邀请
15
人回答
查看邀请
擅长该话题的人
回答过该话题的人
我关注的人
1:SD_WaitReadOperation()或者SD_WaitWriteOperation()函数死循环
原因:数据传输错误导致传输中断,无法满足退出等待的判断条件。
代码分析:
SD_Error SD_WaitReadOperation(void)
{
SD_Error errorstatus = SD_OK;
while ((SD_DMAEndOfTransferStatus() == RESET) && (TransferEnd == 0) && (TransferError == SD_OK))
{}
if (TransferError != SD_OK)
{
return(TransferError);
}
return(errorstatus);
}
代码中用了while()是导致死循环的原因。TransferEnd ,TransferError 这两个参数是在中断中修改的, SD_DMAEndOfTransferStatus() 的结束条件是DMA传输结束。
看中断例程:
SD_Error SD_ProcessIRQSrc(void)
{
if (StopCondition == 1)
{
SDIO->ARG = 0x0;
SDIO->CMD = 0x44C;
TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
}
else
{
TransferError = SD_OK;
}
SDIO_ClearITPendingBit(SDIO_IT_DATAEND);
SDIO_ITConfig(SDIO_IT_DATAEND, DISABLE);
TransferEnd = 1;
return(TransferError);
}
中断配置为数据传输结束中断SDIO_ITConfig(SDIO_IT_DATAEND, ENABLE);
数据传输出错导致传输中断的情况下,SD_DMAEndOfTransferStatus的判断为false,TransferEnd 和TransferError 的状态也不会改变,导致while循环无法退出。
解决:
中断配置为SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND, ENABLE);
中断例程修改:
SD_Error SD_ProcessIRQSrc(void)
{
if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_DTIMEOUT);
TransferError = SD_DATA_TIMEOUT;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_DCRCFAIL) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_DCRCFAIL);
TransferError = SD_DATA_CRC_FAIL;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_RXOVERR) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_RXOVERR);
TransferError = SD_RX_OVERRUN;
}
else if (SDIO_GetFlagStatus(SDIO_FLAG_STBITERR) != RESET)
{
SDIO_ClearFlag(SDIO_FLAG_STBITERR);
TransferError = SD_START_BIT_ERR;
}
else
{
if (StopCondition == 1)
{
SDIO->ARG = 0x0;
SDIO->CMD = 0x44C;
TransferError = CmdResp1Error(SD_CMD_STOP_TRANSMISSION);
}
else
{
TransferError = SD_OK;
}
}
SDIO_ITConfig(SDIO_IT_RXOVERR|SDIO_IT_DTIMEOUT|SDIO_IT_DCRCFAIL|SDIO_IT_DATAEND, DISABLE);
TransferEnd = 1;
return(TransferError);
}
这么做的作用是发生错误时也会进入中断,即使dma没有结束,也能退出while循环。
2:sd_init()过程失败
可能性1:按照SD规范,初始化之前需要有74个或更多个clock让sd卡同步,例程中把clock开起来后直接发送cmd0,没有同步clock,所以先修改SD_PowerON函数内SDIO_ClockCmd(ENABLE);调用之后增加200us延时。
可能性2:发生SDIO_FLAG_DCRCFAIL错误。
修改SDIO_TRANSFER_CLK_DIV 来修改数据传输速率。
按照ST例程的注释,数据传输速率不能超过25M,但是原先配置SDIO_TRANSFER_CLK_DIV=0,按照72M主频计算的话传输速度达到72/2=36M,不出错就怪了。
我现在配置SDIO_TRANSFER_CLK_DIV=2后正常。
可能性3:固件库使用不正确。使用V4.5的例程,固件库需要用V3.5.0的,试过3.2的固件库会失败。
3:SD_DMAEndOfTransferStatus函数内没有清标志位,按照datasheet,标志位是由手动清除的。
4:SD_ReadBlock()发生SDIO_FLAG_DCRCFAIL错误。
一开始是实践发现,先执行一下SD_ReadMultiBlocks函数,以后再执行SD_ReadBlock就正常了。很奇怪的现象吧。后来查阅了一些资料,发现SD卡的block大小并不是固定的,可以配置为512,1024等,于是怀疑是block大小配置不正确导致。检查发现SD_ReadBlock操作之前没有设置sd卡block大小,也就是cmd16,加入这个代码就像行了
/*!< Set Block Size for Card */
SDIO_CmdInitStructure.SDIO_Argument = (uint32_t) BlockSize;
SDIO_CmdInitStructure.SDIO_CmdIndex = SD_CMD_SET_BLOCKLEN;
SDIO_CmdInitStructure.SDIO_Response = SDIO_Response_Short;
SDIO_CmdInitStructure.SDIO_Wait = SDIO_Wait_No;
SDIO_CmdInitStructure.SDIO_CPSM = SDIO_CPSM_Enable;
SDIO_SendCommand(&SDIO_CmdInitStructure);
errorstatus = CmdResp1Error(SD_CMD_SET_BLOCKLEN);
if (SD_OK != errorstatus)
{
return(errorstatus);
}
其实这个操作并不是每次读操作都要执行的,如果中途不改变block大小,只要初始化的时候设置一次就可以了。
---------------------------------
求指点,你的程序能否参考一下,直说的勘误我怎么没有找到?
一周热门 更多>