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

带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组件,内核就能稳定不崩溃了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/413043.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go新项目-为何选Gin框架?(0)

先说结论:我们选型Gin框架 早在大概在2019年下旬,由于内部一个多线程上传的需求,考虑到Go协程的优势; 内部采用Gin框架编写了内部的数据上传平台BAP,采用GinVue开发,但前期没考虑到工程化思维,导…

【数据结构】栈的远房亲戚——队列

队列的基本概念 前言一、队列的定义二、队列的重要术语三、队列的基本操作四、数据结构的三要素4.1 线性表的三要素4.2 栈的三要素4.3 队列的三要素 结语 前言 大家好,很高兴又和大家见面啦!!! 在经过前面内容的介绍,…

享元模式介绍

目录 一、享元模式介绍 1.1 享元模式定义 1.2 享元模式原理 1.2.1 享元模式类图 1.2.2 模式角色说明 1.2.3 示例代码 二、享元模式的应用 2.1 需求说明 2.2 需求实现 2.2.1 类图 2.2.2 具体实现 2.2.2.1 抽象享元类 2.2.2.2 共享享元类-白色棋子 2.2.2.3 共享享元…

Qt/QML编程之路:OpenGL的示例(39)

Qt编程之后,会发现有版本问题,有时候一个示例不同的版本下可能会跑不同,有些Qt5跑不同Qt6已经完善,可以跑通。 我就看到有个关于OpenGL的示例: 这个示例是演示怎么基于OpenGL编程的,但是调试时却发现glVie…

你知道怎么做好接口测试?

前言 谈起软件测试,就不得不说一下接口测试,凡是有功能的软件都离不开接口,没有接口的软件只是一个模具或页面,不具备任何功能。 什么是接口 业内常说的接口一般指两种: API:应用程序编程接口&#xff0c…

hub汉语有轮毂的意思吗?

问题描述:hub汉语有轮毂的意思吗? 问题解答: 是的,"hub"(中文翻译为"轮毂")是指机械装置中的一个中心部分,通常用于连接或支持其他部分。在车辆的轮胎系统中,…

npm依赖库备份

常用命令 设置默认使用本地缓存安装Nodejs时会自动安装npm,但是局路径是C:\Users\Caffrey\AppData\Roaming\npm默认的缓存路径是C:\Users\Caffrey\AppData\Roaming\npm-cache;查看npm的prefix和cache路径配置信息设置路径 设置默认使用本地缓存 npm con…

使用nginx搭建网页

一、基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab!!! 具体配置 #下载nginx [rootoula1 ~]# yum install nginx -y #关闭防火墙 1、[rootoula1 ~]# systemctl stop firewalld 2、[rootoula1 ~]# setenforce 0#修改配置文件 [ro…

C++--默认参数

一.默认参数🍗 C中允许函数提供默认参数,也就是允许在函数的声明或定义时给⼀个或多个参数指定默认值。在调 ⽤具有默认参数的函数时,如果没有提供实际参数,C将⾃动把默认参数作为相应参数的值。 二.使用规则🍗 1.如果…

Halcon基于形状的模板匹配

Halcon基于形状的模板匹配 基于形状的模板匹配,也称为基于边缘方向梯度的匹配,是一种最常用也最前沿的模板匹配算法。该算法以物体边缘的梯度相关性作为匹配标准,原理是提取ROI中的边缘特征,结合灰度信息创建模板,并根…

Linux之引导和服务篇

系统引导是操作系统运行的开始,在用户能够正常登录之前,Linux的引导过程完成了一系列的初始化任务,并加载必要的程序和命令终端,为用户登录做好准备。 一. 引导过程 开机自检--->MBR引导--->GRUB菜单--->加载Linux内核-…

【动态规划】【离线查询】【前缀和】689. 三个无重叠子数组的最大和

作者推荐 【动态规划】【数学】【C算法】18赛车 本文涉及的基础知识点 动态规划 滚动向量 离线查询 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode689. 三个无重叠子数组的最大和 给你一个整数数组 nums 和一个整数 k &…