本帖最后由 杨为民 于 2024-3-31 10:59 编辑
一、引 言 (1)通常包括uC/OS-II在内的单片机上的RTOS都使用关闭总中断作为对临界资源和临界过程的保护方法,但是这种方法会影响RTOS系统的实时性。 在单片机RTOS中任务控制块(TCB)是最重要的临界资源,控制各个任务的状态。在单片机RTOS中进行任务调度是最重要的临界过程,它根据系统和用户的要求对RTOS的临界资源进行读写操作。 处于对操作系统可靠性的要求,要求对这些临界资源的操作必须是独占地连续地进行,因此关闭总中断是一种最简单的方法,可以确保临界区内的程序连续地被执行。 在临界区中关闭总中断执行程序的时候,任何中断都会被阻塞不能发生,这个中断延迟时间就成了RTOS系统的实时响应时间上限。 因此对于一个RTOS系统,这个中断延迟时间越小越好,最好为零。 (2)STC32G/F是STC最新的32位单片机系列,片上的大量高速设备可以在很多领域得到应用。片上众多的高速设备都需要中断的支持,中断源的数量已经超过60个。基于80251的中断机制,除个别中断外,总中断(EA)一个标志位,控制着这些所有这些中断的使能,如果在临界区中关闭总中断,则所有硬件中断都会被阻塞不能发生,如果这时发生同步/异步通讯中断请求,则可能产生通讯错误。 因此对于STC32G单片机RTOS系统,关闭总中断的时间越小越好,最好任何时候都不关闭总中断。 (3)挑战者x51-UCOS2 V3.10是uC/OS-II在STC32G单片机上移植版。其设计目标是: 在RTOS的所有内核中都不涉及对总中断标志“EA”的操作,在整个单片机运行过程中,挑战者x51系统都不会关闭总中断,实现零中断延迟,适用于对系统实时性及中断响应速度有很高要求的场。 (4)为了展示移植版的特色,判断移植版是否达到移植目标,移植版必须配有一些可以在实际单片机上运行的范例程序。 为了展示挑战者x51移植版是否达到所有内核函数全局不关总中断(零中断延迟)的目标,本文提供了三个范例,这三个范例都使用了定时器0的模式3不可屏蔽中断来作为挑战者x51实时操作系统的节拍器。 第一个范例显示了任何时候不关闭系统中断的效果,第二个范例显示了关闭总中断并不影响定时器0的不可屏蔽中断和RTOS的任务调度,第三个范例显示了在移植版中使用加锁/解锁的临界区保护方法不影响任何中断的发生。 二、挑战者x51的移植源 (5)挑战者x51-UCOS2 V3.10的移植源采用“Silicon Laboratories Inc.”的开源版本,文末附件有原始的移植源。 在该开源版本中已经有很多种单片机的移植样板,见下图: 本文选择“ARM-Cortex-M”样板作为参考源。 (6)由于uC/OS-II内核源是一个结构庞大的可裁剪的程序库,其中许多设置要针对具体的单片机和编译器决定,对于产品版应该从最原始的开源程序开始移植,这样有助于全面掌握整个RTOS体系架构,针对移植目标进行必须得选择和设置,才能更好地打造一个可靠的RTOS体系架构。 (7)uC/OS-II架构中,有大量的DEBUG接口和代码。从本质上说,这些DEBUG接口和代码就是RTOS的“供黑客进入的后门”,不利于正式产品的可靠性。本文移植版的目标群体是最终用户,所以就尽量去掉了uC/OS-II的DEBUG部分。 不同的产品版的目标可以不同,但是每个产品版的目标必须明确。面向开源的产品和面向用户的产品的定位不同,对移植源的选择和设置也不同。 三、实现零中断延迟的技术方法 (8)一般的主流单片机RTOS均或多或少地使用关闭总中断的方法来进行临界区保护,而RTOS的许多核心功能程序中都加入了临界区保护语句。为了使得uC/OS-II的移植版实现零中断延迟的目标,本移植版采用了两个技术方法,见下图:
一是将中断里任务切换方法“OSIntCtxSw()”定义为空的宏,在移植版中只使用中断外任务切换方法“OS_TASK_SW()”。这样所有的任务调度都与单片机中断无关——当然也就与关闭或者打开总中断EA无关了。 二是将uC/OS-II核心程序中的进入和退出临界区保护方法的宏函数“OS_ENTER_CRITICAL()”和“OS_EXIT_CRITICAL()”定义为“空宏”,相当于核心程序中的那些临界区保护语句为只有一个分号的空语句,这样一来整个RTOS系统编译出来的代码和运行效果都与总中断EA无关了,更不会去关闭总中断,造成任何中断延迟了。 四、实时响应的用户中断程序
(9)本文范例建立三个实时任务,实时任务见前文范例3,在没有任何中断的时候,它的运行效果是这样的: 其中通道2是主任务B信号,它控制着其他两个任务的执行。通道4是任务A,通道5是任务C。通道3是中断外任务切换信号,本范例的任务切换时间是1.375微秒。
(10)本文范例启用5个定时器作为中断源,其设置如下: 其中第71行到第73行将定时器0设置为优先级最高的“模式3 不可屏蔽中断”。采用这个模式,当第84行第一次打开总中断后,定时器0的中断就再也不受EA的控制了。除了定时器0外,其他定时器中断都分别驱动LDE进行显示,为了获得肉眼可见的效果,第77行到第80行启动了定时器的预分频,降低了定时器的中断频率。
下图是定时器中断ISR的程序: (11)本文范例中定时器0是作为系统节拍定时器,其工作频率为1KHz,驱动系统节拍函数“OSTimeTick()”。由于采用了不可屏蔽中断模式,因此每个系统节拍都不会被阻塞,保证了RTOS系统时间和节拍的精确性。用户应用中的RTOS定时器中断也应该放到这个中断中来。
有了这些定时器中断信号源,P2端口的实际运行情况的逻辑分析仪截屏见下图: 其中通道0是定时器0中断信号,通道1是定时器1中断信号,通道6是定时器2中断信号。从图中可以看到这些中断信号是连续的。 由于本文范例中所有涉及临界区保护的语句皆为空,不会执行任何关闭中断的效果,这些中断都是零延迟的。 五、不可屏蔽中断
(12)为了查看不可屏蔽中断的效果,本文范例B在主控任务程序中的一段关闭了总中断,以此显示总中断EA的影响效果。下图为测试程序: 其中第126行开始关闭总中断,到第149行结束打开总中断,在这个区间中总中断EA是关闭的。下图是测试效果: 上面图中可以看到EA=0只关闭了通道1的定时器1和通道6的定时器2中断信号,但是通道0的定时器0的不可屏蔽中断不受EA=0的影响。 六、加锁/解锁的临界区保护方法 (13)通常的单片机RTOS都有关闭总中断(或者用户中断)和对任务调度进行加锁/解锁这两种临界区保护方法,uC/OS-II也不例外。挑战者x51 uC/OS-II V3.10移植版虽然将关闭总中断的临界区保护方法设置为空,但是仍然可以将对任务调度加锁的“OSSchedLock()”函数作为进入临界区的保护方法,可以将对任务调度解锁的“OSSchedUnlock()”函数作为退出临界区的保护方法。
(14)下面是对任务B的部分程序进行嵌套临界区保护的测试程序,进入临界区保护的测试程序: 下图是退出临界区保护的程序: (15)本文范例C进行不关闭总中断的临界区保护方法的运行效果如下图: 首先从图中可以看出这种对任务切换进行加锁/解锁的临界区保护方法对中断没有影响,不影响RTOS系统的实时响应。 其次在被保护的临界区中,CPU的控制权一直在任务B手上,没有被切换,被保护的程序不间断地被执行。 最后在临界区结束,任务切换功能被恢复后,临界区中被就绪(被阻塞)的任务C和任务A才会被切换执行。 值得注意的是有两个任务就绪了,优先级最高的任务A被调度先执行。对比上面的图,任务A和任务C的执行次序颠倒了。 七、总 结 (16)在采用了空的临界区保护语句和只使用中断外任务切换函数这两条技术方法后,STC32G单片机uC/OS-II-RTOS移植版实现了全局不关闭总中断,实现了零中断延迟,适用于对系统实时性及中断响应速度有很高要求的场。
(17)挑战者x51 V3.10移植版的不关闭任何中断的加锁/解锁的临界区保护方法,既能够保证临界区中的程序得以连续执行,又能够保证所有的硬件中断可以不受影响的自由发生,真正实现在临界区中硬件中断的零延迟。
|