嵌入式系统—基于32位微处理器与实时操作系统-第九章 RTEOS_μCOS-II_的移植.ppt_第1页
嵌入式系统—基于32位微处理器与实时操作系统-第九章 RTEOS_μCOS-II_的移植.ppt_第2页
嵌入式系统—基于32位微处理器与实时操作系统-第九章 RTEOS_μCOS-II_的移植.ppt_第3页
嵌入式系统—基于32位微处理器与实时操作系统-第九章 RTEOS_μCOS-II_的移植.ppt_第4页
嵌入式系统—基于32位微处理器与实时操作系统-第九章 RTEOS_μCOS-II_的移植.ppt_第5页
免费预览已结束,剩余96页可下载查看

下载本文档

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

文档简介

嵌入式系统 rteos c/os-ii 的移植,2006年6月9日,主要内容,移植规划 c/os-ii的移植 嵌入式系统的初始化,移植规划-概述,所谓“移植”,就是使一个实时内核能在其它的微处理器或微控制器上运行。 尽管大部分c/os-ii的代码是用c语言编写的,但是在编写与处理器硬件相关的代码时还是不得不使用汇编语言。 移植的主要工作就是编写这些与处理器硬件相关的代码。 操作系统的移植大体可以分为两个层次: 跨体系结构的移植 针对特定处理器的移植,移植规划,在移植前针对所使用的微处理器进行规划,主要有以下几个方面的考虑: 编译器的选择 任务模式的选择 支持的指令集,移植规划(续),编译器的选择,针对arm处理器核的c语言编译器有很多,如sdt、 ads、iar、tasking和gcc等 目前在国内最流行的是ads、sdt和gcc sdt和ads均为arm公司自己开发,ads为sdt的升级版,以后arm公司不再支持sdt,故不选择sdt。gcc虽然支持广泛,很多开发套件使用它作为编译器,但是与ads比较其编译效率较低,这对充分发挥芯片性能不利 考虑使用ads编译程序和调试,arm的工作模式,arm处理器有7种操作模式: 用户模式(usr) - 正常的程序执行模式 快速中断模式(fiq) - 支持高速数据传输或通道处理 中断模式(irq) - 用于通用中断处理 管理员模式(svc) - 操作系统的保护模式. 中止模式(abt) - 支持虚拟内存和/或内存保护等异常 系统模式(sys) - 支持操作系统的特殊用户模式(运行操作系统任务) 未定义模式(und) - 支持硬件协处理器的软件仿真 除了用户模式外,其他模式均可视为特权模式,移植规划(续),任务模式的取舍,arm7处理器核具有上述七种模式,其中除用户模式外其它均为特权模式。其中管理、中止、未定义、中断和快中断模式与相应异常相联系,任务使用这些模式不太适合。 系统模式除了是特权模式外,其它与用户模式一样,因而可选为任务使用的模式只有用户模式和系统模式。 为了尽量减少任务代码错误对整个程序的影响,缺省的任务模式定为用户模式,可选为系统模式,同时提供接口使任务可以在这两种模式间切换。,移植规划(续),支持的指令集,带t变量的arm7处理器核具有两个指令集: 标准32位arm指令集 16位thumb指令集 两种指令集有不同的应用范围。 为了最大限度地支持芯片的特性,任务应当可以使用任意一个指令集并可以自由切换,而且不同的任务应当可以使用不同的指令集,移植c/os-ii,概述,要移植一个操作系统到一个特定的cpu体系结构并不是一件很容易的事情,它对移植者有以下要求: 1 对目标体系结构要有很深了解; 2 对os原理要有较深入的了解; 3 对所使用的编译器要有较深入的了解; 4 对需要移植的操作系统要有相当的了解; 5 对具体使用的芯片也要一定的了解,要移植一个操作系统到一个特定的cpu体系结构上并不是一件很容易的事情,它对移植者有以下要求: 1 对目标体系结构要有很深了解; 2 对os原理要有较深入的了解; 3 对所使用的编译器要有较深入的了解; 4 对需要移植的操作系统要有相当的了解; 5 对具体使用的芯片也要一定的了解。,概述,要移植一个操作系统到一个特定的cpu体系结构上并不是一件很容易的事情,它对移植者有以下要求: 1 对目标体系结构要有很深了解; 2 对os原理要有较深入的了解; 3 对所使用的编译器要有较深入的了解; 4 对需要移植的操作系统要有相当的了解; 5 对具体使用的芯片也要一定的了解。,因为第4点的影响是全局性的,它决定移植代码的框架和功能。 所以重点介绍第4点。,主要内容,移植规划 c/os-ii的移植 嵌入式系统的初始化,c/os-ii的文件结构,c/os-ii移植,c/os-ii硬件软件体系结构,用于产生系统时钟,移植时需要编写的代码,移植c/os-ii满足的条件,处理器的c编译器能产生可重入代码 在程序中可以打开或者关闭中断 处理器支持中断,并且能产生定时中断(通常在10100hz之间) 处理器支持能够容纳一定量数据的硬件堆栈(通常是几千字节) 处理器有将堆栈指针和其他cpu寄存器的内容存储和读出到堆栈(或者内存)的指令,什么是可重入代码,可重入的代码指的是一段可以被多个任务同时调用,而不必担心会破坏数据的代码(比如:一个函数) 即:可重入型函数在任何时候都可以被中断执行,过一段时间以后又可以继续运行,而不会因为在函数中断的时候被其他的任务重新调用,而影响函数中的数据,可重入代码举例,程序1:可重入型函数 void swap(int *x, int *y) int temp; temp=*x; *x=*y; *y=temp; ,非可重入代码举例,程序2:非可重入型函数 int temp; void swap(int *x, int *y) temp=*x; *x=*y; *y=temp; ,不可重入函数被中断破坏,如何使函数具有可重入性,使swap()函数具有可重入性的条件: 把temp定义为局部变量 调用swap()函数之前关中断,调用 后再开中断 用信号量禁止该函数在使用过程中 被再次调用,概述,根据c/os-ii的要求,移植c/os-ii到一个新的体系结构上需要提供2个或3个文件: os_cpu.h(c语言头文件) os_cpu_c.c(c程序源文件) os_cpu_a.asm(汇编程序源文件) 其中os_cpu_a.asm在某些情况下不需要,但极其罕见。不需要os_cpu_a.asm的必须满足以下苛刻条件: 1.可以直接使用c语言开关中断; 2.可以直接使用c语言编写中断服务程序; 3.可以直接使用c语言操作堆栈指针; 4.可以直接使用c语言保存cpu的所有寄存器。,移植需要编写的文件,概述,实际上,还有一个文件很重要,它就是irq.inc,它定义了一个汇编宏,它是c/os-ii for arm7通用的中断服务程序的汇编与c函数接口代码。时钟节拍中断服务程序也没有移植,因为其与芯片和应用都强烈相关,需要用户自己编写,不过可以通过irq.inc简化用户代码的编写。,移植代码包括的主要内容,关于头文件includes.h和config.h,c/os-ii要求所有.c文件的都要包含头文件includes.h,这样使得用户项目中的每个.c文件不用分别去考虑它实际上需要哪些头文件。 使用includes.h的缺点是它可能会包含一些实际不相关的头文件,这意味着每个文件的编译时间可能会增加,但却增强了代码的可移植性。 在移植中另外增加了一个头文件config.h,要求所有用户程序必须包含config.h,在config.h中包含includes.h和特定的头文件和配置项。而c/os-ii的系统文件依然只是包含includes.h,即c/os-ii的系统文件完全不必改动。所有的配置改变包括头文件的增减均在config.h中进行,而includes.h定下来后不必改动(c/os-ii的系统文件需要包含的东西是固定的)。这样,c/os-ii的系统文件需要编译的次数大大减少,编译时间随之减少。,设置与处理器和编译器相关的代码,os_cpu.h中定义了与编译器相关的数据类型。比如:int8u、int8s等。 与 arm处理器相关的代码,使用os_enter_critical() 和os_exit_critical() 宏开启关闭中断 设置堆栈的增长方向 :堆栈由高地址向低地址增长,编写os_cpu.h,c/os-ii使用结构常量os_stk_growth中指定堆栈的生长方式: 置os_stk_growth为0表示堆栈从下往上长。 置os_stk_growth为1表示堆栈从上(高地址)往下(低地址)长。 虽然arm处理器核对于两种方式均支持,但ads的c语言编译器仅支持一种方式,即从上往下长,并且必须是满递减堆栈,所以os_stk_growth的值为1。 #define os_stk_growth 1,堆栈生长方式,编写os_cpu.h,c/os-ii不使用c语言中的short、int、long等数据类型的定义,因为它们与处理器类型有关,隐含着不可移植性。代之以移植性强的整数数据类型,这样,既直观又可移植,不过这就成了必须移植的代码。根据ads编译器的特性,这些代码如下程序清单所示(与编译有关)。,typedef unsigned char boolean; typedef unsigned char int8u; typedef signed char int8s; typedef unsigned short int16u; typedef signed short int16s; typedef unsigned int int32u; typedef signed int int32s; typedef float fp32; typedef double fp64; typedef int32u os_stk;,不依赖于编译的数据类型,设置includes.h,typedef unsigned char boolean; typedef unsigned char int8u; typedef signed char int8s; typedef unsigned int int16u; typedef signed int int16s; typedef unsigned long int32u; typedef signed long int32s; typedef float fp32; typedef double fp64; typedef unsigned long os_stk; typedef unsigned long os_cpu_sr; extern int ints_off(void); extern void ints_on(void); #define os_enter_critical() cpu_sr = ints_off(); #define os_exit_critical() if(cpu_sr = 0) ints_on(); #define os_stk_growth 1 /*从高向低*/,程序状态寄存器(cpsr),条件位: n = 1-结果为负,0-结果为正或0 z = 1-结果为0,0-结果不为0 c =1-进位,0-借位 v =1-结果溢出,0结果没溢出 q 位: 仅arm 5te/j架构支持 指示增强型dsp指令是否溢出 j 位 仅arm 5te/j架构支持 j = 1: 处理器处于jazelle状态,中断禁止位: i = 1: 禁止 irq. f = 1: 禁止 fiq. t bit 仅arm xt架构支持 t = 0: 处理器处于 arm 状态 t = 1: 处理器处于 thumb 状态 mode位(处理器模式位): 0b10000 user 0b10001 fiq 0b10010 irq 0b10011 supervisor 0b10111 abort 0b11011 undefined 0b11111 system,编写os_cpu.h,c/os-ii运行时,处理器可能处于的模式如下图所示:,使用软中断swi作底层接口,用户任务使用的处理器模式,arm7内核具有的指令集,arm指令 用户模式,arm指令 系统模式,thumb指令 系统模式,thumb指令 用户模式,编写os_cpu.h,为了使底层接口函数与处理器状态无关,同时在任务调用相应的函数不需要知道函数位置,在移植中使用软中断指令swi作为底层接口,使用不同的功能号区分不同的函数。软中断功能号分配如下表所示,未列出的为保留功能。,使用软中断swi作底层接口,编写os_cpu.h,用软中断作为操作系统的底层接口就需要在c语言中使用swi(software interrupt)指令。在ads中,有一个关键字_swi,用它声明一个不存在的函数,则调用这个函数就在调用这个函数的地方插入一条swi指令,并且可以指定功能号。同时,这个函数也可以有参数和返回值,其传递规则与一般函数相同。,使用软中断swi作底层接口,/* 任务级任务切换函数 */ _swi(0x00) void os_task_sw(void); /* 运行优先级最高的任务 */ _swi(0x01) void _osstarthighrdy(void); /* 关中断 */ _swi(0x02) void os_enter_critical(void); /* 开中断 */ _swi(0x03) void os_exit_critical(void); /* 任务切换到系统模式 */ _swi(0x80) void changetosysmode(void); /* 任务切换到用户模式 */ _swi(0x81) void changetousrmode(void); /* 任务代码是arm代码 */ _swi(0x82) void taskisarm(int8u prio); /* 任务代码是thumb代码 */ _swi(0x83) void taskisthumb(int8u prio);,编写os_cpu_c.c,c/os-ii的移植要求用户编写10个c函数: ostaskstkinit(): ostaskcreat()和ostaskcreatext()通过调用 本函数,初始化任务的栈结构 ostaskcreatehook():每当添加任务时由os_tcbinit( )函数调用 ostaskdelhook(): 任务被删除后由ostaskdel()调用 ostaskswhook(): 任务切换时两种情况均会调用该函数 ostaskidlehook():ostaskidle()函数可调用该函数实现cpu低功耗模式 ostimetickhook():本函数在每个时钟节拍都会被ostimetick()调用 osinithookbegin():进入osinit()函数后本函数会立即被调用 osinithookend(): osinit()函数返回之前被调用 ostcbinithook():os_tcbinit( )在调用ostaskcreatehook()之前将先 调用本函数 唯一必要的函数是ostaskstkinit(),其他9个函数必须声明,但不一定要包含任何代码,编写os_cpu_c.c,该函数用于初始化任务堆栈,使任务的堆栈看起来就像刚发生中断一样。即任务被执行时,就像从中断返回一样。 在编写此函数之前,必须先确定任务的堆栈结构。而任务的堆栈结构是与cpu的体系结构、编译器有密切的关联。本移植的堆栈结构如下图所示。,ostaskstkinit( ),编写os_cpu_c.c,ostaskstkinit( ),os_stk *ostaskstkinit (void (*task)(void *pd), void *pdata, os_stk *ptos, int16u opt) os_stk *stk; opt = opt; stk = ptos; *stk = (os_stk) task; *-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 = (user_using_mode|0x00); *-stk = 0; return (stk); ,入栈的数据,编写os_cpu_c.c,ostaskstkinit( ),os_stk *ostaskstkinit (void (*task)(void *pd), void *pdata, os_stk *ptos, int16u opt) os_stk *stk; opt = opt; stk = ptos; *stk = (os_stk) task; *-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 = (user_using_mode|0x00); *-stk = 0; return (stk); ,该数据比较特别,它用于保存该任务关中断的次数,它在调用os_enter_critical( )时加1,在调用os_exit_critical( )时减1。 这样每个任务都可以独立控制本任务的中断允许状态,而不会影响其它任务的中断允许状态。因此关中断和开中断就可以嵌套。,编写os_cpu_c.c,软件中断异常服务程序,操作系统与硬件相关的底层函数使用软件中断作为接口,如下表所示。 移植代码中一个重要的工作就是为这些软件中断编写服务程序,编写os_cpu_c.c,软件中断异常服务程序,void swi_exception(int swi_num, int *regs) os_tcb *ptcb; switch(swi_num) case 0x02: / 关中断 . case 0x03: / 开中断 . case 0x80: / 任务切换到系统模式 . case 0x81: / 任务切换到用户模式 . case 0x82: / 任务代码是arm代码 . case 0x83: / 任务代码是thumb代码 . default: ,编写os_cpu_c.c,软件中断异常服务程序,编写os_cpu_c.c,软件中断异常服务程序,编写os_cpu_c.c,软件中断异常服务程序,void swi_exception(int swi_num, int *regs) . case 0x02: / 关中断 _asm mrs r0,spsr orr r0,r0,#noint msr spsr_c,r0 osentersum+; break; case 0x03: / 开中断 if (-osentersum = 0) _asm mrs r0,spsr bic r0,r0,#noint msr spsr_c,r0 break; .,关闭中断,打开中断,编写os_cpu_c.c,软件中断异常服务程序,编写os_cpu_c.c,软件中断异常服务程序,void swi_exception(int swi_num, int *regs) . case 0x80: / 任务切换到系统模式 _asm mrs r0,spsr bic r0,r0,#0x1f orr r0,r0,#sys32mode msr spsr_c,r0 break; case 0x81: / 任务切换到用户模式 _asm mrs r0,spsr bic r0,r0,#0x1f orr r0,r0,#usr32mode msr spsr_c,r0 break; .,编写os_cpu_c.c,软件中断异常服务程序,编写os_cpu_c.c,软件中断异常服务程序,. case 0x82: / 任务代码是arm代码 if (regs0 ostcbstkptr1 .,cpsr:程序状态寄存器,编写os_cpu_c.c,软件中断异常服务程序,注意: 这两个函数必须在相应的任务建立后但还没有运行时调用。 如果在低优先级的任务中创建高优先级的任务就十分危险了。此时,解决的方法有三种: (1)高优先级任务使用默认的指令集; (2)改变函数ostaskcreatehook()使任务默认不是处于就绪状态,建立任务后调用函数ostaskresume()来使任务进入就绪状态; (3)建立任务时禁止任务切换,调用函数 taskisarm()或taskisthumb()后再允许任务切换。,编写os_cpu_c.c,在os_cpu_c.c文件中还有许多hook()函数,它们在某个特定的系统动作时被调用,允许执行函数中的用户代码。这些函数默认是空函数,用户根据实际情况添加相关代码。它们分别如下表所示。,hook( )函数,移植c/os-ii,编写os_cpu_a.asm,在os_cpu_a.asm文件中有: 软件中断的汇编接口程序 任务切换程序 os启动时运行就绪最高优先级任务的程序,os_cpu_a.asm,c/os-ii的移植要求用户编写4个汇编语言函数: osstarthighrdy() osctxsw() osintctxsw() ostickisr() 如果编译器支持插入行汇编代码,就可以将所有与处理器相关的代码放到os_cpu_c.c文件中,而不必再有单独的汇编语言文件,编写os_cpu_a.asm,在调用软中断之后,处理器切换到arm指令和管理模式下工作。在执行软件中断服务函数之前,要提取中断号和其它入口参数,这些通过软件中断接口程序完成。,软件中断汇编接口,softwareinterrupt ldr sp, stacksvc stmfd sp!, r0-r3, r12, lr mov r1, sp mrs r3, spsr tst r3, #t_bit ldrneh r0, lr,#-2 bicne r0, r0, #0xff00 ldreq r0, lr,#-4 biceq r0, r0, #0xff000000 cmp r0, #1 ldrlo pc, =osintctxsw ldreq pc, =_osstarthighrdy bl swi_exception ldmfd sp!, r0-r3, r12, pc,编写os_cpu_a.asm,c/os-ii是抢占式实时操作系统,得到运行的始终是就绪条件下最高优先级的任务。当处于运行状态的任务因为某种原因进入就绪态,或者有其它更高优先级的任务进入就绪态,操作系统内核就要运行别的就绪任务,这时需要进行任务切换。,任务切换代码,编写os_cpu_a.asm 任务切换代码,任务切换可能发生的情况有两种: 1.当前运行的任务主动交出cpu控制权,通常发生在等待某个事件或是调用系统延时。调用函数os_task_sw( ) 2.发生中断,使更高优先级的任务进入就绪状态,内核剥夺当前任务的运行资格。即发生在中断退出时。调用函数osintctxsw( ),spsr:程序状态保留寄存器 cpsr:当前程序状态寄存器,编写os_cpu_a.asm,虽然os_task_sw( )和osintctxsw( )的执行条件不同,但是它们的功能相同,只要稍作处理就可以它们共用一段任务切换代码。这些处理就是保证在执行任务切换前两者的任务现场是一致的。共同执行的任务切换代码是“osintctxsw” 其中os_task_sw( )是通过软件中断0完成的,通过前面的分析,可以知道执行任务切换时的现场环境如下所示,同时r3中保存着spsr,它是任务中断前cpsr的备份。,任务切换代码,编写os_cpu_a.asm,osintctxsw,流程图,编写os_cpu_a.asm,osintctxsw,保存当前任务的 寄存器组及其它,osintctxsw ;下面为保存任务环境 ldr r2, sp, #20 ;获取pc ldr r12, sp, #16 ;获取r12 mrs r0, cpsr ;保存lr,pc及r4-r12 msr cpsr_c, #(noint | sys32mode) mov r1, lr stmfd sp!, r1-r2 stmfd sp!, r4-r12 ;获取r0-r3,并出栈r12和pc寄存器 msr cpsr_c, r0 ldmfd sp!, r4-r7 add sp, sp, #8 ;保存r0-r3 msr cpsr_c, #(noint | sys32mode) stmfd sp!, r4-r7 ;获取osentersum,并保存cpsr,osentersum ldr r1, =osentersum ldr r2, r1 stmfd sp!, r2, r3 .,任务环境保存结束后的栈结构,编写os_cpu_a.asm,osintctxsw,修改当前任务的tcb堆栈指针,用将要运行任务的优先级和tcb指针更新ospriohighrdy和ostcbcur,osintctxsw . ;保存当前任务堆栈指针到当前任务的tcb ldr r1, =ostcbcur ldr r1, r1 str sp, r1 bl staskswhook ;调用钩子函数 ;ospriocur = ospriohighrdy ldr r4, =ospriocur ldr r5, =ospriohighrdy ldrb r6, r5 strb r6, r4 ;ostcbcur = ostcbhighrdy ldr r6, =ostcbhighrdy ldr r6, r6 ldr r4, =ostcbcur str r6, r4 .,编写os_cpu_a.asm,osintctxsw,编写os_cpu_a.asm,osintctxsw,恢复新任务的寄存器组及其它,运行新任务,osintctxsw . osintctxsw_1 ;从r6指向tcb中获取新任务堆栈指针 ldr r4, r6 ;调整堆栈指针 ;17寄存器cpsr,osentersum,r0-r12,lr,sp add sp, r4, #68 ldr lr, sp, #-8 ;进入管理模式,恢复任务的各寄存器和变量 msr cpsr_c, #(noint | svc32mode) mov sp, r4 ;设置堆栈指针 ;获取cpsr和osentersum ldmfd sp!, r4, r5 ;恢复新任务的osentersum ldr r3, =osentersum str r4, r3 ;恢复cpsr msr spsr_cxsf, r5 ;运行新任务 ldmfd sp!, r0-r12, lr, pc ,编写os_cpu_a.asm,osintctxsw,这段代码还被_osstarthighrdy 函数调用,用于启动最高优先级的就绪任务,_osstarthighrdy msr cpsr_c, #(noint | sys32mode) ;告诉uc/os-ii自身已经运行 ldr r4, =osrunning mov r5, #1 strb r5, r4 ;调用钩子函数 bl ostaskswhook ldr r6, =ostcbhighrdy ;取得新任务的tcb指针 ldr r6, r6 b osintctxsw_1,编写os_cpu_a.asm,osstarthighrdy,c/os-ii的多任务环境由函数osstart( ) 启动。用户在调用该函数之前,必须已经建立了一个或更多任务。osstart()最终调用函数osstarthighrdy( )运行多任务启动前优先级最高的任务,而它最终是调用_osstarthighrdy实现的,其代码如下所示:,编写os_cpu_a.asm,通过前面的分析,我们可以画出下面这张结构图:,移植c/os-ii,关于中断及时钟节拍,在本移植中,irq是受c/os-ii管理的中断,而对于fiq不做处理,这是为了提高fiq的响应速度。由于各种arm芯片的中断系统不一样,各个用户的目标板也不一样,对于中断和时钟节拍是需要进一步移植的代码。为此编写一个汇编宏,它是c/os-ii for arm7通用的中断服务程序的汇编与c函数接口代码。,注:在不受管理的中断服务程序中不能调用任何系统函数。,关于中断及时钟节拍,流程图,关于中断及时钟节拍,流程图,保存当前任务的 寄存器组,中断嵌套数加1,切换到系统模式 执行中断服务程序,关中断 执行osintexit( ),切换到irq模式 判断是否需要进行任务切换,切换任务或返回,macro $irq_label handler $irq_exception_function export $irq_label ; 输出的标号 import $irq_exception_function ; 引用的外部标号 $irq_label sub lr, lr, #4 ; 计算返回地址 stmfd sp!, r0-r3, r12, lr ; 保存任务环境 mrs r3, spsr ; 保存状态 ; 保存用户状态的r3,sp,lr,不能回写 stmfd sp, r3, sp, lr ldr r2, =osintnesting ldrb r1, r2 add r1, r1, #1 strb r1, r2 sub sp, sp, #4*3 ; 切换到系统模式 msr cpsr_c, #(noint | sys32mode) cmp r1, #1 ldreq sp, =stackusr .,关于中断及时钟节拍,关于中断及时钟节拍,流程图,保存当前任务的 寄存器组,中断嵌套数加1,切换到系统模式 执行中断服务程序,关中断 执行osintexit( ),切换到irq模式 判断是否需要进行任务切换,切换任务或返回,中断服务程序 (isr),在isr中可以打开中断实现中断嵌套,macro $irq_label handler $irq_exception_function export $irq_label ; 输出的标号 import $irq_exception_function ; 引用的外部标号 $irq_label . bl $irq_exception_function ; 切换到系统模式 msr cpsr_c, #(noint | sys32mode) ; osentersum,使osintexit退出时中断关闭 ldr r2, =osentersum mov r1, #1 str r1, r2 bl osintexit ; 因为中断服务程序要退出,所以osentersum=0 ldr r2, =osentersum mov r1, #0 str r1, r2 ; 切换回irq模式,并恢复用户状态的r3,sp,lr msr cpsr_c, #(noint | irq32mode) ldmfd sp, r3, sp, lr ; 注意不能回写 .,关于中断及时钟节拍,关于中断及时钟节拍,流程图,保存当前任务的 寄存器组,中断嵌套数加1,切换到系统模式 执行中断服务程序,关中断 执行osintexit( ),切换到irq模式 判断是否需要进行任务切换,切换任务或返回,macro $irq_label handler $irq_exception_function export $irq_label ; 输出的标号 import $irq_exception_function ; 引用的外部标号 $irq_label . ldr r0, =ostcbhighrdy ldr r0, r0 ldr r1, =ostcbcur ldr r1, r1 cmp r0, r1 add sp, sp, #4*3 msr spsr_cxsf, r3 ; 不进行任务切换 ldmeqfd sp!, r0-r3, r12, pc ; 进行任务切换 ldr pc, =osintctxsw mend,关于中断及时钟节拍,关于中断及时钟节拍,流程图,保存当前任务的 寄存器组,中断嵌套数加1,切换到系统模式 执行中断服务程序,关中断 执行osintexit( ),切换到irq模式 判断是否需要进行任务切换,切换任务或返回,中断服务程序 (isr),在isr中可以打开中断实现中断嵌套,void isr(void) os_enter_critical()或直接给变量osentersum赋1; 清除中断源; 通知中断控制器中断结束: 开中断: os_exit_critical(); 用户处理程序; ,中断服务程序的编写,因为中断发生时肯定是允许中断的,所以如果用户在清除中断源之前调用c/os-ii的系统服务函数就很可能会造成芯片的中断系统工作异常而使程序工作异常。因此在函数开始处关闭中断,或者直接给变量osentersum赋1。如果用户程序没有这种情况,则不需要这个操作。在执行os_exit_critical( )后,中断重新打开,如果在接下来的用户处理程序中发生中断,就可以实现中断嵌套。,主要内容,移植规划 c/os-ii的移植 嵌入式系统的初始化,初始化程序的下载执行,目标机,宿主机,1)通过编程器将可执行目标文件烧写到bootrom(rom、eprom、flash)等; 2)通过串行口和网口下载执行目标文件,要求宿主机系统上有数据传输工具程序、目标机装载器、嵌入式监视器或目标机系统上的调试代理。 3)通过jtag或bdm接口下载;,嵌入式系统的初始化过程,嵌入式系统的初始化过程,硬件初始化阶段,1、复位向量 entry b resethandler ;for debug b handlerundef ;handlerundef b handlerswi ;swi interrupt handler b handlerpabort ;handlerpabort b handlerdabort ;handlerdabort b . ;handlerreserved b handlerirq b handlerfiq,嵌入式系统的初始化过程(2),硬件初始化阶段,2、最小硬件初始化,1)设置适当的寄存器,使嵌入式处理器处于一个已知的状态: 获得cpu的类型; 获得或设置cpu的时钟频率。 2)禁止中断和高速缓存 3)初始化内存控制器、内存芯片和高速缓存单元,包括: 得到内存的开始地址; 得到内存的大小; 如果有要求,则还需要进行主存测试;,嵌入式系统的初始化过程(3),硬件初始化阶段,3、其余硬件初始化,1)引导代码调用合适的函数对目标机系统上的全部硬件部件进行初始化,包括: 建立执行处理程序 初始化中断处理程序 初始化总线接口 初始化板级外设得到内存的开始地址;,嵌入式系统的初始化过程(4),rtos初始化阶段,4、rtos初始化,1)rtos初始化 2)rtos对象和服务初始化 任务 信号量 定时器 中断 内存管理 3)rtos任务堆栈初始化 4)rtos扩展部件初始化 5)启动rtos,arm7tdmi系统初始化的一般过程,启动(系统上电/复位),从程序入口点,关闭中断,初始化时钟等硬件相关寄存器,初始化存储器系统,初始化c所需要的存储器空间,调用c入口函数,一、设置程序入口指针,上电复位后直接到程序入口点执行,入口点一般为一个跳转表,跳转到复位处理程序处开始执行arm7tdmi系统的初始化; 启动程序首先必须定义入中指针,而且整个应用程序只有一个入口指针 例:area boot,code,readonly entry /*设置程序入口指针*/,二、设置中断向量,arm要求中断向量必须设置在从ox00000000地址开始,连续8*4字节的地址空间; 向量表包含一系列跳转指令,跳转到相应的中断服务程序; 对各未用中断,使其指向一个含返回指令的哑函数,以防止错误中断引起系统的混乱;,中断向量表,中断向量表的程序,area boot,code,readonly entry b reset_handler b undef_handler b swi_handler b preabort_handler b . ;for reserved interrupt,stop here b irq_handler b fiq_handler,三、初始化时钟和设置相关的寄存器,通过设置时钟控制器来确定cpu的工作频率,设置中断控制寄存器屏蔽中断,四、初始化存储器系统,存储器类型和时序配置(参考芯片手册,设置与内存映射相关的寄存器) 一个复杂的系统可能存在多种存储器类型的接口,需要根据实际的系统设计对此加以正确配置。对同一种存储器类型来说,也因为访问速度的差异,需要不同的时序设置。 通常flash 和sram 同属于静态存储器类型,可以合用同一个存储器端口; 而dram 因为动态刷新和地址线复用等特性,通常配有专用的存储器端口。 存储器端口的接口时序优化是非常重要的,影响到整个系统的性能。因为一般系统运行的速度瓶颈都存在于存储器访问,所以存储器访问时序应尽可能地快;但同时又要考虑由此带来的稳定性问题。只有根据具体选定的芯片,进行多次的测试之后,才能确定最佳的时序配置。,存储器地址分布,有些系统具有非常灵活的存储器地址分配特性,进行存储器初始化设计的时候一定要根据应用程序的具体要求来完成地址分配。 一种典型的情况是启动rom 的地址重映射(remap)。当一个系统上电后程序将自动从0 地址处开始执行,因此在系统的初始状态,必须保证在0 地址处存在正确的代码,即要求0 地址开始处的存储器是非易性的rom 或flash 等。但是因为rom 或flash 的访问速度相对较慢,每次中断发生后都要从读取rom 或flash 上面的向量表开始,影响了中断响应速度。因此有的系统便提供一种灵活的地址重映射方法,可以把0 地址重新指向到ram 中去。在这种地址映射的变化过程当中,程序员需要仔细考虑的是程序的执行流程不能被这种变化所打断。,rom地址的重映射,rom地址重映射的实现,mov r8,#ram_base_boot /ram_base_boot是重映射前内部ram区地址 add r9, pc,#-(8+.-vectortable) /vectortale是异常向量表入口 ldmia r9!, r0-r7 /读8个异常向量 stmia r8!, r0-r7 /保存8个异常向量到ram区 ldmia r9!, r0-r4 /读5个异常处理程序绝对地址 stmia r8!, r0-r4 /保存5个异常处理程序绝对地址到ram区,为保证重映射之后提供正确的中断入口地址,在重映射之前就必须把中断和异常向量表拷贝到内部ram中。其程序实现如下:,五、初始化堆栈,arm处理器有好几种运行状态(模式),各种状态都需要有自己的堆栈,所以需要分别为这些堆栈分配空间并设置好各自的堆栈指针 每一种状态的堆栈指针寄存器(sp)都是独立的(system 和user 模式使用相同的sp 寄存器)。因此对程序中需要用到的每一种模式都要给sp 寄存器定义一个堆栈地址。方法是改变状态寄存器cpsr内的状态位,使处理器切换到不同的状态,然后给sp 赋值。(意不要切换到user模式进行user 模式的堆栈设置,因为进入user 模式后就不能再操作cpsr 回到别的模式了。可能会对接下去的程序执行造成影响。) 一般堆栈的大小要根据需要而定,但是要尽可能给堆栈分配快速和高带宽的存储器。堆栈性能的提高对系统整体性能的影响是非

温馨提示

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

评论

0/150

提交评论