移植μC/OS-Ⅱ.

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
第一章 C语言概述 计算机公共教学部.
基于解释性语言的手机跨平台架构 Sloan Yi. Qt MTK.
Oracle数据库 Oracle 子程序.
第五章 C/OS-II在ARM系统中的应用与开发
嵌入式系统概论 —基于32位微处理器与实时操作系统 第五讲实时操作系统C/OS-Ⅱ分析 北京航空航天大学 机器人研究所 魏洪兴.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
在PHP和MYSQL中实现完美的中文显示
陈香兰 助教:陈博、李春华 Spring 2009 嵌入式操作系统 陈香兰 助教:陈博、李春华 Spring 2009.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
嵌入式系统及应用.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
嵌入式操作系统ucOS-II分析.
嵌入式系统 —RTEOS μC/OS-II 的移植
第7章 移植μC/OS-II到ARM7.
UcOS-II任务管理.
UCOS -II的使用 撰写:李湧 2006-06-29.
《手把手教你学STM32-UCOS》 主讲人 :正点原子团队 硬件平台:正点原子STM32开发板 版权所有:广州市星翼电子科技有限公司
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
文件读写实践 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
嵌入式系统 —嵌入式实时操作系统C/OS-Ⅱ分析 2006年5月.
第48组:姜立群(SC ) 谭兆路(SC ) 闫 佼(SC )
第五讲 C/OS-Ⅱ移植分析和系统初始化
本节内容 模拟线程切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
逆向工程-汇编语言
如何生成设备节点 广州创龙电子科技有限公司
ΜC/OSⅡ中的任务调度 Group01小组 柴永锋 李逢春 苗 冬.
UcOS-II时间管理.
嵌入式系统设计与实例开发 ——ARM与C/OS-Ⅱ 北京航空航天大学 智能嵌入式技术工作室 王田苗 魏洪兴.
CPU结构和功能.
中国科学技术大学计算机系 陈香兰(0551- ) Spring 2009
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
宁波市高校慕课联盟课程 与 进行交互 Linux 系统管理.
中 断 王 静 阜阳师范学院 计算机与信息工程学院.
SOA – Experiment 2: Query Classification Web Service
3. µC/OS-II内核 2019/4/11.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
5. µC/OS-II应用实例.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
OpenGL几何变换程序.
姚金宇 MIT SCHEME 使用说明 姚金宇
Ch6. uC/OS-II分析 宋健建 南京大学软件学院.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
信号量(Semaphore).
<编程达人入门课程> 本节内容 为什么要使用变量? 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
第九节 赋值运算符和赋值表达式.
iSIGHT 基本培训 使用 Excel的栅栏问题
第二章 类型、对象、运算符和表达式.
本节内容 结构体 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
#include <iostream.h>
临界区问题的硬件指令解决方案 (Synchronization Hardware)
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
_03宽字符与Unicode编程 本节课讲师——void* 视频提供:昆山爱达人信息技术有限公司 官网地址:
Python 环境搭建 基于Anaconda和VSCode.
本节内容 结构体.
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
基本知识 数据类型、变量、常量、运算符.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
使用Fragment 本讲大纲: 1、创建Fragment 2、在Activity中添加Fragment
<编程达人入门课程> 本节内容 有符号数与无符号数 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ:
多个Activity的使用 本讲大纲: 1、使用Bundle在Activity之间交换数据 2、调用另一个Activity并返回结果
一个实时嵌入式操作系统移植问题研究 报告人:荣峰华.
Presentation transcript:

移植μC/OS-Ⅱ

μC/OS-Ⅱ的移植 移植就是使一个实时内核能在某个微处理器或微控制器上运行。 为了方便移植,大部分的μC/OS-Ⅱ代码是用C语言写的;但仍需要用C和汇编语言写一些与处理器相关的代码,这是因为μC/OS-Ⅱ在读写处理器寄存器时只能通过汇编语言来实现。 由于μC/OS-Ⅱ在设计时就已经充分考虑了可移植性,所以μC/OS-Ⅱ的移植相对来说是比较容易的。

μC/OS-Ⅱ的移植 要使μC/OS-Ⅱ正常运行,处理器必须满足以下要求: 1. 处理器的C编译器能产生可重入代码。 3. 处理器支持中断,并且能产生定时中断(通常在10至100Hz之间)。 4. 处理器支持能够容纳一定量数据(可能是几千字节)的硬件堆栈。 5. 处理器有将堆栈指针和其它CPU寄存器读出和存储到堆栈或内存中的指令。 像Motorola 6805系列的处理器不能满足上面的第4条和第5条要求,所以μC/OS-Ⅱ不能在这类处理器上运行。

μC/OS-Ⅱ的结构以及与硬件的关系

