rt-thread修改全局中断屏蔽函数,解决内核频繁关闭中断影响精密计时问题

发布时间:2024年01月18日

带rtt-nano实时操作系统的小板子需要读取单总线设备,使用软件延时吧,总是由于时隙不精确,通信不稳定。按说不稳定情况也不频繁,但考虑到未来需要对上百、上千米外的单总线设备通信,开发的时候偷个懒,到应用上就是个大麻烦。再加上强迫症发作,遂决定花时间怼开这个问题。

软件延时不稳定,咱理解:通信通到一半,内核调度器掐表你时间到了,干别的去;就算摁死内核不让动,还有别的中断响应会破坏软件延时时长,干脆,给个定时器,在中断响应里收发位数据,位组成字节,字节组成字节块实现通信。

但改成硬件定时器溢出中断,又有问题。定时器的延时时间长度居然不稳定!5us的延迟,一会儿变4微秒一会儿变8微秒,偶尔还给你搞个二三十微秒,这谁受得了。

我猜,应该还是rtos内核调度器在作妖,提高定时器中断优先级,无效;掐断内核,不大可行,因为内核是由中断驱动,掐内核=掐中断,一掐中断,定时器的溢出中断也没办法响应。

去rtthread查一查,发现不少人吐槽rtt这问题,内核调度器管着中断,一进临界区第一步掐全局中断。虽然rtt自己解释进入临界区时间很短,可在精密计时面前,时间很短=一定会碰到=计时出错。得改。再往里看,有大神提出arm-cortex-M3、M4内核自带屏蔽部分中断功能,那能不能修改rtt中断管理函数,把屏蔽全局中断改成屏蔽部分中断呢?可以!rtt论坛有大神做到这个,可以抄作业了!

需要改的重点是cortex_rvds.S文件。这两个函数,rt_hw_interrupt_disable/enable,加个[WEAK]描述,方便我们在外部修改。然后在外部随便哪个源文件重写这两个函数,建议在main文件,方便好改。

重写之后的全局中断控制函数,从操作primask改成操作basepri。写入什么数值取决于读者自己设置的抢占优先级/响应优先级分组。basepri是屏蔽抢占优先级低于写入内容的中断请求。而且basepri生效的是高四位。举个例子,笔者抢占/响应优先级分组为2/2,将抢占优先级0组设为不需屏蔽。则basepri的屏蔽值就是0100,再左移4位放到高八位,得到0x40,最后送给basepri。

这样0组小于1,不能被屏蔽,1、2、3组大于等于1,被屏蔽。且basepri不会考虑响应优先级,只看抢占优先级。

除了重写函数之外,文件中还有一处需要修改。按上文修改完毕,烧入芯片后只要发生线程调度,就会进hardfault。

需要额外增加这两行汇编,大概意思应该是将basepri设为0,禁止屏蔽。这里似乎是内核的线程调度入口。这里如果没有解除屏蔽,似乎会导致rtt内核调度失效。笔者水平有限,没有能深入研究此处,希望抛砖引玉,积极评论。

修改之前,由于内核调度屏蔽全局中断,导致微秒延时不稳定。

修改之后,定时器工作、发生溢出中断、翻转IO不受内核调度影响,微秒级翻转非常稳定。

使用[weak]后缀的好处是,s文件就算更换工程,没有重写的内核中断控制函数,也不会导致系统死机。笔者这里使用keil自带的rtt-nano文件,需要对禁止编辑的cortex-rvds.S文件进行修改,方法是右击-找到文件所在路径,右击s文件-属性,关闭只读选项,增加“weak”修饰符、增加basepri赋值汇编代码,保存,恢复只读,这样cortex-rvds.S文件修改完毕。任意位置重写全局中断控制函数即可使用该功能,不重写就和原版一样。

本文基于rtt-nanoV3.1.5版本修改,欢迎讨论。

ps:最后吐槽一下rtt的内核调度,搜索出135处全局中断控制函数,也是醉了,这么频繁地切中断,那微秒级甚至纳秒级延时、io控制能精确才见鬼。

对了,再加个PS。修改过优先级、导致rtt内核切中断时无法强行关闭的中断,其响应函数中绝对禁止操作rtt的任何IPC组件。基本上一操作内核就要卡死。给个建议,可以在精密延时结束之后把中断优先级改回来,然后再加一次延时溢出,最后在那个多出来的溢出响应函数中操作IPC组件,内核就能稳定不崩溃了。

文章来源:https://blog.csdn.net/fox0815/article/details/135682695
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。