第一章 uCOS II微小内核分析ppt课件.ppt
第1章 C/OS-II微小内核分析,本章导读,为了方便初学者学习嵌入式实时操作系统的基本原理,作者将C/OS-II V2.52由小到大裁减为几个只具备基本功能的微小内核。通过分析仅仅418行的操作系统最小内核,带领初学者尽快入门。作者建议在学习或教授本章的过程中,初学者或教师要边阅读原码,边画图,深刻理解过程,因为“过程比结论更重要!”。,目录,概述最小内核临界区与中断管理任务的结束信号量删除信号量,目录,概述最小内核临界区与中断管理任务的结束信号量删除信号量,1.1 概述,C/OS-II微小内核简介,C/OS-II 嵌入式实时操作系统的源代码可以分成三部分:与硬件无关的内核代码、与处理器有关的移植代码和用户配置文件。,1.1 概述,C/OS-II微小内核简介,内核代码,内核代码位于source目录下,提供了4个微小内核。它们分别位于sourceSOURCE1(包含建立任务和延时功能)、sourceSOURCE2(增加删除任务功能)、sourceSOURCE3(增加信号量文件)和sourceSOURCE4(增加删除信号量功能)。它们的功能依次增强,代码也依次增大。 以上代码并没有完全裁减到最小,还包含了一些参数校验代码等非必需代码,C/OS-II的代码裁减功能也同时保留,这些代码大约50多行。,1.1 概述,C/OS-II微小内核简介,移植代码,本书提供基于ARM的移植代码,位于arm目录下,分别为OS_CPU_C.C(移植代码C语言部分)、OS_CPU_a.S(移植代码汇编语言部分)、OS_CPU.H(移植代码头文件)和IRQ.INC(移植代码与芯片无关的中断处理接口程序)4个文件。,1.1 概述,C/OS-II微小内核简介,配置文件,配置文件是每个C/OS-II程序必备的文件,而且不同的程序一般不一样,但大小基本上相同。配置文件范例位于H目录下,分别为INCLUDES.H(内核需要的头文件,对于特定的移植,一般不需要改变)和OS_CFG.H(内核配置的头文件,一般需要根据程序的需求修改其常量的内容)文件。 一般来说,每个应用程序都有自己的配置文件拷贝,并很可能与范例不同。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSInit函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSStart函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTaskCreate函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTimeDly函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTimeTick函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSTaskDel函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSIntEnter函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSIntExit函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供禁止/允许中断函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemCreate函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemPend函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemPost函数。,1.1 概述,函数说明,C/OS-II 微小内核SOURCE4提供OSSemDel函数。,目录,概述最小内核临界区与中断管理任务的结束信号量删除信号量,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,基本概念,什么是任务,在实时多任务系统下运行的应用软件程序就是任务。在没有使用OS的前后台系统中,我们可以认为main函数以及通过main函数调用的全体函数为一个任务。 通常将“并行程序执行的基本逻辑单位”称之为“任务”,也就是说任务是可以被分割为独立的且可并行执行的基本逻辑单位程序。一个任务的程序是顺序执行的,而不同任务的程序却是并行执行的。任务必须包括相互“独立”和“并行”执行两个方面。,1.2 最小内核,基本概念,独立,独立具体指任务不能彼此直接调用,也不能直接进行数据交换。,void task0 (void) task1( );,void task1 (void) ,内核,通过调用执行任务,因此可以看成整体。,void task0 (void) 系统调用,通过内核进行任务调度和数据交换。,1.2 最小内核,基本概念,独立,独立具体指任务不能彼此直接调用,也不能直接进行数据交换。,1.2 最小内核,基本概念,并行执行,想象相互独立的任务各自拥有一个CPU,每个CPU各自执行各自的任务,此即任务的并行执行。但实际上CPU只有一个,我们认为操作系统为每个任务虚拟了一个CPU。,1.2 最小内核,基本概念,任务的状态,在C/OS-中,任务有5种状态,分别为睡眠状态、就绪状态、运行状态、等待状态和被中断状态。,睡眠状态,等待状态,就绪状态,被中断状态,运行状态,任务驻留在内存中尚未创建,任务已经准备好但尚未运行,任务掌握CPU的控制权,任务等待事件的而尚未发生,中断服务程序执行打断任务,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,案例分析,CPU,Task0,Task1,TaskIdle,P0.9,P0.10,在前后台系统中,一个“模块”可以调用另一个“模块”,因此各模块在执行时间上相互错开,且信息传递“同步”。,1.2 最小内核,案例分析,在操作系统中,程序设计就象记流水帐一样简单。,1.2 最小内核,案例分析,注意:在进入首个运行的任务之前要禁止产生任何受操作系统管理的中断,包括节拍定时器的中断。因为这类中断产生后操作系统会对任务进行扫描,并尝试进行任务切换,这将会导致程序出错,甚至引起系统崩溃。所以通常将硬件初始化函数放在首个运行任务开始的地方执行。,void Task0(void *pdata) pdata = pdata; TargetInit( ); while (1) ,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,任务控制块,C/OS-是通过任务控制块来管理任务的。任务控制块是一个基于链表的数据结构,任务控制块主要用于记录任务的堆栈栈顶指针、指向下一个任务控制块的指针、任务等待的延迟时间、任务的当前状态标志与任务的优先级别等一些与任务管理有关的属性。 当任务的CPU使用权被剥夺时,C/OS-用任务控制块来保存该任务的状态,从而保证任务重新获得CPU使用权时从断点处执行。,1.2 最小内核,任务控制块,typedef struct os_tcb OS_STK *OSTCBStkPtr; struct os_tcb *OSTCBNext; INT16U OSTCBDly; INT8U OSTCBStat; INT8U OSTCBPrio; INT8U OSTCBX; INT8U OSTCBY; INT8U OSTCBBitX; INT8U OSTCBBitY; OS_TCB;,任务控制块定义,任务控制块成员示意图,OSTCBStkPtr,OSTCBNext,OSTCBDly,OSTCBStat,OSTCBPrio,OSTCBX,OSTCBY,OSTCBBitX,OSTCBBitY,指向当前任务栈栈顶的指针。C/OS-允许每个任务有自己的栈,尤为重要的是,每个任务的堆栈的容量可以是任意的。,指向下一个任务控制块的指针。用于任务控制块OS_TCB的链接。,任务等待的延时时间变量。用于将任务挂起一段时间以等待某事件的发生,这种等待是有超时限制的。,任务的当前状态标志变量。其为0时,任务进入就绪态 。,任务优先级变量。变量值越小,任务的优先级越高。,1.2 最小内核,任务控制块,C/OS-最小内核定义了4个指针、 1个数组和1个指针数组 。,OSTCBCur指向“当前任务控制块”的指针;OSTCBFreeList“空任务控制块”链表的表头指针;OSTCBHighRdy 指向“将要运行最高优先级任务控制块”的指针;OSTCBList“已使用任务控制块”链表的表头指针;,1.2 最小内核,任务控制块,OSTCBPrioTbl任务控制块优先级表,专门用来存放指向各任务控制块的指针,并按任务的优先级别将这些指针存放在数组的各个元素里。,OSTCBPrioTbl指向各任务控制块的起始地址,即OSTCBStkPtr地址。,1.2 最小内核,任务控制块,OSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。,任务控制块初始状态,建立“单向空任务块链表”,链表头指针,存放“节点”地址,存放下一个节点地址,用户数据,表尾存放“空指针”,1.2 最小内核,任务控制块,OSTCBTbl任务控制块数组,所有的任务控制块都保存在这个数组中。,建立一个用户任务后的状态,系统空闲任务,用户任务,初始化空OS_TCB链表,OS_TCB *ptcb1; OS_TCB *ptcb2;,OSTCBList = (OS_TCB *)0; for(i=0;i(OS_LOWEST_PRIO+1);i+) OSTCBPrioTbli = (OS_TCB *)0;,ptcb1 = ,for (i = 0; i OSTCBNext = ptcb2; ptcb1+; ptcb2+; ,ptcb1-OSTCBNext = (OS_TCB *)0; OSTCBFreeList = ,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,任务就绪算法,所谓就绪状态是指任务准备运行但CPU没空,任务等待运行的状态。 任务就绪算法涉及“任务就绪表OSRdyTbl、映射表OSMapTbl、优先级判定表OSUnMapTbl以及变量OSRdyGrp和相关的任务优先级prio”,其中映射表OSMapTbl和优先级判定表OSUnMapTbl是2个常数表,用于查表算法。,优先级19的任务放入就绪表,OSRdyGrp|= OSMapTblPrio 3;OSRdyTblPrio 3 |= OSMapTblPrio ,就绪的任务在任务就绪表相应位置置1,1,优先级19的任务脱离就绪表,If (OSRdyTblPrio 3 ,&,=,0,&,=,0,该优先级任务脱离就绪表,优先级判定表,8线3线优先编码表,INT8U const OSUnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */*0 x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ;,优先级判定表,计算48在表中的对应值?,321 16 48,48O 30H,INT8U const OSUnMapTbl = /* 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f */*0 x00*/0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x10*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x20*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x30*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x40*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x50*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x60*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x70*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 x80*/ 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 x90*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xA0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xB0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xC0*/ 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,/*0 xD0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xE0*/ 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /*0 xF0*/ 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 ;,所在任务的Y值越小优先级越高,所在任务的X值越小优先级越高,由此可见最小的Y、X值所对应的任务就是进入就绪态优先级最高的的任务。,查找就绪态优先级最高的任务,y= OSUnMapTblOSRdyGrp;x= OSUnMapTblOSRdyTbly;Prio= (y 3) + x;,01101001B 69H,00110000B 30H,Y = 0,X = 4,Prio = 4,0,4,Y3,就绪表初始化,OSRdyGrp = 0 x00;,prdytbl = ,OS_RDY_TBL_SIZE = 2,OSPrioCur = 0; OSPrioHighRdy = 0; OSTCBHighRdy = (OS_TCB *)0; OSTCBCur = (OS_TCB *)0;,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,OS初始化,C/OS-II必须通过函数OSInit()初始化后才可以使用,该仅调用OS_InitMisc()、OS_InitRdyList()、OS_InitTCBList()和OS_InitTaskIdle() 4个函数。,OS_InMisc(),1.2 最小内核,OS初始化,static void OS_InitMisc (void) OSIntNesting = 0; OSRunning = FALSE;,0,FALSE,初始化为FLASE,表明OS没启动。调用OSStart()之后, OSRunning始终为TRUE。,0表示OS已经推出中断或所有中断嵌套已完成;1代表当前中断发生在执行任务;1表示发生嵌套。,1.2 最小内核,OS初始化,OS_InitTaskIdle()创建空闲任务函数比较重要,当所有用户任务都可能未处于就绪状态的时候,此时CPU将运行空闲任务,以防程序跑飞。,#define OS_IDLE_PRIO (OS_LOWEST_PRIO)#defineOS_STK_GROWTH 1#defineOS_TASK_IDLE_STK_SIZE 512,空闲任务优先级,堆栈由高地址往低地址生长,空闲任务堆栈大小,1.2 最小内核,OS初始化,void OS_TaskIdle (void *pdata) pdata = pdata; for (;) ,static void OS_InitTaskIdle (void) #if OS_STK_GROWTH = 1 (void)OSTaskCreate(OS_TaskIdle, (void *)0, #endif,创建空闲任务,空闲任务,OS初始化后状态,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,任务管理,C/OS-通过任务控制块对任务进行管理,创建任务实际上就是给任务代码分配一个任务控制块,通过调用函数OSTaskCreate()实现。 任务可以在多任务调度开始前建立,也可以在其它任务的执行过程中建立。在开始多任务调度之前,用户必须至少创建一个任务,但任务不能在中断服务程序(ISR)中建立。,任务创建函数OSTaskCreate()需要4个参数: task:指向任务代码的指针,即任务函数名,指向任务的代码地址; pdata:当任务开始执行时传递给任务的参数的指针; ptos:分配给任务的堆栈的栈顶指针; prio:分配给任务的优先级。,1.2 最小内核,任务管理,任务管理,创建任务流程图,INT8U OSTaskCreate (void (*task)(void *pd), void *pdata, OS_STK *ptos, INT8U prio) OS_STK *psp; INT8U err; OS_ENTER_CRITICAL(); if (OSTCBPrioTblprio = (OS_TCB *)0); OSTCBPrioTblprio = (OS_TCB *)1; OS_EXIT_CRITICAL(); psp = (OS_STK *)OSTaskStkInit(task, pdata, ptos, 0); err = OS_TCBInit(prio, psp, (OS_STK *)0, 0, 0, (void *)0, 0); if (err = OS_NO_ERR) if (OSRunning = TRUE); OS_Sched(); else OS_ENTER_CRITICAL(); OSTCBPrioTblprio = (OS_TCB *)0; OS_EXIT_CRITICAL(); return (err); return (OS_PRIO_EXIST); ,任务管理,创建任务函数,任务管理,通过分析创建任务OSTaskCreate()函数得知,OSTaskCreate()调用了OSTaskStkInit()任务堆栈初始化函数和OS_TCBInit()函数获得并初始化一个OS_TCB。,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,栈是限定仅在表尾进行插入与删除操作的线性表,表头端称为栈底,表尾端称为栈顶。 栈的修改是按照后进先出的原则,因此称为后进先出的线性表(简称LIFO结构)。插入元素的操作称为入栈,删除栈顶元素的操作称为出栈。,1.2 最小内核,任务堆栈初始化,1.2 最小内核,任务堆栈初始化,C/OS-使用结构常量OS_STK_GROWTH指定堆栈的生长方式:,OS_STK_GROWTH 1,OS_STK_GROWTH 0,ADS只支持“向下生长”的方式,且必须“满递减堆栈”,1.2 最小内核,任务堆栈初始化,堆栈初始化OSTaskStkInit()需要4个参数: task:任务开始执行的地址,在C语言中就是任务函数名; pdata:当任务开始执行时传递给任务的参数的指针,它应当保存到R0中; ptos:分配给任务的堆栈栈顶指针; otp:保留参数,目前没有使用。,函数,任务堆栈初始化,函数,TaskEntry,task,0,0,0,0,0,0,0,0,0,0,0,0,0 x1f,pdata,0,PC,LR,R12,R11,R10,R9,R8,R7,R6,R5,R4,R3,R2,OsEnterSum,CPSR,R0,R1,stk = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17,OS_STK *OSTaskStkInit(void (*task)(void *pd), void *pdata, OS_STK *ptos, INT16U opt) OS_STK *stk; extern void TaskEntry(void); opt = opt; stk = ptos; *stk = (OS_STK) TaskEntry; *-stk = (OS_STK) task; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = 0; *-stk = (unsigned int) pdata; *-stk = 0 x1f; *-stk = 0; return (stk);,ptos = &OSTaskIdleStkOS_TASK_IDLE_STK_SIZE-1,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,任务控制块函数OS_TCBInit()用于从任务控制块链表获取并初始化一个任务控制块,再将这个任务控制块链接到任务控制块链表的头部。 当建立任务时,系统就会将空任务控制块指针OSTCBFreeList指向的任务控制块分配给该任务,然后OSTCBFreeList的值便调整为指向链表中下一个空的任务块,OSTCBList总是指向最后建立的任务控制块。,1.2 最小内核,获取并初始化TCB,函数OS_TCBInit()虽然具有7个参数,但只有2个参数有效,其它参数预留以后升级使用: prio:任务的优先级; ptos:指向任务堆栈的栈顶指针,OSTaskStkPtr()任务堆栈初始化之后,最后返回栈顶指针psp。,1.2 最小内核,获取并初始化TCB,获取并初始化TCB,创建任务流程图,获取并初始化TCB,TCB初始化,ptos = &OSTaskIdleStk(OS_TASK_IDLE_STK_SIZE-1)-17,ptcb = OSTCBFreeList;OSTCBFreeList = ptcb-OSTCBNext;ptcb-OSTCBStkPtr = ptos;OSTCBPrioTblprio = ptcb;ptcb-OSTCBNext = OSTCBList;OSTCBList = ptcb;,假设建立一个最低优先级任务,创建空闲任务后状态,#define OS_LOWEST_PRIO 9,创建任务0后的状态,Prio 4,创建任务1后的状态,Prio 5,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,启动OS,多任务的启动是通过调用OSStart()函数实现的,启动C/OS-之前,用户至少要建立一个应用任务。,void OSStart (void) INT8U y; INT8U x; if (OSRunning = FALSE) y = OSUnMapTblOSRdyGrp; x = OSUnMapTblOSRdyTbly; OSPrioHighRdy = (INT8U)(y 3) + x); OSPrioCur = OSPrioHighRdy; OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy; OSTCBCur = OSTCBHighRdy; OSStartHighRdy(); ,OSStartHighRdy()永远将不会返回,它只执行一次。,EXPORT _OSStartHighRdyvoid OSStartHighRdy(void) _OSStartHighRdy();,1.2 最小内核,启动OS,OSStartHighRdy()函数位于OS_CPU_C文件中,其实际是通过调用_OSStartHighRdy()函数实现功能。,由于C语言不能直接调用汇编代码,必须经过“SWI软中断异常”实现。,_OSStartHighRdy MSR CPSR_c, #(NoInt | SYS32Mode) LDR R4, =OSRunning MOV R5, #1 STRB R5, R4 LDR R6, =OSTCBHighRdy LDR R6, R6,1.2 最小内核,启动OS,&OSTCBTbl1,&OSTCBTbl1,4,4,TRUE,FALSE,假设已建立空闲任务、Task1和Task0,优先级分别为9、5、4,R6=&OSTCBTbl1,1.2 最小内核,启动OS,&OSTCBTbl1,&OSTCBTbl1,4,4,TRUE,R6=&OSTCBTbl1,OSIntCtxSw_1 LDR R4, R6 ADD SP, R4, #68 LDR LR, SP, #-8 MSR CPSR_c, #(NoInt | SVC32Mode) MOV SP, R4 LDMFD SP!, R4, R5 LDR R3, =OsEnterSum STR R4, R3 MSR SPSR_cxsf, R5 LDMFD SP!, R0-R12, LR, PC ,R4=OSTCBStkPtr,栈顶,OSTCBStkPtr指向栈顶位置0 x04,Task0,0 x48,R4=OSEnterSumR5=CPSR,0 x04,CPSR,0 x0C,TaskEntry,0,0,0,0,CPSR,再通过执行EXPORT TaskEntryTaskEntry BX R14程序跳到Task0运行,启动OS,在调用OSStart()之后首先启动新任务Task0,然后执行目标板初始化函数TargetInit(),接着初始化VIC中断向量控制器和Timer0定时器并产生周期性的中断。,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,TargetInit 初始化,C/OS-要求在多任务环境启动之前不允许产生中断,所以通常会在第一个执行的任务中调用函数TargetInit()初始化中断系统和能够产生中断的外设。 因为这些代码都与中断有关,所以必须禁止中断以保证程序执行正确。,void TargetInit(void) OS_ENTER_CRITICAL(); VICInit(); Timer0Init(); OS_EXIT_CRITICAL();,1.2 最小内核,TargetInit 初始化,TargetInit()目标板初始化包括其它初始化代码、VICInit()初始化、Timer0Init()初始化与其它外设初始化。,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,时间管理,任务可以通过调用系统服务函数OSTimeDly()申请一段时间(即等待时间事件)。 调用该函数会使操作系统进行一次任务调度,并且执行下一个处于就绪态优先级最高的任务。 函数OSTimeDly()仅有一个参数ticks表明任务需要延时的时间,以系统时钟节拍为单位。,void OSTimeDly (INT16U ticks) if (ticks 0) OS_ENTER_CRITICAL(); if (OSRdyTblOSTCBCur-OSTCBY ,1.2 最小内核,时间管理,1.2 最小内核,时间管理,如果ticks为0,则表明用户不想延时任务,函数会立即返回到调用者;如果ticks非0,则将当前任务从就绪表中删除。与此同时将ticks延时节拍数保存到当前任务的OS_TCB中,然后进行一次任务调度,并且执行下一个优先级最高的处于就绪态的任务。,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,任务调度,C/OS-内核采用了“可剥夺型”任务调度算法,C/OS-总是运行处于就绪态中优先级最高的任务,具体是通过调度器(Scheduler)实现。 任务级的任务调度由OS_Sched()函数完成,而中断级的任务调度由OSIntExt()函数完成。,1.2 最小内核,任务调度,void OS_Sched (void) INT8U y; OS_ENTER_CRITICAL(); if (OSIntNesting = 0) y = OSUnMapTblOSRdyGrp; OSPrioHighRdy = (INT8U)(y 3) + OSUnMapTblOSRdyTbly); if (OSPrioHighRdy != OSPrioCur) OSTCBHighRdy = OSTCBPrioTblOSPrioHighRdy; OS_TASK_SW(); OS_EXIT_CRITICAL();,Task0从就绪表删除后的任务调度,1,0,5,4,&OSTCBTbl1,&OSTCBTbl2,5,&OSTCBTbl2,当前还是运行Task0,&OSTCBTbl2,&OSTCBTbl1,&OSTCBTbl0,1.2 最小内核,基本概念案例分析任务控制块任务就绪算法OS初始化任务管理任务堆栈初始化,获取并初始化TCB启动OSTargetInit 初始化时间管理任务调度SWI软件中断异常任务级的任务调度小结,1.2 最小内核,SWI软件中断异常,由于C语言程序不能直接调用汇编程序,因此必须制定一个调用接口规范。为了使底层接口函数与处理器状态无关,同时在任务调用相应的函数时也不需要知道该函数的确切位置,那么解决上述问题的方法之一就是使用ARM7的软中断SWI作为底层接口,使用不同的功能号区分不同的函数。,1.2 最小内核,SWI软件中断异常,ADS编译器规定,用户可以使用关键字_swi作为前缀来声明一个利用软件中断的调用,那么就在调用这个函数的地方插入一条SWI指令,并且可以指定功能号。 关键字_swi后面的括号中的字段叫作软件中断功能编号,即汇编指令swi中的立即数,系统可以根据这个编号在软件中断管理程序中确定应该执行的程序段。,_swi(功能号)返回值 名称(列表),1.2 最小内核,SWI软件中断异常,为了进一步提高效率,最小内核没有使用功能编号,而是使用第一个参数的数值(保存在R0中)来区分不同的功能。,_swi(0 x00) void OsSwiHandle1(int Handle);#define OS_TASK_SW() OsSwiHandle1(0) #define _OSStartHighRdy() OsSwiHandle1(3) #define OS_ENTER_CRITICAL() OsSwiHandle1(1)#define OS_EXIT_CRITICAL()OsSwiHandle1(2),MOVR0, #0SWI0,编译器编译成汇编指令,&OSTCBTbl2,&OSTCBTbl1,5,4,TRUE,假设优先级为4的Task0挂起,那么当前最高优先级5的Task1将运行,此间将进行任务切换。,任务级的任务调度,TASK_SW MRS R3, SPSR MOV R2, LR MSR CPSR_c, #(NoInt | SYS32Mode) STMFD SP!, R2 STMFD SP!, R0-R12, LR B OSIntCtxSw_0,&OSTCBTbl2,CPSR,PC+4,SoftwareInterrupt,TASK_SW,+0 x48,R3=SPSR_svc,R2=PC+4,PC+4,+0 x44,LR,R12,R11,R1,R0,+0 x0C,&OSTCBTbl2,&OSTCBTbl1,5,4,TRUE,假设优先级为4的Task0挂起,那么当前最高优先级5的Task1将运行,此间将进行任务切换。,任务级的任务调度,&OSTCBTbl2,CPSR,PC+4,PC+4,LR,R12,R11,R1,R0,OSIntCtxSw_0 LDR R1, =OsEnterSum LDR R2, R1 STMFD SP!, R2, R3 LDR R1, =OSTCBCur LDR R1, R1 STR