μC/OS-Ⅱ的移植 移植工作包括以下几个内容: 用#define设置一个常量的值(OS_CPU.H) 用C语言编写六个简单的函数(OS_CPU_C.C) 编写四个汇编语言函数(OS_CPU_A.ASM) 根据处理器的不同,一个移植实例可能需要编写或改写50至300行的代码。

μC/OS-Ⅱ的移植 一旦代码移植结束,下一步工作就是测试。 这样做有两个好处:第一,避免使本来就复杂的事情更加复杂;第二,如果出现问题,可以知道问题出在内核代码上而不是应用程序。 开始测试的时候可以运行一些简单的任务和时钟节拍中断服务例程。一旦多任务调度成功地运行了,再添加应用程序的任务就是非常简单的工作了。

移植开发工具 移植μC/OS-Ⅱ需要一个C编译器,并且是针对用户用的CPU的。

移植目录结构和文件 Intel/AMD 80186 \SOFTWARE\uCOS-II\Ix86S   \OS_CPU.H \OS_CPU_A.ASM \OS_CPU_C.C \SOFTWARE\uCOS-II\Ix86L Motorola 68HC11 \SOFTWARE\uCOS-II\68HC11 各个微处理器的移植源代码必须在以下两个或三个文件中找到:OS_CPU.H,OS_CPU_C.C,OS_CPU_A.ASM。 汇编语言文件OS_CPU_A.ASM是可选择的,因为某些C编译器允许用户在C语言中插入汇编语言,所以用户可以将所需的汇编语言代码直接放到OS_CPU_C.C中。 一个放置移植实例的目录结构如表所示。这样的目录结构,使用户更容易找到目标处理器的文件。

INCLUDES.H文件 INCLUDES.H是一个头文件,它在所有.C文件的第一行被包含。 #include "includes.h"

OS_CPU.H文件 用户所必须要做的就是查看编译器手册,并找到对应于μC/OS-Ⅱ的标准C数据类型。 #ifdef OS_CPU_GLOBALS #define OS_CPU_EXT #else #define OS_CPU_EXT extern #endif  /*********************************** * 数据类型 (与编译器相关) ************************************/  typedef unsigned char BOOLEAN; typedef unsigned char INT8U; /* 无符号8位整数 (1)/整型数据结构既是可移植的又是直观的 typedef signed char INT8S; /* 有符号8位整数 typedef unsigned int INT16U; /* 无符号16位整数 typedef signed int INT16S; /* 有符号16位整数 typedef unsigned long INT32U; /* 无符号32位整数 typedef signed long INT32S; /* 有符号32位整数 typedef float FP32; /* 单精度浮点数 (2)/浮点数据类型 typedef double FP64; /* 双精度浮点数 typedef unsigned int OS_STK; /* 堆栈入口宽度为16位 用户所必须要做的就是查看编译器手册,并找到对应于μC/OS-Ⅱ的标准C数据类型。

OS_CPU.H文件(续) /************************* * 与处理器相关的代码 * 与处理器相关的代码 *************************/  #define OS_ENTER_CRITICAL() ??? /* 禁止中断 */ (3) #define OS_EXIT_CRITICAL() ??? /* 允许中断 */  #define OS_STK_GROWTH 1 /* 定义堆栈的增长方向: 1=向下, 0=向上 */ (4) /绝大多数的微处理器和微控制器的堆栈是从上往下长的,但是某些处理器是用另外一种方式工作的。μC/OS-Ⅱ被设计成两种情况都可以处理。 #define OS_TASK_SW() ??? (5)/μC/OS-Ⅱ从低优先级任务切换到最高优先级任务时调用OS_TASK_SW() 。任务切换只是简单的将处理器寄存器保存到将被挂起的任务的堆栈中,并且将更高优先级的任务从堆栈中恢复出来。 上述代码中的???部分,对于不同的微处理器来说,都不一样。例如通过执行STI命令在Intel 80186上禁止中断,并用CLI命令来允许中断。 #define OS_ENTER_CRITICAL() asm CLI #define OS_EXIT_CRITICAL() asm STI

OS_CPU_A.ASM文件 μC/OS-Ⅱ的移植实例要求用户编写四个简单的汇编语言函数: OSStartHighRdy()、OSCtxSw()、OSIntCtxSw()、OSTickISR() 如果用户的编译器支持插入汇编语言代码的话,用户就可以将所有与处理器相关的代码放到OS_CPU_C.C文件中,而不必再拥有一些分散的汇编语言文件。

