项目场景:
背景:写一组在FreeRTOS系统下的串口驱动
,芯片使用的是杰发科的AC781x系列
,ARM® CortexM3
内核,96MHz主频。
项目场景:计划使用dma接收数据,设置dma半满中断与全满中断,在半满中断中把前半部分数据传入消息队列,在全满中断中把后半部分数据传入消息队列。
问题描述
问题1:
在中断中调用FreeRTOS的消息队列发送函数带中断保护版本,会出现死机情况,进入hardfault,dma配置的传输字节为8字节(即每接收到8字节进一次传输完成中断)
中断中的代码如下
if (wparam & (1<<0))//传输完成
{
for(uint8_t cj=0; j<8; j++)//连续八次发送数据到消息队列
{
xQueueSendFromISR( UART_ALL[i]->RX_Queue,
(uint8_t*)&UART_ALL[i]>rx_bounce_buf_ptr[j],
&xHigherPriorityTaskWoken );
}
}
断点调试发现是在xQueueSendFromISR()函数死机的。问题2:
在此处执行断点调试发现for循环的每前两次都能执行完,而在第三次执行时会死机,初步排除是中断栈溢出原因。问题3:
进一步进入函数调试发现最后一直在执行三行汇编代码,在那里死循环,最后定位到是在FreeRTOS的xQueueSendFromISR()
–>( void ) prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
–>( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );这一行代码死机。可以得到的消息是跟memcpy函数的执行有关。
原因分析:
猜想原因1:中断优先级问题
网上搜索最接近的情况是在中断中调用FreeRTOS的API时必须确保此中断的实际优先级低于FreeRTOS中配置的MAX_SYSCALL_INTERRUPT_PRIORITY,因为ARM® CortexM3
的优先级是数值越大实际优先级越低,
所以就需要使此中断的优先级值大于MAX_SYSCALL_INTERRUPT_PRIORITY。但此时还有一个疑惑
就是我的情况与网上其它朋友的情况略有出入,就是我能够成功在中断中调用一次os的API,只是在多次调用时会出问题。而且我卡死的位置也与他们的不一样。
在实在束手无策之后,死马当活马医,调整中断优先级,发现情况没有变化,依然卡死,排除优先级配置的问题。
猜想原因2:DMA总线冲突问题
在猜想1验证不符之后网上已搜不到任何类似情况了,换遍各种关键词也只能搜到几个猜想1的情况。此时能想到的各种原因都试了一遍,全都不行,然后与朋友吃饭时聊到memcpy卡死的情况,他说他遇到过dma占用总线导致memcpy卡死的问题,而且也是在第三次卡死。我顿时以为有救了,找到了希望。但验证后也排除此情况。排除手段为自己不使用FreeRTOS的api转而在同一位置单独使用memcpy函数发现并无问题。
到此处能够获得的信息就是与memcpy函数有关
最终在断点调试卡死处,看到汇编语句有这样一句
BL.W __aeabi_memcpy (0x08000228)
此时已几乎可以确定就是memcpy函数导致的卡死。
解决方案:
编译优化memcpy函数文章来源:https://www.toymoban.com/news/detail-610183.html
通过编译优化memcpy函数之后问题迎刃而解,此问题卡了我一个元旦,导致我元旦都没过好。网上无相关案列,遂决定记录一下。文章来源地址https://www.toymoban.com/news/detail-610183.html
到了这里,关于FreeRTOS中断调用API消息队列发送函数导致系统死机(memcpy函数卡死)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!