当前位置:首页 > 嵌入式 > 嵌入式软件
[导读] mC/OS-II内核工作原理实时嵌入式操作系统mC/OS-II内核的工作原理如图1所示。首先,在主程序中对操作系统进行初始化,完成mC/OS-II所有变量和数据结构的初始化,包括任务控

 mC/OS-II内核工作原理

实时嵌入式操作系统mC/OS-II内核的工作原理如图1所示。首先,在主程序中对操作系统进行初始化,完成mC/OS-II所有变量和数据结构的初始化,包括任务控制块(TCB)初始化,TCB优先级表初始化,TCB链表初始化,事件控制块(ECB)链表初始化以及空闲任务的创建等。

然后,根据应用程序的需要,用户可以调用OSTaskCreate()函数创建多个任务(至少1个)。该函数为新任务建立任务堆栈(OSTaskStkInit())以及初始化任务控制块TCB(OS_ TCBInit())。

最后,通过调用OSStart()启动多任务调度。程序将跳到就绪表中优先级最高的任务开始执行。这里假设启动多任务调度前创建了一个任务Task1()。

程序进入Task1()后,首先初始化时钟和启动时钟节拍源开始计时。此节拍源给系统提供周期性的时钟中断信号,实现延时和超时确认。然后根据应用程序要求,完成该任务的基本功能。最后,调用OSTimeDly(),将自己挂起,即从就绪表中删除。直到等待延时时间到,才将该任务恢复到就绪表中,并等待调度器的调度。

OSTimeDly()将任务挂起的同时,为其做好延时记号,然后调用OS_Sched()进行任务级的任务调度。若此时没有任何任务进入就绪态,就切换到空闲任务。

当时钟中断来临时,系统进入中断服务程序OSTickISR()。系统把当前正在执行的任务挂起,保护现场,进行中断处理OSTimeTick(),判断有无任务延时到期,若有,则使该任务进入就绪态。最后调用OSIntExit()进行中断级的任务调度,从而切换到优先级最高的任务,若没有别的任务进入就绪态,则恢复现场继续执行原任务。

AT91FR40162简介

AT91FR40162是ATMEL公司出品的一款基于ARM7TDMI内核的AT91 16/32位微控制器,其核心为高性能的32位RISC体系结构,并具有高密度的16位指令集和极低的功耗。

ARM处理器共有7种运行模式,处理器模式可以通过软件控制进行切换,也可以通过外部中断或异常处理过程进行切换。在每一种处理器模式中有一组相应的寄存器组。任意时刻(也就是任意的处理器模式下),可见的寄存器包括15个通用寄存器(R0~R14)、一个或两个状态寄存器及程序计数器(PC)。

CPSR(当前程序状态寄存器)可以在任何处理器模式下被访问。它包含了条件标志位、中断禁止位、当前处理器模式标志以及其他的一些控制和状态位。每一种处理器模式下都有一个专用的物理状态寄存器,称为SPSR(备份程序状态寄存器)。当特定的异常中断发生时,这个寄存器用于存放CPSR的内容。在异常中断程序退出时,可以用SPSR中保存的值来恢复CPSR。

mC/OS-II在

AT91FR40162上的移植

本文使用的内核是mC/OS-II v2.76,选用ADS1.2中的C编译器。

整个移植过程主要分为两个方面:与应用相关的mC/OS-II配置(OS_CFG.H,INCLUDES.H);与处理器相关的mC/OS-II移植(OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C)。

OS_CPU.H

此文件中主要是定义了一些与处理器相关的常数、宏以及类型。根据ADS1.2的编译手册,char型变量为8位,short型为16位,int型为32位,堆栈为32位宽。另外,v2.76版本中新增加了一个全局变量OSIntCtxSwFlag,如果需要中断级的任务切换时,就令OSIntCtxSwFlag=TRUE。

OS_CPU_C.C

在这里需要编写两个函数:OSInitHookBegin()和OSTaskStkInit()。

OSInitHookBegin()在OSInit()中调用,用来初始化移植中出现的特殊变量。这里将OSIntCtxSwFlag初始化为0。

OSTaskStkInit()在OSTaskCreate()和OSTaskCreateExt()中调用,用来初始化任务的栈结构。图2显示了初始化后任务栈的结构。堆栈从上往下递减。mC/OS-II规定任务工作在SVC模式下。另外,根据ATPCS规定,子程序间通过R0~R3传递参数,所以参数p_arg放在R0里。

与以往的版本不同,这里OSIntCtxSw()(由OSIntExit()调用)并不完成任务的切换工作,仅将OSIntCtxSwFlag变量置1,标志需要进行任务切换。当OSIntExit()调用返回到ISR时,检查OSIntCtxSwFlag变量,如果为1,则跳到OS_IntCtxSw()函数执行任务切换。

