《uCOS-II多核移植.docx》由会员分享,可在线阅读,更多相关《uCOS-II多核移植.docx(8页珍藏版)》请在金锄头文库上搜索。
1、uC/OS-II是源码开放、可固化、可移植、可裁剪、可剥夺的实时多任务OS内核,适用于任务多、对实时性要求较高的场合。uC/OS-II适合小型系统,具有执行效率高、占用空间小、实时性优良和可扩展性等特点,最小内核可编译至2K。uC/OS-II内核提供任务调度与管理、时间管理、任务间同步与通信、内存管理和中断服务等功能。所谓RTOS移植,就是使一个实时内核能在某个微处理器或微控制器上运行。大部分的uC/OS-II代码试用C写的,但仍需要用C和ASM写一些与处理器相关的代码,这是因为uC/OS-II在读写处理器寄存器时只能通过ASM实现。要是uC/OS-II正常运行,处理器必须满足一定的条件: 处
2、理器的C编译器能产生可重入代码; 用C语言就可以打开和关闭中断; 处理器支持中断,并能产生定时中断; 处理器支持能够容纳一定量数据的硬件堆栈; 处理器有将SP和其他CPU reg读出和存储到堆栈或内存中的指令;uC/OS-II移植工作主要包括以下三个方面的内容:(1) 修改与处理器核编译器相关的代码:主要在includes.h中,修改数据类型定义说明,OS_ENTER_CRITICAL()、OS_EXIT_CRITICAL()和堆栈增长方向定义OS_STK_GROWTH。(2) 用C语言编写10个移植相关的函数:主要在OS_CPU_C.C中,包括堆栈初始化OSTaskStkInit()和各种回
3、调函数。(3) 编写4个汇编语言函数:主要在OS_CPU_A.ASM中,包括: _OSTickISR/时钟中断处理函数 _OSIntCtxSW/从ISR中调用的任务切换函数 _OSCtxSW/从任务中调用的任务切换函数 _OSStartHighRdy/启动最高优先级的任务uC/OS-II移植的关键问题:(1) 临界区访问:uC/OS-II需要先禁止中断再访问代码临界段,并且在访问完毕后重新允许中断,这就使得uC/OS-II能够保护临界段代码免受多任务或ISR的破坏。uC/OS-II定义了OS_ENTER_CRITICAL()(禁止中断)和OS_EXIT_CRITICAL()(允许中断),有3种
4、实现方法。(2) 系统引导:uC/OS-II引导分为两部分:一是处理器相关的引导,包括初始化处理器状态、数据段、SP等,一是OS相关的引导,包括系统各个数据结构的初始化、初始任务的创建等,最终执行到_OSStartHighRdy开启多任务执行。 与uC/OS-II引导相关的几个移植函数是OSStartHighRdy、OSTaskStkInit和OSTickISR,其中OSTaskStkInit负责初始化任务堆栈,初始化的堆栈数据会在任务第一次被调用执行时装入相应的寄存器。在OSStartHighRdy前执行的所有代码都是为多任务启动做准备,由OSStartHighRdy开始才真正的启动多任务环
5、境,OSStartHighRdy执行后不会返回,而是直接切换到最高优先级任务运行。(3) 堆栈切换和管理:堆栈切换伴随任务切换而发生,uC/OS-II中主要有三个地方发生堆栈切换: 在OSStartHighRdy启动多任务时,将任务堆栈初始内容弹出堆栈; 在OSIntCtxSW中切换,在中断返回时如果最高优先级的任务发生了改变,就需要调用这个函数切换任务; 在OSCtxSW中切换,这是主动调用OSSched等函数触发的任务切换,在任务中以软中断方式触发该调用; 影响堆栈切换的另一个因素是中断嵌套,uC/OS-II中的中断嵌套通过全局变量OSIntNesting控制。当进入中断时,只有最外层的中
6、断(也就是第一次进入的中断)需要将当前的SP保存在TCB中;相应的,只有最外层的中断返回时才需要进行可能的堆栈切换。uC/OS-II多NiosII软核扩展-uC/OS-MC在多NiosII软核上扩展的uC/OS-II称为uC/OS-MC,uC/OS-MC期望能够实现其对于多核处理器的支持,实现传统的CMP架构,即运行一个RTOS动态的调度任务到各个CPU核上运行,保证任务的优先级和CPU核的负载平衡。对uC/OS-MC,需要保证有最高优先级的N个任务始终运行,N代表系统中NiosII核的数量,这是对任务优先级的保证;还要保证处理器的负载均衡,任意一个处理器核如果运行空转任务,说明系统中不存在就
7、绪运行的任务。uC/OS-MC移植设计难点一是多核处理器的引导,怎样将多核处理器启动,完成各个处理器核的初始化,同时还要保证各个处理器核间的同步,以使其能够在几乎同一时间进入任务调度;二是多核处理器的互斥和同步,仅仅禁止某个核的中断处理不能保证临界区的互斥访问,必须采用新的方式实现多核处理器对于临界区的互斥核同步访问;三是任务调度,必须在多核处理器上设计出一个性能良好的调度算法,一方面保证最高优先级任务的运行,另一方面要是各个处理器核上的任务切换次数尽可能的少;四是时钟中断处理,多核处理器上的每个处理器核都需要一个独立的时钟中断来提供“心跳”。(1) 多核处理器的引导在多核处理器的引导过程中,
8、处理器内核间是不平等的,有主次之分。系统启动后,PM(Primary CPU)首先初始化自身,同时完成一些全局化的初始化过程,如数据段清零、MMU初始化等,然后跳转到C代码的函数中执行,此时才由PM逐个启动PE(Processor Element),各个PE在初始化自身后需要和PM同步,等待PM发出启动信号量后统一进入任务调度。对于PM和各个PE,自身的初始化是每个处理器核都必须执行的,而全局和一些系统的初始化工作则只由PM在启动时执行一次。(2) 多核上的任务调度每个任务都能在任意的CPU上运行,这就需要在任务堆栈中保存足够的信息以使它能够在任意一个CPU上恢复运行。空转任务(IDLE TA
9、SK)作为一个特殊的任务不能够被调度到别的处理器上运行,实际上每个处理器上都运行了一个相同的空转任务。RTOS在多核处理器上的任务调度实际上是一个处理器核和任务双向选择的过程:一方面要保证最高优先级任务的运行,另一方面要保证全局的任务切换次数最少,即原来运行在该处理器核上的任务尽可能不发生切换,这是任务调度算法需要考虑的两个关键问题。uC/OS-MC按优先级排序,最高优先级的N个任务都有可能同时运行。 任务切换时机在uC/OS-MC中,与任务调度相关的4个变量OSPrioCur、OSPrioHighRdy、OSTCBCur、OSTCBHighRdy都扩展为长度为N的数组。注意:“最高优先级任务
10、”的含义发生了变化,在单一处理器核上运行的任务也许不是全局的最高优先级,但在所有处理器核上运行的N个任务一定是所有任务中具有最高优先级的N个任务。每个处理器核在两个地方进行任务切换:一是时钟中断返回,通过调用OSIntExit检查是否需要进行任务切换;一是处理器间中断,这是任务主动触发的任务调度。在多核处理器环境下,某一个任务上运行的任务调度的效果可能是全局性的,也就是说PE1上运行的任务调度可能会影响到PE0、PE2、PE3上运行的任务,这就需要通过处理器间中断来处理。 调度算法多核处理器上的任务调度算法有两个目标:一是保证最高优先级的N个任务运行,二是保证全局的任务切换次数最少,即使原来运
11、行在该处理器上的任务尽可能的不发生切换。uC/OS-MC任务调度分两个步骤:首先从当前就绪的任务队列中选择出优先级排在前N位的任务,然后把这N个任务调度到N个处理器核上。任务调度流程图如下图所示:(3) 多核处理器间的通信uC/OS-MC主要使用三种核间通信机制: 多核处理器间的中断; 多核处理器间的同步; 多核处理器间的互斥,主要通过硬件自旋锁实现;在多核处理器中,禁止本处理器核的中断只能保证运行在该处理器核上的任务间的互斥,而运行在别的处理器核上的任务可能同时进入临界区访问。这样,不仅需要禁止本处理器核上的中断,还需要处理器核间的互斥机制来保证对于临界区的访问。uC/OS-MC中,封装了对
12、于多核处理器间的自旋锁操作:wait_cmp_lock()和release_cmp_lock()。在访问多核处理器间需要互斥访问的数据之前,需要先调用wait_cmp_lock()来获得处理器核间的互斥锁,访问完毕后再通过release_cmp_lock()释放互斥锁。注意:需要同时调用OS_ENTER_CRITICAL()和wait_cmp_lock()时,要先调用OS_ENTER_CRITICAL()禁止中断,再调用wait_cmp_lock()获得处理器间的互斥锁。(4) 时钟中断处理对uC/OS-MC,外部中断的分配和处理大部分由硬件支持,而作为RTOS“心跳”的时钟中断则由每个处理器核内部提供。系统初始化时,每个处理器核都需要初始化其内部的定时器,配置成频率相同的时钟中断;另外,不同的处理器核必须使用不同的时钟中断源。uC/OS-II中,时钟中断作为外部中断由外部时钟提供;而uC/OS-MC中,每个处理器核上都需要一个独立的时钟中断来驱动该处理器核上的任务切换,改由每个处理器核上的内部时钟提供时钟中断。在SOPC Builder中,可为每个NiosII软核配置一个Internal Timer。