UCOS-II移植ARM的笔记_第1页
UCOS-II移植ARM的笔记_第2页
UCOS-II移植ARM的笔记_第3页
UCOS-II移植ARM的笔记_第4页
UCOS-II移植ARM的笔记_第5页
已阅读5页,还剩34页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、UCOS-II 移植 ARM 的笔记(转贴UCOS-II 的移植需要提供 2, 3个文件分别介绍如下:一:OS_CPU.H1 与编译器有关的数据类型经典的全局变量定义,可以套用,简洁明了实用性好。#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT#else#define OS_CPU_EXT extern#endif只是按照不同的编译器编写对应的数据类型的 typedef对应于 ARM7的数据类型的编写如下typedef unsigned char BOOLEAN; /* 布尔变量 */typedef unsigned char INT8U; /* 无符号 8位整型

2、变量 */typedef signed char INT8S; /* 有符号 8位整型变量 */typedef unsigned short INT16U; /* 无符号 16位整型变量 */typedef signed short INT16S; /* 有符号 16位整型变量 */typedef unsigned int INT32U; /* 无符号 32位整型变量 */typedef signed int INT32S; /* 有符号 32位整型变量 */typedef float FP32; /* 单精度浮点数(32位长度 */typedef double FP64; /* 双精度浮点数

3、(64位长度 */在上面定义的各种数据类型中按照 ARM7的堆栈宽度选择 INT32Utypedef INT32U OS_STK; /* 堆栈是 32位宽度 */2 与处理器相关的代码先定义中断的实现方式,预先设定的中断方式有三种,在 ARM7中设置为方式 2 #define OS_CRITICAL_METHOD 2 /* 选择开、关中断的方式 */_swi(0x00 void OS_TASK_SW(void; /* 任务级任务切换函数 */_swi(0x01 void _OSStartHighRdy(void; /* 运行优先级最高的任 务 */_swi(0x02 void OS_ENTER

4、_CRITICAL(void; /* 关中断 */_swi(0x03 void OS_EXIT_CRITICAL(void; /* 开中断 */_swi(0x40 void *GetOSFunctionAddr(int Index; /* 获取系统服务函数入 口 */_swi(0x41 void *GetUsrFunctionAddr(int Index;/* 获取自定义服务函数入 口 */_swi(0x42 void OSISRBegin(void; /* 中断开始处理 */ _swi(0x43 int OSISRNeedSwap(void; /* 判断中断是否需要切 换 */_swi(0x

5、80 void ChangeToSYSMode(void; /* 任务切换到系统模 式 */_swi(0x81 void ChangeToUSRMode(void; /* 任务切换到用户模 式 */_swi(0x82 void TaskIsARM(INT8U prio; /* 任务代码是 ARM 代 码 */_swi(0x83 void TaskIsTHUMB(INT8U prio; /* 任务代码是THUMB */定义堆栈的生长方式, ARM7内核支持两种生长方式, 但是 ADS 的 C 语言编译器只支持 从上往下的生长方式,因此:#define OS_STK_GROWTH 1 /* 堆栈是

6、从上往下长的, 0-从下往 上的生长方式 */最后几行分别定义了用户模式 01和系统模式 1f 以及 IRQ 中断禁止的指令 80三个立即数, 方便调用。#define USR32Mode 0x10 /* 用户模式 */#define SYS32Mode 0x1f /* 系统模式 */#define NoInt 0x80还有两个预定义往后看应该知道作用,暂不考虑,不是很重要。#ifndef USER_USING_MODE#define USER_USING_MODE USR32Mode /* 任务缺省模式 */#endif#ifndef OS_SELF_EN#define OS_SELF_EN

7、 0 /* 允许返回 OS 与任务分别编译、固化 */#endifOS_CPU_EXT INT32U OsEnterSum; /* 关中断计数器(开关中断的信 号量 */二. OS_CPU.C文件头文件的引用:#define OS_CPU_GLOBALS#include "config.h"/* * 函数名称 : OSTaskStkInit* 功能描述 : 任务堆栈初始化代码,本函数调用失败会使系统崩溃* 输 入 : task : 任务开始执行的地址* pdata :传递给任务的参数* ptos :任务的堆栈开始位置* opt :附加参数,当前版本对于本函数无用,具体意义参

8、见 OSTaskCreateExt(的 opt 参 数* 输 出 : 栈顶指针位置* 全局变量 :* 调用模块 :* 作 者 : 陈明计* 日 期 : 2003年 6月 5日*-* 修改人 : 陈明计* 日 期 : 2003年 6月 13日*-* */OS_STK *OSTaskStkInit (void (*task(void *pd, void *pdata, OS_STK *ptos, INT16U opt OS_STK *stk;opt = opt; /* 'opt' 没有使用。作用是避免编译器警告 */stk = ptos; /* 获取堆栈指针 */* 建立任务环境,

9、 ADS1.2使用满递减堆栈 */*stk = (OS_STK task; /* pc */*-stk = (OS_STK task; /* lr */*-stk = 0; /* r12 */*-stk = 0; /* r11 */*-stk = 0; /* r10 */*-stk = 0; /* r9 */*-stk = 0; /* r8 */*-stk = 0; /* r7 */*-stk = 0; /* r6 */*-stk = 0; /* r5 */*-stk = 0; /* r4 */*-stk = 0; /* r3 */*-stk = 0; /* r2 */*-stk = 0; /

10、* r1 */*-stk = (unsigned int pdata; /* r0,第一个参数使用 R0传递 */*-stk = (USER_USING_MODE|0x00; /* spsr,允许 IRQ, FIQ 中断 */*-stk = 0; /* 关中断计数器 OsEnterSum; */return (stk;OSTaskStkInit ( 函数的功能是初始化任务的栈结构, 任务的堆栈结构与 CPU 的体系结构、 编译器有密切的关联。从 ARM 的结构可以写出如下的栈结构:程序计数器 PC ,程序链接器 LR , R12-R1, R0用于传递第一个参数 pdata , CPSR/SPS

11、R,关中断计数器(用于计算关中断的次数,这样就实现了中断的嵌套,返回的地址指针是指向的最后一个存入的数据, 而不是一个空地址。/* * 函数名称 : SWI_Exception* 功能描述 : 软中断异常处理程序,提供一些系统服务* 输 入 : SWI_Num:功能号* Regs0 为第一个参数,也是返回值* Regs1 为第二个参数* Regs2 为第三个参数* Regs3 为第四个参数* 输 出 : 根据功能而定* 全局变量 : 无* 调用模块 : 无* 作 者 : 陈明计* 日 期 : 2003年 6月 5日*-* 修改人 : 陈明计* 日 期 : 2003年 6月 19日*-* 修改人

12、 : 陈明计* 日 期 : 2003年 6月 24日*-* */#if OS_SELF_EN > 0extern int const _OSFunctionAddr;extern int const _UsrFunctionAddr;#endifvoid SWI_Exception(int SWI_Num, int *RegsOS_TCB *ptcb;switch(SWI_Num/case 0x00: /* 任务切换函数 OS_TASK_SW,参考 os_cpu_s.s文件 */ / break;/case 0x01: /* 启动任务函数 OSStartHighRdy ,参考 os_cp

13、u_s.s文件 */ / break;case 0x02: /* 关中断函数 OS_ENTER_CRITICAL(,参考 os_cpu.h文件 */ _asmMRS R0, SPSRORR R0, R0, #NoIntMSR SPSR_c, R0OsEnterSum+;break;case 0x03: /* 开中断函数 OS_EXIT_CRITICAL(,参考 os_cpu.h文件 */ if (-OsEnterSum = 0_asmMRS R0, SPSRBIC R0, R0, #NoIntMSR SPSR_c, R0break;#if OS_SELF_EN > 0case 0x40:

14、/* 返回指定系统服务函数的地址 */* 函数地址存于数组 _OSFunctionAddr中 */* 数组 _OSFunctionAddr需要另外定义 */* Regs0 为第一个参数,也是返回值 */* Regs1 为第二个参数 */* Regs2 为第三个参数 */* Regs3 为第四个参数 */* 仅有一个参数为系统服务函数的索引 */ Regs0 = _OSFunctionAddrRegs0;break;case 0x41:/* 返回指定用户的服务函数的地址 */ /* 函数地址存于数组 _UsrFunctionAddr中 */ /* 数组 _UsrFunctionAddr需要另外定

15、义 */ /* Regs0 为第一个参数,也是返回值 */ /* Regs1 为第二个参数 */* Regs2 为第三个参数 */* Regs3 为第四个参数 */* 仅有一个参数为用户服务函数的索引 */ Regs0 = _UsrFunctionAddrRegs0;break;case 0x42: /* 中断开始处理 */OSIntNesting+;break;case 0x43: /* 判断中断是否需要切换 */ if (OSTCBHighRdy = OSTCBCurRegs0 = 0;elseRegs0 = 1;break;#endifcase 0x80: /* 任务切换到系统模式 */

16、_asmMRS R0, SPSRBIC R0, R0, #0x1fORR R0, R0, #SYS32ModeMSR SPSR_c, R0break;case 0x81: /* 任务切换到用户模式 */ _asmMRS R0, SPSRBIC R0, R0, #0x1fORR R0, R0, #USR32ModeMSR SPSR_c, R0break;case 0x82: /* 任务是 ARM 代码 */ if (Regs0 <= OS_LOWEST_PRIOptcb = OSTCBPrioTblRegs0;if (ptcb != NULLptcb -> OSTCBStkPtr1

17、&= (1 << 5;break;case 0x83: /* 任务是 THUMB 代码 */ if (Regs0 <= OS_LOWEST_PRIOptcb = OSTCBPrioTblRegs0;if (ptcb != NULLptcb -> OSTCBStkPtr1 |= (1 << 5;break;default:break;软件中断异常 SWI 服务程序 C 语言部分void SWI_Exception(int SWI_Num, int *Regs:参数 SWI_Num对应前面文 件中定义的功能号,其中 0、 1号的功能在后面的文件中定义,这

18、里只定义了其他 10个功能。 2、 3分别对应关中断和开中断关中断:MRS R0, SPSR /在软件中断的时候直接对程序状态保存寄存器 SPSR 操作也就是对 CPSR 的操作ORR R0, R0, #NoInt /在汇编语言中对寄存器的对应位置位用 ORR ,清零用 BICMSR SPSR_c, R0 /SPSR_c表示的是只改变 SPSR 的控制段的 8位代码,其他三段 _f, _s, _x中标志位在 _f段,其他为保留位开中断:MRS R0, SPSR /在开中断中基本与上面相同,只是 ORR 改成 BIC 清零BIC R0, R0, #NoIntMSR SPSR_c, R由于需要实现

19、中断嵌套,所以只有当关中断的计数器减为 0的时候才能够开中断,而且每次 关中断的时候该计数器都应该加 1。另外,插入汇编语言时用 _asm指令。80、 81、 82、 83分别对应系统模式、用户模式、 ARM 指令集、 THUMB 指令集系统模式:MRS R0, SPSRBIC R0, R0, #0x1f /先将控制模式的低 5位清零ORR R0, R0, #SYS32Mode /设置成系统模式的 1FMSR SPSR_c, R0用户模式:MRS R0, SPSRBIC R0, R0, #0x1fORR R0, R0, #USR32Mode /设置成用户模式的 10MSR SPSR_c, R0

20、_OSStartHighRdyMSR CPSR_c, #(NoInt | SYS32Mode ;MSR:在 ARM 中只有 MSR 能够 直接设置状态寄存器 CPSR 或 SPSR ,可以是立即数或者源寄存器, NoInt 是禁止中断, SYS32Mode 是系统模式; 告诉 uC/OS-II自身已经运行LDR R4, =OSRunning ;OSRunning 正在运行多任务的标志,= OSRunning 是把 OSRunning 的地址加载到 R4, R4里存的是一个地址。MOV R5, #1STRB R5, R4 ; 将 R5存储到 R4存的地址的变量即 OSRunning 中,也就是

21、将 OSRunning 置 1BL OSTaskSwHook ; 调用钩子函数, OSTaskSwHook 是用于 扩展的,在任务切换的时候执行用户自己定义的功能。LDR R6, =OSTCBHighRdy ;OSTCBHighRdy 指向最高优先级任务的控制 块 TCB 的指针!将放指针的地址放到 R6中。LDR R6, R6 ; 将 R6地址处的数据读出即 OSTCBHighRdy 的地址放到 R6中B OSIntCtxSw_1 ; 跳转到 OSIntCtxSw_1AREA SWIStacks, DATA, NOINIT,ALIGN=2SvcStackSpace SPACE SVC_STA

22、CK_LEGTH * 4 ; 管理模式堆栈空间继续昨天没有看完的代码OSIntCtxSw; 下面为保存任务环境LDR R2, SP, #20 ; 获取 PC ,放入 R2LDR R12, SP, #16 ; 获取 R12, /R12存的什么东西啊? MRS R0, CPSRMSR CPSR_c, #(NoInt | SYS32Mode ;进入系统模式并禁止中断MOV R1, LR ;R1放 LR 值STMFD SP!, R1-R2 ; 保存 LR,PC ,将 R1, R2存入 SP STMFD SP!, R4-R12 ; 保存 R4-R12,将 R4-12存入 SPMSR CPSR_c, R0

23、 ; 再回到之前的模式LDMFD SP!, R4-R7 ; 获取 R0-R3ADD SP, SP, #8 ; 出栈 R12,PCMSR CPSR_c, #(NoInt | SYS32ModeSTMFD SP!, R4-R7 ; 保存 R0-R3LDR R1, =OsEnterSum ; 获取 OsEnterSumLDR R2, R1STMFD SP!, R2, R3 ; 保存 CPSR,OsEnterSum; 保存当前任务堆栈指针到当前任务的 TCBLDR R1, =OSTCBCurLDR R1, R1STR SP, R1BL OSTaskSwHook ; 调用钩子函数;OSPrioCur &

24、lt;= OSPrioHighRdyLDR R4, =OSPrioCurLDR R5, =OSPrioHighRdyLDRB R6, R5STRB R6, R4;OSTCBCur <= OSTCBHighRdyLDR R6, =OSTCBHighRdyLDR R6, R6LDR R4, =OSTCBCurSTR R6, R4OSIntCtxSw_1; 获取新任务堆栈指针LDR R4, R6 ; 把 OSTCBHighRdy 指向最高优先级任务的控制块 TCB 的 指针给 R4ADD SP, R4, #68 ;17寄存器:CPSR,OsEnterSum,R0-R12,LR,SPLDR LR

25、, SP, #-8 ; 取出 LR 放到 LRMSR CPSR_c, #(NoInt | SVC32Mode ; 进入管理模式并且保持禁止中 断MOV SP, R4 ; 设置堆栈指针LDMFD SP!, R4, R5 ;CPSR,OsEnterSum 。 LDMFD 数据 出栈,放入 R4, R5; 恢复新任务的 OsEnterSumLDR R3, =OsEnterSum ;OsEnterSum 的地址存入 R3STR R4, R3 ; 把 R4的值赋给 OsEnterSumMSR SPSR_cxsf, R5 ; 恢复 CPSR ; 在管理模式里是修改 SPSR LDMFD SP!, R0-R

26、12, LR, PC ; 运行新任务 ,恢复现场,异常处 理返回实时系统概念1 前后台系统不复杂的小系统通常选择前后台系统,应用程序是一个无限循环。在循环中调用相应的函数 完成相应的操作, 这部分可以看成后台行为。 中断服务程序处理异步事件, 可以看成前台行为。 2 代码的临界段需要在前后关开中断的代码,不能被打断的代码3 资源输入输出设备,各种变量,结构,数组4 共享资源可以被多个任务使用的资源5多任务通过 CPU 在许多任务之间转换和调度6任务每个任务都是一个无限循环,都可能处于五种状态之一:休眠,就绪,运行,挂起,被中断。 UCOS 中提供各种函数使任务能从一个状态变为另一个状态每个任务

27、都有自己的 CPU 寄存器和栈空间以及 TCB 任务控制块7任务切换任务切换过程是将正在运行任务的 CPU 寄存器全部内容保存到任务自己的栈区中,再将下一 个要运行的任务的当前状况从该任务的栈中重新装入 CPU 的寄存器, 并开始下一个任务的运行8内核负责管理各个任务,为每个任务分配 CPU 时间,并负责任务间的通信9调度决定该轮到哪个任务运行。主要是通过优先级来决定。总是让处于就绪态的优先级最高的任务 先运行。10不可剥夺型内核每个任务主动放弃 CPU 的使用权,放弃的方法可以使用多种函数定时或者定事件的放弃。异 步事件还是由中断服务来处理。中断处理结束之后还是回到被中断的那个任务直到该任务

28、主动 放弃 CPU 的使用权。 在任务级, 不可剥夺型内核允许使用不可重入函数函数不必担心被重复调 用,因为每个时刻都只有一个任务在运行。当然,该函数不能具有放弃 CPU 使用权的功能。11可剥夺型内核当系统响应时间很重要, 就需要使用可剥夺型内核。 最高优先级任务一旦就绪, 总能得到 CPU 的使用权。 当运行的任务使一个更高优先级的任务进入就绪态, 当前任务的 CPU 使用权就被剥 夺或挂起,更高优先级的任务获得 CPU 的使用权。如果是中断服务子程序造成的, 中断完成后 被中断的任务被挂起,执行更高优先级的任务。在可剥夺型内核中, 要谨慎使用不可重入函数。 因为低优先级的和高优先级的任务

29、有可能都调 用该函数。总是让就绪态的高优先级的任务先运行,中断服务程序可以抢占 CPU12可重入函数可重入函数或者只使用局部变量,要么就是使用全局变量并且对全局变量予以保护。13时间片轮番调度法UCOS 中各个任务的优先级都是不同的。不支持时间片轮番调度14任务优先级从 0开始,越小的优先级越高15静态优先级在执行过程中优先级是不变的16动态优先级优先级在运行过程中可以变化17优先级反转避免优先级反转的方法是使占有共享资源的任务的优先级升到最高。18任务优先级分配19互斥条件满足互斥条件的一般方法:关中断使用测试并置位指令,获得共享资源时置位,只有为零才有权获得共享资源禁止作任务切换:用给任务

30、切换上锁然后开锁的方法利用信号量:信号量的操作:初始化 create 挂起 pend 发送 postUCOS 中是等待信号量任务中优先级最高的20死锁死锁也称为抱死指两个任务无限期地互相等待对方控制着的资源。21同步可以单向同步也可以双向同步22事件标志当某个任务要与多个事件同步时,须使用事件标志。23任务间通信任务间或中断服务与任务间的通信。有两种途径:通过全程变量或者发消息给另一个任务24消息邮箱把一则消息放到邮箱,通过内核也可以接收这则消息。25消息队列用于给任务发消息。26中断27中断延迟28中断响应29中断恢复时间对于可剥夺型内核,中断的恢复要复杂一些。在中断服务子程序的末尾,要调用

31、一个由实时内 核提供的函数。这个函数用于判断中断是否脱离了所有嵌套。如果脱离了嵌套就判断是否中断 让一个更高优先级的任务进入就绪。30中断延迟、响应及恢复31中断处理时间32非屏蔽中断33时钟节拍34对存储器的需求使用多任务内核时内核本身需要额外的代码空间 ROM 。因为每个任务都是独立运行的,必须 给每个任务提供单独的栈空间 RAM 。内核结构1临界段, OS_ENTER_CRITICAL和 OS_EXIT_CRITICAL开关中断的实现方法分三种:1直接用处理器指令2在堆栈中保存中断的开关状态,然后再关中断。3通过编译器提供的 c 函数来保存处理器状态字的值。2任务3任务状态睡眠态:在 R

32、OM 或 RAM 中,交给 UCOS 要调用下面两个函数之一:OSTaskCreate 或 者 OSTaskCreateExt ,调用之后告诉了 UCOS 任务的起始地址,优先级,要使用多少栈空 间。就绪态:建立了任务之后,就进入就绪态。如果是由任务建立的新任务且优先级更高,那么新 建的任务将立即得到 CPU 使用权。通过 OSTaskDel 将一个任务返回到睡眠态。运行态:调用 OSStart 可以启动多任务,该函数运行用户初始化代码中已建的优先级最高的 任务。等待态:正在运行的任务通过两个函数将自己延迟即进入等待状态。 OSTimeDly 或者 OSTimeDlyHMSM 。这两个函数将会

33、立即执行强制任务切换,让下一个优先级最高且进入就 绪态的任务运行。当延时时间到后,系统服务函数 OSTimeTick 将会让等待的任务进入就绪 态。在运行中的任务如果调用 OSFlagPend 、 OSSemPend 、 OSMutexPend 、 OSMboxPend 或者 OSQPend 时时间并没有发生,那么该任务就进入等待态,此时最高优 先级的就绪态任务进入运行态。 当等待事件发生或者等待超时, 该任务就从等待态进入就绪态。 中断服务态:正在运行的任务可以被中断。被中断了的任务进入中断服务态。响应中断时该任 务被挂起,中断服务子程序可能报告多个事件发生,从而使得更高优先级的任务进入就绪

34、态,当中断返回时会重新判断优先级,让最高优先级的任务运行,如果由更高优先级的任务那么先 执行,直到被挂起的任务的优先级最高才会返回到被中断挂起的任务。4任务控制块 TCB当任务建立的时候,一个任务控制块 TCB 就被赋值,任务控制块能确保任务从被中断的那一 点丝毫不差的继续运行。 OS_TCB全部驻留在 RAM 中。 OS_TCB中包括:指向当前任务堆 栈栈顶的指 OSTCBStkPtr 、指向用户定义的任务控制块扩展 OSTCBExtPtr (该扩展数据 结构包含任务名字、跟踪某个任务的执行事件、跟踪切换到某个任务的次数、指向任务堆栈 栈底的指针 OSTCBStkBottom (如果堆栈指针

35、递减则指向任务使用的栈空间的最低地址 、 存有栈中可容纳的指针元数目 OSTCBStkSize (是指针元数目,乘以地址宽度即为实际栈容 量 、 选择项 OSTCBOpt (传给 OSTaskCreateExt 、 用于存储任务的识别码 OSTCBId 、 用于任务控制块双向链表的前后链接 OSTCBNext/OSTCBPrev、指向事件控制块的指针 OSTCBEventPtr 、指向传递给任务的消息的指针 OSTCBMsg 、指向事件标志节点的指针 OSTCBFlagNode 、使任务进入就绪态的事件标志 OSTCBFlagsRdy 、延时或者挂起一段 事件时用来计时的变量 OSTCBDly

36、 、任务的状态字 OSTCBStat (OS_STAT_READY-就 绪态、任务的优先级 OSTCBPrio 、用于加速任务进入就绪态的过程或进入等待事件发生状 态的过程 OSTCBX/OSTCBY/OSTCBBitX/OSTCBBitY、一个表示该任务是否须删除的 布尔量 OSTCBDelReq 。所有的任务控制块 OS_TCB都是放在任务控制块列表数组 OSTCBTbl 【】中。所有任务控制块 OS_TCB都被链接成单向空任务链表。任务一旦建立, 空任务控制块指针 OSTCBFreeList 指向的任务控制块便赋给了该任务。 任务建立时, 任务建 立函数调用任务控制块初始化函数 OS_T

37、CBInit。 在初始化 OS_TCB的时候调用了用户自定 义的函数 OSTCBIni tHook和 OSTaskCreateHook 函数。两个函数都是扩展作用的。当 新建的任务块要插入表中时先要关中断,新任务的控制块总是插在 OSTCBList 表的开头。5就绪表每个就绪的任务都放在就绪表中,就绪表中有 2个变量 OSRdyGrp 和 OSRdyTbl 【】。 OSRdyGrp 中任务按优先级分组, 8个任务一组, 8位表示 8组任务中每组是否有进入就绪 态的任务。进入就绪态后,就绪表 OSRdyTbl 【】中相应元素的相应位置 1。因此,使任务进 入就绪态的程序为:OSRdyGrp |=

38、 OSMapTblprio>>3;OSRdyTblprio>>3 |= OSMapTblprio & 0x07; OSMapTbl是屏蔽字,将 0-7的下标转换成各自位置 1的 8位值通过优先级判定表 OSUnMapTbl 查找任务的优先级,即 OSUnMapTblOSRdyGrp×8 +OSUnMapTblOSRdyTblOSUnMapTblOSRdyGrp。得到优先级后,查任务控 制块优先级表 OSTCBPrioTbl 【】得到指向相应任务的任务控制块 OS_TCB。6任务调度任务级的调度是由 OSSched 完成, 中断级的调度是由函数 OSIn

39、tExt 完成的。 任务调度函 数将找出优先级最高的进入就绪态的任务,检查该任务是否是当前正在运行的任务,如果不是 才进行任务调度。为了实现任务的切换将该任务的控制块从任务控制块优先级表中取出并赋给 OSTCBHighRdy ,将统计切换次数的变量加 1来跟踪任务切换次数。 最后就可以使用宏调用 OS_TASK_SW完成实际上的任务切换任务切换:将被挂起任务的寄存器推入堆栈再将准备运行的任务的寄存器从栈中恢复到寄存器。 因此 UCOS 运行就绪态任务要做的就是恢复所有的 CPU 寄存器并运行中断返回指令。这里是 一段重点,为了实现任务切换,运行 OS_TASK_SW人为模仿了一次中断。在 AR

40、M 中由软 中断指令来实现上述操作。必须给汇编语言函数 OSCtxSw 提供中断向量。 OSCtxSw 除了 需要 OS_TCBHighRdy指向即将被挂起的任务, 还需让当前任务控制块 OSTCBCur 指向即 将被挂起的任务。 OSCtxSw 挂起了正在执行的任务而让 CPU 执行更重要的任务。7任务级的任务切换 OSCtxSwOSCtxSw 是宏调用通常含有软中断指令,切换是靠中断级代码完成的。 UCOS 将与实际处 理器相关的软件中断机制封装起来易于移植。8 给调度器上锁和开锁上锁函数 OSSchedlock ,调用该函数可以禁止任务调度,保持该任务对 CPU 的使用权, 不过中断还是

41、可以识别,中断服务也能得到,因为中断是开着的,中断和调度是两个意思。其 中变量 OSLockNesting 跟踪 OSSchedLock 函数被调用的次数所以允许嵌套函数。如果 OSLockNesting =0调度重新得到允许。9空闲任务UCOS-II 中总要建立一个空闲任务,主要是计数,然后有一个用户定义的函数 OSTaskIdleHook 。10统计任务除了空闲任务还有一个统计运行时间的任务 OSTaskStat ,它告诉用户应用程序使用了多少 CPU 时间,用百分比表示。11UCOS-II 中的中断中断服务子程序的编写:保存全部 CPU 寄存器;调用 OSIntEnter 或者 OSIn

42、tNesting 直接加 1;如果是中断的第一层,立即将堆栈指针保存到这个任务;如果需要重新允许中断, 必须清中断源,重新开中断;用户设定;调用脱离中断函数 OSIntExit ,标志着中断服务子程 序的结束。OSIntExit 是使中断离开的函数,当中断嵌套层数计数器和锁定嵌套计数器都为 0才重新 开始调度,然后选择一个优先级最高的任务。最后应该调用中断切换函数 OSIntCtxSw 而不 应该调用任务切换函数 OS_TASK_SW。 因为在中断之前已经把 CPU 寄存器存入到中断了的 任务堆栈中不需要再用。这部分也牵涉到后面的移植部分。12时钟节拍在调用 OSStart 之后应做的第一件事

43、情就是初始化定时器中断。 时钟节拍服务是通过在中断 服务子程序中调用 OSTimeTick 实现的。时钟节拍中断服务子程序:OSTickISR(void保存 CPU 寄存器的值调用 OSIntEnter 或是将 OSIntNesting 加 1如果 OSIntNesting 等于 1则将当前堆栈指针存入当前任务控制块的堆栈中调用 OSTimeTick清发出中断设备的中断重新允许中断调用 OSIntExit恢复处理器寄存器的值执行中断返回指令其中 OSTimeTick 通过 OSTimeTickHook 函数进行扩展。除此之外最大的任务就是给每 个用户任务控制块 OS_TCB中的时间延时项 OS

44、TCBDly 减 113UCOS-II 初始化OSInit 函数void OSInit (void#if OS_VERSION >= 204OSInitHookBegin(; /* Call port specific initialization code */#endifOS_InitMisc(; /* Initialize miscellaneous variables */OS_InitRdyList(; /* Initialize the Ready List */OS_InitTCBList(; /* Initialize the free list of OS_TCBs *

45、/OS_InitEventList(; /* Initialize the free list of OS_EVENTs */#if (OS_VERSION >= 251 && (OS_FLAG_EN > 0 && (OS_MAX_FLAGS > 0 OS_FlagInit(; /* Initialize the event flag structures */#endif#if (OS_MEM_EN > 0 && (OS_MAX_MEM_PART > 0OS_MemInit(; /* Initialize the

46、memory manager */#endif#if (OS_Q_EN > 0 && (OS_MAX_QS > 0OS_QInit(; /* Initialize the messagequeue structures */#endifOS_InitTaskIdle(; /* Create the IdleTask */#if OS_TASK_STAT_EN > 0OS_InitTaskStat(; /* Create the Statistic Task */#endif#if OS_VERSION >= 204OSInitHookEnd(; /* C

47、all port specific init. code */#endif初始化中会建立两个任务,并且初始化 5个空的数据结构缓冲区:任务控制缓冲池、事件控制 块缓冲池、消息队列缓冲池、标志控制块缓冲池、存储控制块缓冲池,缓冲池的容量在OS_CFG.H中定义14UCOS-II 的启动OSInit 初始化 UCOS-II ;通过调用 OSTaskCreate 或者 OSTaskCreateExt 创建至少一个任务;OSStart 开始多任务调度,永远不会返回;OSStart 的主要任务:从任务就绪表中找到用户建立的优先级最高任务的任务控制块;调用高优先级就绪任务启动函数 OSStartHighR

48、dy 。 OSStartHighRdy 函数与选择的微 处理器相关,也就是与移植相关,实际上,函数 OSStartHighRdy 是将任务栈中保存的值弹 回到 CPU 寄存器中, 然后执行一条中断返回指令,中断返回指令强制执行该任务代码, 该函数 永远不会返回到 OSStart软中断:中断不返回形式:void _swi(swi_num swi_name(arguments返回一个结果到 R0中 int _swi(swi_num swi_name(arguments;最多可以返回四个结果 R0-R3到一个结构struct type int a,b,c,d中 type(返回类型 _value_in

49、_regs(返回多个结果的修饰符 _swi(swi_numswi_name(arguments;比如在程序运行到调用 OS_TASK_SW(void函数时,就产生软件中断,然后就进入中断服 务子程序,按照什么指令走呢?恩,就按照下面这个代码,这个代码是将软件中断异常处理程 序挂接到内核的作用的,是在启动代码中实现的:LDR PC , SWI_AddrSWI_Addr DCD SoftwareInterrupt因此当产生软中断之后 PC 就跳到了 SoftwareInterrupt ,这时就算真正进入了软件异常中 断处理部分了,然后就是执行下面的汇编代码SoftwareInterruptLDR

50、SP, StackSvc ; 重新设置堆栈指针STMFD SP!, R0-R3, R12, LRMOV R1, SP ; R1指向参数存储位置MRS R3, SPSRTST R3, #T_bit ; 中断前是否是 Thumb 状态,判断 SPSR 的 T 位是 不是为零LDRNEH R0, LR,#-2 ; 不为零即 THUMB 指令集 : 取得 Thumb 状态 SWI 号BICNE R0, R0, #0xff00 ;在 THUMB 指令集中软中断功能号为 8位,所 以取低八位即为功能号LDREQ R0, LR,#-4 ; 为零即 ARM 指令集 : 取得 arm 状态 SWI 号 BICE

51、Q R0, R0, #0xFF000000 ;在 ARM 指令集中软中断功能号为 24位, 所以取低 6位即为功能号; r0 = SWI号, R1指向参数存储位置CMP R0, #1LDRLO PC, =OSIntCtxSw ; 功能号为 0到 OSIntCtxSw 执行中断任务切换 函数LDREQ PC, =_OSStartHighRdy ; SWI 0x01为第一次任务切换BL SWI_Exception ; 否则进入 c 编写的中断服务函数LDMFD SP!, R0-R3, R12, PCStackSvc DCD (SvcStackSpace + SVC_STACK_LEGTH * 4

52、- 4怎么进入 c 编写的中断服务子程序 SWI_Exception呢?通过下面的申明IMPORT SWI_Exception ; 软中断异常处理程序, 表示将 c 程序中的该函数挂 接到此段汇编代码中同样的道理EXPORT _OSStartHighRdyEXPORT OSIntCtxSw ; 中断退出时的入口,参见 startup.s 中的IRQ_HandlerEXPORT SoftwareInterrupt ; 软中断入口上面的申明是将该段汇编代码挂接到外面,因此在外部可以直接调用函数名继续看 OS_CPU_A.S的其他部分代码,就是两个软件异常中断处理函数 OSIntCtxSw 和 OSStarHighRdyOSIntCtxSw 代码是中断服务子程序使得更高优先级的任务进入就绪状态后,中断返回后需 要切换到该任务时调用的, 这是被切换的任务的 CPU 寄存器的值已经在响应中断后存入了堆栈 中,因此,这里不需要重复保存了直接切换任务即可,具体过程看代码OSIntCtxSw; 下面为保存任务环境;当响应软件异常中断

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论