OSStartHighRdy() void OSStartHighRdy (void) 要想运行最高优先级任务,用户所要做的是将所有处理器寄存器按顺序从任务堆栈中恢复出来,并且执行中断的返回。 void OSStartHighRdy (void) { Call user definable OSTaskSwHook(); Get the stack pointer of the task to resume: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; OSRunning = TRUE; Restore all processor registers from the new task's stack; Execute a return from interrupt instruction; } 注意:OSStartHighRdy()必须调用OSTaskSwHook(),因为用户正在进行任务切换的部分工作——用户在恢复最高优先级任务的寄存器。而OSTaskSwHook()可以通过检查OSRunning来知道是OSStartHighRdy()在调用它(OSRunning为FALSE)还是正常的任务切换在调用它(OSRunning为TRUE)。 OSStartHighRdy()还必须在最高优先级任务恢复之前和调用OSTaskSwHook()之后设置OSRunning为TRUE。

OSCtxSw() 任务级的切换问题是通过发软中断命令或依靠处理器执行陷阱指令来完成的。中断服务例程,陷阱或异常处理例程的向量地址必须指向OSCtxSw()。 如果当前任务调用μC/OS-Ⅱ提供的系统服务,并使得更高优先级任务处于就绪状态,μC/OS-Ⅱ就会借助上面提到的向量地址找到OSCtxSw()。 在系统服务调用的最后,μC/OS-Ⅱ会调用OSSched(),并由此来推断当前任务不再是要运行的最重要的任务了。OSSched()先将最高优先级任务的地址装载到OSTCBHighRdy中,再通过调用OS_TASK_SW()来执行软中断或陷阱指令。 注意:变量OSTCBCur早就包含了指向当前任务的任务控制块(OS_TCB)的指针。软中断 (或陷阱) 指令会强制一些处理器寄存器(比如返回地址和处理器状态字)到当前任务的堆栈中,并使处理器执行OSCtxSw()。

OSCtxSw()的原型程序 void OSCtxSw(void) { 保存处理器寄存器; { 保存处理器寄存器; 将当前任务的堆栈指针保存到当前任务的OS_TCB中: OSTCBCur->OSTCBStkPtr = Stack pointer; 调用用户定义的OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; 得到需要恢复的任务的堆栈指针: Stack pointer = OSTCBHighRdy->OSTCBStkPtr; 将所有处理器寄存器从新任务的堆栈中恢复出来; 执行中断返回指令; } 上述这些代码必须写在汇编语言中,因为用户不能直接从C中访问CPU寄存器。注意在OSCtxSw()和用户定义的函数OSTaskSwHook()的执行过程中,中断是禁止的。

OSIntCtxSw() OSIntExit()通过调用OSIntCtxSw()来从ISR中执行切换功能,所有的处理器寄存器都被正确地保存到了被中断的任务的堆栈之中。 实际上除了我们需要的东西外,堆栈结构中还有其它的一些东西。OSIntCtxSw()必须要清理堆栈,这样被中断的任务的堆栈结构内容才能满足我们的需要。

在ISR执行过程中的堆栈内容 当中断来临的时候,处理器会结束当前的指令,识别中断并且初始化中断处理过程,包括将处理器的状态寄存器和返回被中断的任务的地址保存到堆栈中(1)。 接着,CPU会调用正确的ISR,要求用户的ISR在开始时要保存剩下的处理器寄存器(2)。 μC/OS-Ⅱ要求用户的ISR在完成中断服务的时候调用OSIntExit(),导致调用者的返回地址被保存到被中断的任务的堆栈中(3)。 处理器的状态寄存器会被保存到被中断的任务的堆栈中(4)。 调用OSIntCtxSw()使返回地址被保存到被中断的任务的堆栈中(5)。

OSIntCtxSw()的原型程序 OSIntExit(), OSIntCtxSw()过程中压入堆栈的多余内容; void OSIntCtxSw(void) { 调整堆栈指针来去掉在调用: OSIntExit(), OSIntCtxSw()过程中压入堆栈的多余内容; 将当前任务堆栈指针保存到当前任务的OS_TCB中: OSTCBCur->OSTCBStkPtr = 堆栈指针; 调用用户定义的OSTaskSwHook(); OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; 得到需要恢复的任务的堆栈指针: 堆栈指针 = OSTCBHighRdy->OSTCBStkPtr; 将所有处理器寄存器从新任务的堆栈中恢复出来; 执行中断返回指令; } 这些代码必须写在汇编语言中,因为用户不能直接从C语言中访问CPU寄存器。

OSTickISR() μC/OS-Ⅱ要求用户提供一个时钟资源来实现时间的延时和期满功能。时钟节拍应该每秒钟发生10-100次。可以使用硬件时钟,也可以从交流电中获得50/60Hz的时钟频率。 用户必须在开始多任务调度后(调用OSStart()后)允许时钟节拍中断。即用户应该在OSStart()运行后,μC/OS-Ⅱ启动运行的第一个任务中初始化节拍中断。

时钟节拍ISR的原型程序 void OSTickISR(void) {保存处理器寄存器; 调用OSIntEnter()或者直接将 OSIntNesting加1;  调用OSTimeTick();  调用OSIntExit(); 恢复处理器寄存器; 执行中断返回指令; } 这些代码必须写在汇编语言中,因为用户不能直接从C语言中访问CPU寄存器。

OS_CPU_C.C文件 μC/OS-Ⅱ的移植实例要求用户编写六个简单的C函数: OSTaskStkInit()、OSTaskCreateHook()、OSTaskDelHook()、OSTaskSwHook()、OSTaskStatHook()、OSTimeTickHook() 唯一必要的函数是OSTaskStkInit(),其它五个函数必须得声明但没必要包含代码。

OSTaskStkInit() OSTaskCreate()和OSTaskCreateExt()通过调用OSTaskStkInit()来初始化任务的堆栈结构,因此,堆栈看起来就像刚发生过中断并将所有的寄存器保存到堆栈中的情形一样。 假定pdata会被编译器保存到堆栈中,OSTaskStkInit()就会简单的模仿编译器的这种动作,将pdata保存到堆栈中(1)。 处理器至少得将程序计数器的值(中断返回地址)和处理器的状态字存入堆栈(2)。 接着,用户需要将剩下的处理器寄存器保存到堆栈中(3)。 一旦用户初始化了堆栈,OSTaskStkInit()就需要返回堆栈指针所指的地址(4)。

OSTaskCreateHook() 当用OSTaskCreate()或OSTaskCreateExt()建立任务的时候就会调用OSTaskCreateHook(),该函数允许用户或使用用户的移植实例的用户扩展μC/OS-Ⅱ的功能。 当μC/OS-Ⅱ设置完了自己的内部结构后,会在调用任务调度程序之前调用OSTaskCreateHook()。该函数被调用的时候中断是禁止的,因此用户应尽量减少该函数中的代码以缩短中断的响应时间。

OSTaskDelHook() 当任务被删除的时候就会调用OSTaskDelHook()。该函数在把任务从μC/OS-Ⅱ的内部任务链表中解开之前被调用。 当OSTaskDelHook()被调用的时候,它会收到指向正被删除任务的OS_TCB的指针,这样它就可以访问所有的结构成员了。

OSTaskSwHook() 当发生任务切换的时候调用OSTaskSwHook()。不管任务切换是通过OSCtxSw()还是OSIntCtxSw()来执行的都会调用该函数。 OSTaskSwHook()可以直接访问OSTCBCur 和OSTCBHighRdy,因为它们是全局变量。OSTCBCur指向被切换出去的任务的OS_TCB,而OSTCBHighRdy指向新任务的OS_TCB。 注意在调用OSTaskSwHook()期间中断一直是被禁止的。因为代码的多少会影响到中断的响应时间,所以用户应尽量使代码简化。

OSTaskStatHook() OSTaskStatHook()每秒钟都会被OSTaskStat()调用一次。 用户可以用OSTaskStatHook()来扩展统计功能。例如,用户可以保持并显示每个任务的执行时间,每个任务所用的CPU份额,以及每个任务执行的频率等等。

OSTimeTickHook() OSTaskTimeHook()在每个时钟节拍都会被OSTaskTick()调用。 实际上,OSTaskTimeHook()是在节拍被μC/OS-Ⅱ真正处理,并通知用户的移植实例或应用程序之前被调用的。

OSTaskCreate() and OSTaskCreateExt() OSTaskCreateHook() void OSTaskCreateHook(OS_TCB *ptcb)   File Called from Code enabled by OS_CPU_C.C OSTaskCreate() and OSTaskCreateExt() OS_CPU_HOOKS_EN  

OSTaskDelHook() void OSTaskDelHook(OS_TCB *ptcb) File Called from   File Called from Code enabled by OS_CPU_C.C OSTaskDel() OS_CPU_HOOKS_EN  

OSCtxSw() and OSIntCtxSw() OSTaskSwHook() void OSTaskSwHook(void)   File Called from Code enabled by OS_CPU_C.C OSCtxSw() and OSIntCtxSw() OS_CPU_HOOKS_EN  

OSTaskStatHook() void OSTaskStatHook(void) File Called from   File Called from Code enabled by OS_CPU_C.C OSTaskStat() OS_CPU_HOOKS_EN  

OSTimeTickHook() void OSTimeTickHook(void) File Called from   File Called from Code enabled by OS_CPU_C.C OSTimeTick() OS_CPU_HOOKS_EN