单片机RTOS是软件与硬件结合的产品,RTOS的性能指标与软件方法和硬件架构都密切相关。了解RTOS的性能指标是用户选择和应用RTOS的前提。RTOS的性能指标主要包括任务切换时间和系统本身占用内存的多少。 针对STC不同系列的单片机和C语言编译模式,笔者移植的uC/OS-II STC单片机研究版分为三个了不同的版本。根据实际测试这三个研究版的主要性能指标如下: 1)STC8H8K64单片机版本: 任务切换时间小于15微秒;code代码空间占9576字节;data空间不含系统堆栈(64字节)只占用14字节;xdata空间不含用户任务堆栈和空闲任务堆栈,只占433字节(含192字节的TCB)。 2)STC32G12K128,XL编译模式版本(RAM模式为Xsmall,CODE模式为Large,用户任务堆栈和空闲任务堆栈均设置在EDATA中): 任务切换时间小于4微秒,code代码空间占4854字节,比上面使用8位的8051指令集的STC8H要少了很多;data空间占19字节;edata空间不含用户任务堆栈和空闲任务堆栈,不含系统堆栈(256字节)只占用1字节;xdata空间占522字节(含192字节的TCB)。 3)STC32G12K128,LL编译模式版本(RAM模式为Xsmall,CODE模式为Large,用户任务堆栈和空闲任务堆栈均设置在XDATA中): 任务切换时间小于31微秒;code代码空间占4940字节;data空间占11字节;edata空间占2字节,不含系统堆栈(256字节);xdata空间占522字节(含192字节的TCB)。 虽然STC32G的LL编译模式版本类似STC8H,但是保存中断寄存器现场需要移动40个字节,而对于STC8H保存中断寄存器现场只需要移动15个字节,因此LL版本的任务切换时间是STC8H的两倍。 对于XL版本,由于系统堆栈和用户任务堆栈都在EDATA空间,所以任务切换时间是最短的。 一、简 介 (1)uC/OS-II分三个重要部分:下层硬件接口、任务调度核心和任务间协调工作。下层硬件接口是移植的重点,除了这个部分程序是用汇编语言编写的,其他两个部分程序都是用C语言编写的。uC/OS-II程序框架设计巧妙,通常只需要改写下层硬件接口就可以将uC/OS-II移植到新的单片机上了,目前将uC/OS-II移植到8051类单片机上有多个版本都只是改写了这个部分。 (2)具有众多的硬件中断是STC8H和STC32G/F单片机最重要的特色,但原始的uC/OS-II却很少涉及这一部分,为了发挥STC的特色,笔者经过研究后特别修改了中断嵌套保护和临界区保护的汇编语言程序,同时也修改了相关的C语言程序,形成了微山x51 uC/OS-II 研究版(以下简称研究版)。 (3)为了突出重点研究内容,研究版范例硬件采用了最简单的“打狗棒”作为STC8H单片机的开发板,采用了最简单的“降龙棍”作为STC32G单片机的开发板。研究范例只使用开发板上的LED灯作为实时任务的视觉显示,同时使用P2端口连接一个8通道逻辑分析仪来显示各个任务的时序关系以及测量各种性能指标。 下图是开发板的外观照片: 下面是研究版范例程序运行的效果视频: 从视频中可以看到开机时的LED闪烁LOGO,可以看到开发板左上部的P0端口LED的交替闪烁(任务A),左下部的P1端口LED的左右闪烁(任务B),右下部的P3端口LED的跑马灯(任务C),以及右上部的P2端口逻辑分析仪的LED闪烁。
下图是6.5秒逻辑分析仪的整体截屏: 图中第0通道是10KHz的定时器3中断信号(系统任务切换中断), 第1通道是中断任务切换信号, 第2通道是任务A信号, 第3通道是非中断任务切换信号, 第4通道是任务B信号, 第5通道是任务C信号, 第6通道是1KHz的定时器0中断信号(系统时间节拍服务), 第7通道是空闲任务1毫秒延时的信号。 二、研究版的内存分配 (4)研究版的用户程序对于STC8H单片机和STC32G单片机都是一样的,只是任务堆栈定义的空间不同。
1)对于STC8H单片机上的STC8H研究版,它的全部任务堆栈必须放在XDATA空间,其定义和主函数“main()”如下: 其中第18行到第20行以显式的方法定义了三个任务的堆栈。
2)对于STC32G单片机上的“XL模式”研究版,它的全部任务堆栈必须放在EDATA空间,其定义如下: 除了第18行到第20行的任务堆栈定义不同,其他程序与STC8H的相同。
3)对于STC32G单片机上的“LL模式”研究版,它的全部任务堆栈必须放在XDATA空间,其定义如下: 除了第18行到第20行的任务堆栈定义不同,其他程序与STC32G单片机上的“XL模式”研究版的相同。 (5)由于三个研究版的范例程序相同,通过C51/C251的编译结果,可以分析比较各个研究版占用的存储空间。 对于研究版范例,3个实时任务堆栈的长度是一样的,空闲任务堆栈可以不同。实时任务堆栈长度一样是原始uC/OS-II设计的一个瑕疵,本次研究版移植时笔者没有去修改它。
STC8H研究版编译结果见下图: 其中code代码空间占9576字节。 data空间占78字节,含8字节的R0~R7,64字节的系统堆栈,其他占6字节。 xdata空间占4027字节,含3072字节的实时任务堆栈,512字节的空闲任务堆栈,其他占433字节。
(6)STC32G单片机XL研究版编译结果见下图: 其中code代码空间占4854字节,对比上面STC8H,由于STC32G使用了32位指令集,代码长度比使用8位的8051指令集要减少很多。 data空间占19字节,含8字节的R0~R7,其他占11字节。 edata空间占2305字节,含2048字节的实时任务和空闲任务堆栈,256字节的系统堆栈(SP),其他占1字节。 xdata空间占522字节。
(7)STC32G单片机LL研究版编译结果见下图: 其中code代码空间占4940字节,对比上面的STC32G的XL模式,LL模式需要将堆栈数据在EDATA空间与XDATA空间之间进行复制,保存与恢复任务现场,因此多了大约100个字节。 data空间占19字节,含8字节的R0~R7,其他占11字节。 edata空间占258字节,含256字节的系统堆栈(SP),其他占2字节。 xdata空间占4106字节,含3072字节的实时任务堆栈和512字节的空闲任务堆栈,,其他占522字节。 三、研究版的中断服务程序
(8)在单片机RTOS程序中,中断程序必须严格地按照一定的框架来写,下图是研究版范例的中断服务程序: 每个RTOS的中断服务程序包含两个大的部分:第一个部分从第55行的CODE程序段定义开始到第92行的中断返回指令结束,是一个可以重定位的代码段,第二个部分从第96行开始是一个绝对地址代码段,由它在指定的中断矢量地方放置一条远跳转指令,将程序转到对应的中断服务程序去执行。 (9)从上面的程序可以看到每个RTOS的中断服务程序固定包含三个部分,以定时器3中断为例,首先是进入中断的部分,第81行在中断一开始就将中断嵌套计数加1,然后用宏代码“STC32G_PUSHALL”将当前任务的寄存器现场推入系统堆栈(在EDATA中)保存起来。 第二部分是用“LCALL”指令访问C语言编写的中断处理程序,见第86行。 第三部分是恢复被中断任务的寄存器现场(第88行)和将中断嵌套计数减1(第90行),最后用“RETI”指令退出中断服务程序。 (10)上面ISR程序中的第62行、第75行、第80行和第91行是测试语句,它们在逻辑分析仪的第6通道和第0通道产生进入中断的正脉冲信号。 1)通道0:定时器3中断信号,对于三个研究版的测量结果如下: STC8H 5.625微秒 STC32G XL模式 3.750微秒 STC32G LL模式 3.750微秒 这个时间是在没有发生中断任务切换的时间(上面程序第80行到第91行),也就是当“uCx51_IntSched()”任务调度函数没有检测到更高优先级任务就绪时花费的时间。 2)通道6:定时器0中断信号,对于三个研究版的测量结果如下: STC8H 27.750微秒 STC32G XL模式 5.875微秒 STC32G LL模式 4.625微秒 这个时间是包括“OSTimeTick()”时间节拍函数的时间。uC/OS-II按节拍来处理休眠的任务,对于休眠的任务每个节拍将休眠计数减1,减到0就将该任务置为就绪状态,结束休眠。由于节拍计数是32位的整数,所以32位的STC32G单片机的处理速度要比8位的STC8H单片机速度要高很多。 3)通道1:中断任务切换的信号,对于三个研究版的测量结果如下: STC8H 14.125微秒 STC32G XL模式 3.375微秒 STC32G LL模式 29.500微秒 这个时间是uC/OS-II的中断任务切换函数“OSIntCtxSw()”的执行时间。 4)通道3:非中断任务切换的信号,对于三个研究版的测量结果如下: STC8H 14.375微秒 STC32G XL模式 4.000微秒 STC32G LL模式 30.125微秒 这个时间是uC/OS-II的非中断任务切换函数“OSCtxSw()”的执行时间。 (11)*重要结论1:由于XL模式的任务堆栈是在EDATA空间中,而C251的函数重入堆栈也是在EDATA空间中,因此对于XL模式,每次每次任务切换时只需要保存当前任务的寄存器现场和恢复新任务的寄存器现场,所以任务切换速度极快。上面XL模式与STC8H速度的对比差异大致反映了32位单片机与8位单片机的差异。 (12)*重要结论2:由于LL模式的任务堆栈是在XDATA空间中,而C251的函数重入堆栈是在EDATA空间中,因此对于LL模式,每次任务切换时先要将EDATA空间中的当前“任务现场”——包括寄存器现场和任务数据现场(当前调用的全部可重入函数的参数和局部数据),全部复制到位于XDATA空间的任务堆栈中,然后把新任务的“任务现场”从位于XDATA空间的任务堆栈中又全部复制到EDATA空间中作为当前“任务现场”,最后再开始进行任务切换,所以要花费的时间很长,甚至长于STC8H的任务切换时间。 四、结 论 (13)在RTOS程序中,中断服务程序必须按照固定的格式用“汇编语言”编写。这时因为用C语言编写的ISR程序,寄存器现场的保存与恢复是由C语言编译器产生的,这就带来两个严重问题: 首先如果用C语言写中断嵌套计数操作“uCx51_IntNesting++”语句会出现在保存现场指令序列之后以及“uCx51_IntNesting--”语句会出现在恢复现场指令序列之前,这样如果在寄存器保存或者恢复期间再次发生更高优先级的中断,这时的中断嵌套计数就是不正确的,如果产生带着未完成的中断切换任务,将会产生不可预料的后果。 其次C语言编译器会进行优化,每个中断保存和恢复的寄存器可能不一样,这样会造成堆栈中的现场不一样,有可能在进行任务切换时(按固定的寄存器序列)发生堆栈溢出或者不平衡的问题,同样可能会造成不可预料的后果。 因此从完美主义的角度看和从RTOS平台应具有极端的可靠性的要求看,那些在RTOS程序中使用C语言写中断服务程序的做法是不规范的,是存在BUG的,有可能某个时候就会产生预料之外的问题。 (14)从上面的测量分析中可以看到,由于下面3个原因使得C251编译器可能成为限制未来STC32位单片机(RAM存储器大于128KB,最多为8M)RTOS发展的天花板: 1)C251取消了C51的“C_XBP”函数重入堆栈指针,将函数重入堆栈设置在EDATA空间,而80251架构的内核的EDATA空间最多只有64KB,因此如果RTOS采用XL模式,虽然任务切换速度很快,但所有的任务堆栈加起来不能超过64KB,难以实现大规模程序。 2)如果RTOS采用LL模式,虽然所有任务堆栈的规模可以超过64KB直到8MB,但是每个任务的堆栈仍然不能超过64KB,仍然难以实现大规模程序。 3)如果RTOS采用LL模式,对于大型程序每个任务在EDATA空间中的可重入函数数据会很大,这样在进行任务切换时需要移动的数据太多,这种情况下任务的切换时间有可能长到不能忍受的长度。
(15)因此对于未来的STC32G/F系列单片机, 即使硬件上具有很大的RAM空间(片上的或者外接), 如何能够像其他32位单片机那样运行大型的RTOS,还需要在技术上有所突破。 附件:研究版范例程序
|