OS_CPU_A.S

由于C语言不能对寄存器进行直接操作,所以必须用汇编语言编写以下函数。

OSStartHighRdy()由OSStart()调用。该函数使就绪态任务中优先级最高的任务开始运行。注意开始要将IRQ和FIQ中断禁止,最后从堆栈弹出所有寄存器时,必须按照OSTaskStkInit()中相反的顺序弹出。

OSCtxSw()由OSSched()调用,完成任务级的任务切换。任务级的任务切换包括将当前任务在SVC模式下的寄存器压入任务栈中,并且将新任务的堆栈弹出到SVC模式下的寄存器中。注意必须按照OSTaskStkInit()中任务栈的结构对任务栈进行操作。

OS_CPU_SR_Save()用于关中断,OS_CPU_SR_Restore()用于开中断。OS_CPU_SR_Save()将CPSR保存到R0中,通过将CPSR中I位和F位置1来禁止IRQ和FIQ中断。OS_CPU_SR_Restore()只需将R0中保存的CPSR恢复即可。

OS_IntCtxSw()完成中断级的任务切换。当检查OSIntCtxSwFlag变量为1时,就调用该函数。因为OS_IntCtxSw()是在ISR中被调用的,所以所有的处理器寄存器都已经被正确地保存到了被中断任务的堆栈中。

mC/OS-II 要求用户提供一个周期性的时钟源,来实现时间的延迟和超时功能。这里时钟节拍设为100次每秒,使用定时器0来完成该任务。时钟节拍中断OSTickISR()代码如下,此时系统进入IRQ模式。

STMFD SP!, {R0-R3, R12, LR}

BL OSIntEnter

BL Tmr_TickISR_Handler

BL OSIntExit

LDR R0,addr_OSIntCtxSwFlag

LDR R1, [R0]

CMP R1, #1

BEQ OS_IntCtxSw

LDMFD SP!, {R0-R3,R12,LR}

SUBS PC, LR, #4

Tmr_TickISR_Handler是中断处理程序,用C语言编写。如果是其他类型的中断,可以替换为相应的中断处理程序。这里定时器0中断处理程序要做的工作是首先清中断源,即读取TC_SR寄存器值,AIC_ICCR=0x00000010,然后告诉处理器中断结束(向AIC_EOICR写数据),最后调用OSTimeTick()函数,对延时记号进行处理。

定时器0的设置为:WAVE模式;TC_CMR中CPCTRG=1,表示RC比较将复位计数器并开启时钟;TC_RC=计时时间;TC_IER=AT91C_TC_CPCS,允许RC比较中断。[!--empirenews.page--]

移植中要注意的问题

由于各方面的原因,移植中编写的代码不一定完全正确,需要进行逐步调试。调试过程中,要善于根据具体现象来发现问题所在。根据笔者的调试经历,总结了一些移植调试过程中要注意的问题。

(1) 对mC/OS-II的内核机理要有充分理解。可以尝试对其内核进行调试,这样可以帮助自己从更深的层次来理解嵌入式实时操作系统。只有对mC/OS-II的内核有了清楚地认识,才能在移植过程中发现问题的本质。

(2) 对所使用的编译器要有深刻细致的了解。由于ADS1.2的C 编译器有很多优化编译选项和流水处理选项,在处理内核编译时很容易有冲突,所以,选择优化选项要慎重。加强对ADS1.2的C 编译器的理解,可以节约代码编写时间。

(3) 在移植过程中,最容易出问题的就是堆栈处理。堆栈处理是操作系统移植的关键部分。先分析ARM系统自身在进行现场保护时的堆栈处理的操作,然后模拟其过程。关键是要将需要的寄存器都保护到。由于我们在进行任务切换的时候采用了系统函数来进行现场保护,因此在堆栈初始化的时候,就应该按照这两个函数的操作来对任务堆栈进行初始化。

(4) 要详细分析ARM系统自自身处理中断时的压栈操作,必须将多余的信息从堆栈中清理干净。如果对编译器不熟悉,可以通过仔细调试中断,来确定编译器的具体操作。在对AT91FR40162的移植中,由于ARM处理器有7种运行模式,每种运行模式下都有自己独立的寄存器,所以在处理中断的过程中,要注意运行模式的切换,避免寄存器的内容无法正确保存和恢复。

(5) 注意程序的返回地址。异常中断发生时,程序计数器PC所指的位置对各种不同的异常中断是不同的,所以,返回地址也是不同的。需要根据不同的中断类型,确定不同的中断返回地址偏移量,否则程序将跑飞。

结语

本方案经过测试已证明移植成功。本文是以AT91FR40162为例,说明mC/OS-II移植,对于ARM系列的处理器,只需稍加改动就可以实现。

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