ucos ii是一个源码公开、可移植、可固化、可剪裁和抢占式的实时多任务操作系统,其大部分源码是用ansi c编写,与处理器硬件相关的部分使用汇编语言编写。总量约200行的汇编语言部分被压缩到最低限度,以便于移植到任何一种其它的cpu上。
ucos ii最多可支持56个任务,其内核为占先式,总是执行就绪态的优先级最高的任务,并支持semaphore (信号量)、mailbox (邮箱)、messagequeue(消息队列)等多种常用的进程间通信机制。与大多商用rtos不同的是,ucos ii公开所有的源代码.并可以免费获得,只对商业应用收取少量license费用。
ucos ii移植跟os_cup_c.c、os_cpu_a.s、os_cpu.h 3个文件有关,中断处理的移植占据了很大一部分内容。作为移植的一个重点,本文以标准中断(irq)为例讨论了移植中的中断处理。
1 ucos ii系统结构
ucos ii的软硬件体系结构如图1。应用程序处于整个系统的顶层.每个任务都可以认为自己独占了cpu,因而可以设计成为一个无限循环。大部分代码是使用ansi c语言书写的,因此ucos ii的可移植性较好。尽管如此,仍然需要使用c和汇编语言写一些处理器相关的代码。ucos ii的移植需要满足以下要求:
1)处理器的c编译器可以产生可重入代码:可以使用c调用进入和退出critical code(临界区代码);
2)处理器必须支持硬件中断,并且需要一个定时中断源;
3)处理器需能容纳一定数据的硬件堆栈;
4)处理器需有能在cpu寄存器与内存和堆栈交换数据的指令。
移植ucos ii的主要工作就是处理器和编译器相关代码以及bsp(board support package)的编写。ucos ii处理器无关的代码提供ucos ii的系统服务,应用程序可以使用这些api函数进行内存管理、任务间通信以及创建、删除任务等。
2 ucos ii移植过程中需要注意的几个问题
ucos ii移植的中断处理跟arm体系结构和ucos ii处理中断的过程有关,必须注意这2个方面的问题才能高效移植。
2.1 arm 处理器7种操作模式
用户模式(user mode)是arm 通常执行状态,用于执行大多数应用程序;快速中断模式(fiq mode)支持数据传输或通道处理;中断模式(irq mode)用于通用中断处理;超级用户模式(svc mode)是一种操作系统受保护的模式:数据中止模式(abt mode)指令预取指中止、数据中止时进入该模式;未定义模式(und mode)当执行未定义的指令时进入该模式;系统模式(sys mode)是操作系统一种特许的用户模式。
除了用户模式之外,其他模式都归为特权模式,特权模式用于中断服务、异常或者访问受保护的资源
特权模式中除系统模式之外另5种模式又称为异常模式,在移植过程中必须设置中断向量表来处理异常。ucos ii的移植主要处理标准中断(irq)、快速中断(fiq)和软件中断(swi)。
2.2 ucos ii中断响应的过程
以irq中断为例,假设crps中i_bit位为0,当有irq中断时,cpu强制进入irq模式,当前的cpsr拷贝到spsr_irq中,pc值保存在lr_irq中,置cpsr中的i位以关闭irq中断。数据保存之后,cpu强行从0x00000018开始执行,pc值保存了os_cpu_irq_isr()的地址, 然后执行os_cpu_irq_isr()。在os_cpu_irq_isr()中os_cpu_irq_isr_handler()被调用来检测中断源并执行中断。
os_cpu_irq_isr_handler()返回以后,os_cpu_irq_isr()又调用osintexit()来确认是否有比isr优先级更高的任务要执行。如果当前中断任务仍然是优先级最高的任务,osintexit()返回,os_cpu_irq_isr()弹出中断堆栈,如果优先级更高的任务需要执行,osintexit()调用osintctxsw()执行优先级更高的任务。
2.3 ucos ii的临界段代码
ucos ii使用关中断来保护临界代码。它定义了2个宏来开中断(os_exit_critical()),关中断(os_enter_critical())。os_enter_critical()和os_exit_critical()有3种方法来实现,ucos ii建议使用第3种方法可以保存当前处理器状态的值。
3 ucos ii移植过程中的中断处理
ucos ii中断处理跟crt.s、os_cpu_a.s和bsp.c有关,其移植过程主要有以下几个步骤。
3.1 在crt.s中设置中断向量表
arm的中断向量表位于rom 的最底部,其地址范围为0x00000000~0x0000001c,设置如下:
vectors:ldr pc,reset_addr
ldr pc,undef_addr
ldr pc,swi_addr
ldr pc,pabt_addr
ldr pc,dabt_addr
nop /*保留向量*/
ldr pc,irq_addr
ldr pc,fiq_addr
reset_addr:. word reset_handler
undef_addr:.word undef—handler
swi_addr:.word swi handler
pabt_addr:.word pabt_handler
dabt_addr:.word dabt_ handler
.word 0 /*保留地址*/
irq_addr:.word irq_handler
fiq_addr:.word fiq handler
undef_handler:b undef_handler
swi_handler: b swi_handler
pabt_handler: b pabt_handler
dabt_handler: b dabt_handler
irq_handler: b os_cpu_irq_isr
/*跳转到os_cpu_irq_isr(在os_cpu_a.s中)*/
fiq_handler: b os_cpu_fiq_isr
/*跳转到os_cpu_fiq_isr(在os_cpu_a.s中) */
这里设置了标准中断异常(irq)和快速中断异常(fiq)的中断入口,其余异常都设置为死循环,当发生这些异常的时候,必须使系统复位才能退出死循环。
3.2 移植中断任务切换
中断任务切换(osintctxsw)和任务切换函数(osctxsw)比较相似,主要有以下几步组成:
1)调用ostask swhook()
2)ospriocur=ospriohighrdy
3)ostcbcur=ostcbhighrdy
4)sp=ostcbhighrdy->ostcbstkptr
//获取高优先级的任务堆栈指针
5)从高优先级的任务的堆栈中弹出高优先级的任务上下文
6)执行高优先级的任务
3.3 移植中断服务程序
以irq中断为例中断服务程序(os_cpu_irq_isr)主要依据上面所描述的“ucos ii中断响应的过程”编写,其主要代码如下:
……
ldr r0,os_intnesting
ldrb r1,[r0]
add r1,r1,#1
strb r1,[r0]
cmp r1,#l
bne os_cpu_irq_isr_1
ldr r4,os_tcbcur
ldr r5,[r4]
str sp,[r5]
os_cpu_irq_isr_1:
msr cpsr_c,#(no_int | irq32_mode)
//切换到svc模式
ldr r0,os_cpu_irq_isr_handler
mov lr,pc
bx r0
msr cpsr_c,#(no_int | svc32_mode)
//切换到svc模式
ldrr0,os_intexit //osintexit()
mov lr,pc
bx r0
……
在代码中省略了现场工作寄存器的保护与恢复及工作模式的切换。
3.4 移植中断处理程序
以irq中断为例,移植中断处理程序:
c程序
void os_cpu_irq_isr_handler(void) { pfnct pfnct; //定义中断函数指针 pfnct=(pfnct)vicvectaddr; //获取函数地址 while(pfnct!=(pfnct)0) { (*pfnct)(); //调用中断函数 pfnct=(pfnct)vicvectaddr; //获取新的中断函数 } //所有中断都执行完毕退出}
中断处理程序依赖中断控制器的中断响应顺序,所以ucos ii把os_cpu_irq_isr_handler()归属于用户程序的一部分。在中断返回之前,中断处理程序要处理完所有的中断响应,以避免在多个中断同时响应或中断处理过程中响应中断的情况下, 进入os_cpu_irq_isr () 和退出os_cpu_irq_isr()时,os_cpu_irq_isr()耗尽保存cpu寄存器的堆栈空间。
另外,在os_cpu_irq_isr_handler()中不要清cpsr的i位来开放中断,因为没有必要使用中断嵌套,os_cpu_irq_isr_handler()在返回之前会检查并处理所有的中断。
3.5 编写中断函数
中断函数一般采用c语言编写,ucos ii建议中断函数应尽量短,一般做法是在中断函数中缓存数据,给任务发送一个信号来处理数据。中断函数的地址在系统初始化的时候要置人中断向量寄存器(vicvectaddr0~15)。由于向量中断控制器(vic)的特殊结构,在中断函数中要写一次中断向量寄存器(vicvectaddr)。
4 中断处理的应用示例
ucos ii要提供周期性信号源,用于实现时间延时和确认超时。节拍率应为10~100 hz。时钟节拍源可以由专门的硬件定时器产生,以下就以irq中断方式产生节拍源为示例。
初始化中断控制器:
c程序
void vicinit(void) { vicintenclr=0xfffff; vicdefvectaddr=-(int32u)non_vect_irq_handler; vicvectaddr0= (int32u)ostickisr; vicvectcntl0= (0x20 | 0x04); vicintenable= 1<<4; }
定时器0中断函数:
c程序
void ostickisr(void) { to_ir = 0xff; ostimetick(); //调用ostimetick() vicvectaddr=0; //通知中断控制器中断结束}
当定时中断发生时调用os_cpu_irq_isr handler(),得到ostickisr()的地址并执行,在ostickisr()中调用ostimetick()为ucos ii提供周期性信号源。
此代码在gnu工具链arm-gcc下编译通过,并在easyarm2100开发实验板上得到验证。
5 结束语
通过示例讲述了在ucos ii移植过程中的中断处理所需要注意的几个问题和通用方法,经笔者在gnu工具链下编译、调试,并在实验板上得到很好的验证。这种移植方案的中断函数都使用c语言编写,具有较好的移植性,有利于对不同需求的用户进行中断扩充,增强了中断嵌套时ucos ii运行的稳定性,使移植具有更好的通用性。
stm32/stm8
意法半导体/st/stm
引入空气间隙以减少前道工序中的寄生电容
使用对讲机天线应该注意的问题
中国电信发布“翼节能”成果,实现数据中心的绿色可持续发展
中国首富王传福:从电池大王到汽车大王
力拼小米MIX!联想ZUK Edge新机来也:重新定义Edge
uCOS-II在ARM移植中的中断处理
什么是排电阻?排电阻的识别技巧介绍
“离子风”驱动无人机,未来有望与传统燃烧系统共用
疑似三星 Galaxy Z Fold 3 专利公布,附带 S pen
人工智能可提高效率,利用创新并简化流程
内核内存布局
白光LED驱动电路图
如何选择LED电子显示屏型号
谷景电感技术助力无人机行业升级换代
再谈“软件定义汽车”,剖析SOAFEE的成绩、打法和目标
深圳福凯半导体荣获DEKRA德凯颁发CB CTF Stage 1认可实验室证书
如何用HFSS-API来设计指数渐变传输线?
基于机智云物联网平台的温湿度和光照强度获取
苹果不忘iPhone6等老机型
新款华硕飞行堡垒笔记本曝光,将首发AMD的移动标压处理器