250 likes | 777 Views
Nucleus 嵌入式操作系统. 主要内容 :. 1 、 嵌入式系统概述 2 、 Nucleus 嵌入式操作系统介绍 3 、 Nucleus 提供的主要服务 4 、 Rftest 中的操作系统代码分析. 与普通的操作系统相比,它的主要特点有: ⑴、微型化。嵌入式系统芯片内部存储器的容量通常不是很大 (1MB) ,加上电源容量较小,以及外部设备的多样化,因而并不允许嵌入式操作系统占用很多资源。 ⑵、实时性。由于对嵌入式实时操作系统的共同要求是系统能够快速响应事件,具有较强的实时性,所以嵌入式实时操作系统的内核都是可剥夺的。
E N D
主要内容: 1、嵌入式系统概述 2、Nucleus嵌入式操作系统介绍 3、Nucleus提供的主要服务 4、Rftest中的操作系统代码分析
与普通的操作系统相比,它的主要特点有: ⑴、微型化。嵌入式系统芯片内部存储器的容量通常不是很大(1MB),加上电源容量较小,以及外部设备的多样化,因而并不允许嵌入式操作系统占用很多资源。 ⑵、实时性。由于对嵌入式实时操作系统的共同要求是系统能够快速响应事件,具有较强的实时性,所以嵌入式实时操作系统的内核都是可剥夺的。 ⑶、可裁剪性。嵌入式操作系统运行的硬件平台多样化,所以要求嵌入式系统提供的各个功能模块可以让用户选择使用。 ⑷、高可靠性。 ⑸、易移植性。为了适应各种各样的硬件平台,嵌入式系统可在不做大量修改的情况下能稳定地运行于不同的平台。 • 什么是嵌入式实时操作系统?
提供的服务主要包括进程管理、存储管理、文件管理、设备管理等提供的服务主要包括进程管理、存储管理、文件管理、设备管理等 嵌入式操作系统的地位: 微内核: 常见的嵌入式实时操作系统有:μc/OS-Ⅱ,RTLinux,Nucleus,ARM-Linux,KURT(源码开放) VxWorks,QNX,pSOS,WindowsCE(商业软件) 返回
Nucleus嵌入式操作系统 Nucleus实时操作系统是Accelerater Technology公司开发的嵌入式RTOS产品。只需一次性购买Licenses就可以获得源码。它的 核心是一个实时多任务内核——Nucleus PLUS,性能介于μc/OS-Ⅱ和VxWorks之间。 • Nucleus PLUS 是为实时嵌入式应用而设计的一个抢先式多任务操作系统内核,其95%的代码是用ANSI C写成的,因此非常便于移植并能够支持大多数类型的处理器。从实现角度来看,Nucleus PLUS 是一组C函数库,应用程序代码与核心函数库连接在一起,生成一个目标代码,下载到目标板的RAM中或直接烧录到目标板的ROM中执行。在典型的目标环境中,Nucleus PLUS 核心代码区一般不超过20K字节大小。 • Nucleus PLUS 采用了软件组件的方法。每个组件具有单一而明确的目的,通常由几个C及汇编语言模块构成,提供清晰的外部接口,对组件的引用就是通过这些接口完成的。除了少数一些特殊情况外,不允许从外部对组件内的全局进行访问。 • Nucleus PLUS 的组件包括任务控制、内存管理、任务间通信、任务的同步与互斥、中断管理、定时器及I/O驱动等。
缺点:实时性不够,定时中断管理不可靠,I/O管理太简单,操作系统调试工具很少等等。缺点:实时性不够,定时中断管理不可靠,I/O管理太简单,操作系统调试工具很少等等。 Nucleus plus使用了软件组件方法学,每个组件有单一的清晰的目的。软件组件往往包括几个C或汇编程序,每个组件软件提供定义非常好的外部接口,通过使用外部接口来利用组件。 组件包含的文件或文件名约定如下: Nucleus plus的组件结构:
Nucleus plus中使用的数据类型: UNSIGNED 32位无符号整数(UNSIGNED LONG) SIGNED 32位有符号整数(Long) OPTION 最小的易于使用的整数(UNSIGNED CHAR) DATA_ELEMENT 与OPTION相同 UNSIGNED CHAR 8位无符号的字符 CHAR 8位的字符 STATUS 与目标C编译器的有符号整数INT类型等价 INT 整数数据类型,具有WORD的大小 UNSIGNED_PTR 指向一个UNSIGNED指针 BYTE_PTR 指向一个UNSIGNED CHAR指针 Nucleus plus的组件有: 通用服务组件(CS)、初始化组件(IN)、线程调度组件(TC)、 定时组件(TM)、邮箱组件(MB)、队列组件(QM)、管道组件(PI) 信号量组件(SM)、事件组件(EV)、存储分配组件(PM)、 动态存储组件(DM)、输入输出组件(IO)等 返回
Nucleus Plus中的初始化 三个层次的初始化 Int_initialize (基于目标系统硬件的初始化) Inc_initialize (Nucleus组件的初始化) Application_initialize (应用环境的初始化)
任务就是目的明确的半独立程序段。大多数现代实时应用都要求多任务。另外,这些任务的重要等级经常变化。管理这些竞争、实时任务的运行是Nucleus PLUS的主要目的。 Nucleus Plus的任务 任务控制块 Nucleus对任务的调度需要任务控制块(TCB),任务控制块是一种结构体,该结构体中包含了任务的各种信息。 任务堆栈 Nucleus的任务堆栈用来保存任务切换时的上下文,包括任务切换时的PC、各寄存器以及堆栈的当前值,此外任务堆栈还用来存储任务运行时的临时变量。 任务状态 每个任务都有五种状态:运行、就绪、挂起、终止、完成
任务优先级在任务创建期间定义,范围0~255,用来定义Nulceus PLUS任务的重要性,数字越小优先级越高。在任务运行中可以动态设置优先级。Nucleus PLUS在低优先级任务前运行更高优先级任务。同等优先级任务按照进入就绪状态的先后顺序运行。 任务的优先级 不同优先级任务调度 采用任务抢占模式。就是当更高优先级的任务就绪时挂起低优先级的任务的行为。任务抢占可以被设置为禁止,那么这时任务会一直运行到完成直到任务主动挂起或者使能抢占。 相同优先级的任务调度 1、主动放弃模式。在任务中调用NU_Relinquish()。 2、采用时间片模式。当任务创建时设置的时间片(Time Slices)到来时,其他的所有就绪且在同一优先级的任务获得CPU而运行。
Nucleus是以链表来管理已创建的任务的TCB的。而且Nucleus把每个就绪任务以任务的优先级高低为顺序放在就绪任务表中,在调度的时候它可以从就绪任务表中找出就绪的优先级最高的任务,然后通过链表访问它的TCB,从而运行该任务。 任务的切换过程 任务的调度 任务切换的实质是断点数据的切换,断点数据的切换也就是处理器堆栈指针的切换。
主要的任务函数介绍 STATUS NU_Create_Task ( 创建一个任务 NU_TASK *task, CHAR *name, VOID (*task_entry)(UNSIGNED, VOID *), UNSIGNED argc, VOID *argv, VOID *stack_address, UNSIGNED stack_size, OPTION priority, UNSIGNED time_slice, OPTION preempt, OPTION auto_start) 指向一个任务控制块 指向一个任务的任务名 指向任务函数的入口地址 传递初始化信息到任务 指向任务堆栈的地址 任务堆栈的大小 任务的优先级 时间片(1 – 4,294,967,293) 任务的抢占模式 任务的初始启动配置 无条件挂起一个任务 STATUS NU_Suspend_Task (NU_TASK *task) 恢复一个任务 STATUS NU_Resume_Task (NU_TASK *task) 挂起一个任务,直到time ticks到来 STATUS NU_Sleep (UNSIGNED ticks) VOID NU_Relinquish (VOID) 主动放弃时间片以便同优先级的就绪任务运行 STATUS NU_Delete_Task(NU_TASK *task) 删除一个已创建的任务
任务需要一定的机制来实现与其他任务的通信。Nucleus PLUS为通信目的提供邮箱(mailbox),队列(queues),管道(pipes)。邮箱,队列,管道是独立的公共设备。任务之间和其他系统设备之间的联系由应用程序确定。这些通信设备之间主要的差别是数据通信的类型。 Nucleus Plus任务间的通信 邮箱(mailbox) 邮箱为传输简单数据提供低消耗方案。每个邮箱可以保持4个32位字 大小的单一消息。消息以(数)值方式发送和接受。 任务可以在邮箱内挂起,其原因有: ⒈试图从空邮箱接受消息的任务; ⒉试图向满邮箱发送消息的任务; 多个任务可以在一个邮箱上挂起,挂起顺序有两种:一是按照优先级 顺序挂起,二是按照FIFO的形式挂起。
主要的邮箱函数 STATUS NU_Create_Mailbox( //创建一个邮箱 NU_MAILBOX *mailbox, //指向邮箱的控制块 CHAR *name, //指向邮箱名 OPTION suspend_type) //多任务在邮箱的挂起方式 STATUS NU_Send_To_Mailbox( //发送消息到邮箱 NU_MAILBOX *mailbox, //指向邮箱的控制块 VOID *message, //要发送的消息指针 UNSIGNED suspend) //任务挂起类型 STATUS NU_Receive_From_Mailbox( //从邮箱中接收消息 NU_MAILBOX *mailbox, //指向邮箱的控制块 VOID *message, //接收消息的指针 UNSIGNED suspend) //任务挂起类型 STATUS NU_Delete_Mailbox( //删除一个邮箱 NU_MAILBOX *mailbox) //指向邮箱的控制块
队列(queues) 队列提供了传输多个消息的机制。队列传递消息类型是Unsigned(即32bit字),队列支持定长和不定长消息(支持不定长消息,需要一个32位的额外附加信息),消息可以放在对列的前端或队列的后端。 任务能在队列内因为几种原因挂起。一个试图从空队列中接受消息的任务可以被挂起。同样,一个试图发送消息至满队列的任务可以被挂起。 多任务能在一个队列上挂起。依靠创建队列的任务可以以FIFO或是优先级次序被挂起。 STATUS NU_Create_Queue( //创建一个队列 NU_QUEUE *queue, //指向队列控制块 char *name, //指向队列名 VOID *start_address, //队列的起始地址 UNSIGNED queue_size, //队列的大小 OPTION message_type, //队列中消息的类型(定长和不定长) UNSIGNED message_size, //消息的大小 OPTION suspend_type) //多个任务在队列上的挂起方式
STATUS NU_Send_To_Queue( //发送消息到队列的末尾 NU_QUEUE *queue, ///指向队列的控制块 VOID *message, //指向要发送的消息 UNSIGNED size, //发送消息的大小 UNSIGNED suspend) //任务的挂起类型 STATUS NU_Send_To_Front_Of_Queue( //发送消息到队列的开头 NU_QUEUE *queue, VOID *message, UNSIGNED size, UNSIGNED suspend) STATUS NU_Receive_From_Queue( //从队列的前端取消息 NU_QUEUE *queue, //指向队列控制块 VOID *message, //接收消息的指针 UNSIGNED size, //消息的大小 UNSIGNED *actual_size, //接收到的实际消息大小 UNSIGNED suspend) //任务的挂起类型 STATUS NU_Delete_Queue(NU_QUEUE *queue) //删除一个队列
为了实现任务之间的合作和无冲突的运行,在有关联的任务之间必须建立一些制约关系。这些关系有两种:为了实现任务之间的合作和无冲突的运行,在有关联的任务之间必须建立一些制约关系。这些关系有两种: 1、直接制约关系,源于任务之间的合作; 2、间接制约关系,源于对资源的共享; Nucleus Plus任务间的同步 因此任务之间的这种合作运 行机制就叫同步。 Nucleus PLUS提供 信号量(semaphores), 事件集(event groups)和 信号(signals)解决信号同步问题。 信号量(semaphores) 信号量提供了一种机制来控制操作系统临界资源的分配。它的两个基本操作是obtain和release,obtain为减少信号量,release为增加信号量。信号量最常见的应用就是资源分配。当多个任务试图obtain信号量时会挂起,挂起方式有优先级和FIFO。
互斥信号量带来的问题:优先级反转 互斥信号量就是一个初始值设置为1的信号量,它只允许一个任务独享其资源。 优先级反转就是低优先级的任务先于高优先级的任务运行的现象。一个优先级反转现象如下图所示: 解决办法: 提高任务C的优先级,使其运行不被打断。 信号量带来的另一个问题是死锁,解决方法是任务只允许一次占用一个信号量。
主要的信号量函数 STATUS NU_Create_Semaphore( //创建一个信号量 NU_SEMAPHORE *semaphore, //指向信号量的结构体 CHAR *name, //信号量的名字 UNSIGNED initial_count, //信号量的初始值 OPTION suspend_type) //多任务访问信号量的挂起方式 STATUS NU_Obtain_Semaphore( //获得信号量 NU_SEMAPHORE *semaphore, //指向信号量的结构体 UNSIGNED suspend) //任务的挂起类型 STATUS NU_Release_Semaphore(NU_SEMAPHORE *semaphore) //释放信号量 事件组(event groups) 事件组提供一个机制来描述一个指定系统事件的发生。每个事件组有32个事件标志,每个事件标志在事件集中占一个bit。每个事件标志可以通过逻辑与/或结合来设置和清除。 一个任务企图接收一个没有出现的事件标志组合会让该任务挂起。
主要的事件组函数 STATUS NU_Create_Event_Group( //创建一个事件组 NU_EVENT_GROUP *group, //指向事件组的控制块 CHAR *name) //事件组的名字 创建后事件组中的每个事件标志都被清0。 STATUS NU_Set_Events( //设置事件标志 NU_EVENT_GROUP *group, //指向事件组的控制块 UNSIGNED event_flags, //设置的事件标志 OPTION operation) //逻辑操作类型(And/Or) 例子:(逻辑操作Or和And的区别) NU_SET_EVENTS(&Event0,0x0001,NU_OR) 0x0001|0x0010=0x0011 NU_SET_EVENTS(&Event0,0x0010,NU_OR) 事件标志1和2被置位 NU_SET_EVENTS(&Event0,0x0001,NU_AND) 0x0001&0x0010=0x0000 NU_SET_EVENTS(&Event0,0x0010,NU_AND) 事件标志1和2被清除
STATUS NU_Retrieve_Events( //获得事件标志组合 NU_EVENT_GROUP *group, //指向事件组控制块 UNSIGNED requested_events, //请求的事件标志 OPTION operation, //逻辑操作类型 UNSIGNED *retrieved_events, //接收到的事件标志组合 UNSIGNED suspend) //任务的挂起类型 逻辑操作类型包括:NU_AND,NU_AND_CONSUME, NU_OR,NU_OR_CONSUME. 信号(signals)与事件组类似,只是信号是异步的,而事件组是同步的。 对于事件组而言,当一个任务在获得事件标志组合时,如果获得的事件标志与请求的事件标志不匹配则任务挂起,直到匹配的事件标志出现。 而对于信号而言,一个任务的开始处定义了一个信号处理函数,在指定的信号没出现时任务可以执行其它操作,当信号到来时,任务才转去执行相应的信号处理函数,这就有点类似于中断处理函数。
Nucleus Plus的中断 中断是为外部和内部事件提供立即响应的机制。当中断发生时处理器立即挂起当前运行的程序,并且转移到适当的中断服务子程序(ISR)。 • Nucleus的中断分为管理的中断和非管理的中断。 • 非管理中断类似以前常见的中断服务程序,它不需要操作系统管理,直接将中断服务程序挂到中断向量表上。它不能使用绝大多数的Nucleus系统调用,因为这很可能破坏操作系统某些保护的数据结构。非管理的中断适合于那些比较频繁的中断,需要由用户自己写代码保存中断的上下文。 • 管理的中断需要向操作系统注册该中断向量。它又分为低级中断(LISR)和高级中断(HISR)。 • 低级中断服务子程序(LISR)和正常的ISR一样运行,包括使用当前堆栈。Nucleus PLUS在调用LISR之前保存上下文,在LISR返回之后恢复上下文。LISR主要完成硬件中断处理,及激活HISR。
高级中断支持动态创建和删除。每个HISR由它自己的堆栈空间和控制块。每个的内存由应用程序提供。当然,HISR必须在LISR激活之前被创建。 • 一旦HISR有自己的堆栈和控制块,如果它试图进入一个已经被访问Nucleus PLUS数据结构时就会被临时封锁。 • HISR的调度类似于任务,具有优先级,允许访问大多数的Nucleus PLUS服务,除了自挂起服务(self-suspension)。 • HISR有三个优先等级。在一个低优先级的HISR处理期间,如果一个更高优先等级的HISR被激活,低优先级的HISR以与任务抢先方式相同的方式抢先。相同优先级的HISR以他们最初激活的顺序运行。 主要的中断函数 VOID *NU_Setup_Vector(INT vector, VOID *new) //设置中断向量表,此项服务使用用户自定义中断服务子程序代替vector指定的中断向量。服务返回先前中断向量内容。该函数主要用于非管理的中断,且用户提供的ISR需用汇编语言编写。
STATUS NU_Register_LISR( //注册一个低级中断 INT vector, //中断向量号 VOID(*lisr_entry)(INT), //ISR函数入口地址 VOID (**old_lisr)(INT)) //旧的ISR函数入口地址 STATUS NU_Create_HISR( NU_HISR *hisr, //指向高级中断控制块 CHAR *name, //高级中断的名称 VOID (*hisr_entry)(VOID), //高级中断处理程序的入口地址 OPTION priority, //高级中断优先级 VOID *stack_pointer, //高级中断的堆栈指针 UNSIGNED stack_size) //堆栈的大小 STATUS NU_Activate_HISR (NU_HISR *hisr) //激活高级中断 INT NU_Control_Interrupts(INT new_level) //使能或是禁止一个中断