32
1 嵌嵌嵌嵌 嵌嵌嵌嵌嵌嵌嵌 ——ARM 嵌 C/OS-嵌嵌嵌 嵌嵌嵌嵌嵌嵌嵌嵌 嵌嵌嵌 嵌嵌嵌嵌嵌嵌嵌嵌

嵌入式系统设计与实例开发 —— ARM 与 C/OS-Ⅱ 第五讲 嵌入式软件的移植

Embed Size (px)

DESCRIPTION

嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植. 第四讲、 嵌入式系统的移植. 移植的概念和目的. 1. 2. 操作系统移植. 3. 软件移植. 4. 5. 一、移植的概念和目的. 移植:程序或应用软件从一个系统平台移动另一个系统平台,其功能、结构、执行结果保持不变。 移植的目的: 1 、硬件平台的升级 2 、实现软件重用 3 、实现软件 / 硬件并行设计 移植的要求: 1 、移植对象具有硬件无关性 2 、移植对象具有系统无关性 3 、移植对象采用标准语言编程. - PowerPoint PPT Presentation

Citation preview

Page 1: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

1

嵌入式系统设计与实例开发——ARM 与 C/OS-Ⅱ

第五讲 嵌入式软件的移植第五讲 嵌入式软件的移植

Page 2: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

2

第四讲、嵌入式系统的移植

1111

3333

2222

5555

4444

操作系统移植

软件移植

移植的概念和目的

Page 3: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

3

移植:程序或应用软件从一个系统平台移动另一个系统平台,其功能、结构、执行结果保持不变。

移植的目的: 1 、硬件平台的升级 2 、实现软件重用 3 、实现软件 / 硬件并行设计

移植的要求: 1 、移植对象具有硬件无关性 2 、移植对象具有系统无关性 3 、移植对象采用标准语言编程

一、移植的概念和目的

Page 4: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

4

二、嵌入式操作系统的移植—— μC/OS-II

μC/OS-II 的软硬件体系结构μC/OS-II 的移植需要满足的要求μC/OS-II 移植的主要工作BSP 的概念及应用

Page 5: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

5

2.1 μC/OS-II 的软硬件体系结构

Page 6: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

6

2.2 μC/OS-II 的移植需要满足以下要求

( 1 )处理器的 C 编译器可以产生可重入代码;

( 2 )可以使用 C 调用进入和退出 Critical Code( 临界区代码 ) ;

( 3 )处理器必须支持硬件中断,并且需要一个定时中断源;

( 4 )处理器需要能够容纳一定数据的硬件堆栈;

( 5 )处理器需要有能够在 CPU 寄存器与内存和堆栈交换数据的指令。

Page 7: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

7

打开 / 关闭中断

在 COS-II 中,可以通过:

OS_ENTER_CRITICAL ()

OS_EXIT_CRITICAL()

宏来控制系统关闭或者打开中断。这需要处理器的支持。

在 ARM7TDMI 的处理器上,可以设置相应的寄存器来关闭或者打开系统的所有中断。

Page 8: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

8

处理器支持中断并且能产生定时中断

COS-II 是通过处理器产生的定时器的中断来实现多任务之间的调度的。 ARM7TDMI 的处理器上可以产生定时器中断。

本系统工作在 60MHz 的主频下,定时器的中断的频率为1000Hz 。也就是系统的响应时间为 1ms 。

Page 9: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

9

处理器支持硬件堆栈

COS-II 进行任务调度的时候,会把当前任务的 CPU 寄存器存放到此任务的堆栈中,然后,再从另一个任务的堆栈中恢复原来的工作寄存器,继续运行另一个任务。所以,寄存器的入栈和出栈是 COS-II 多任务调度的基础。

ARM7 处理器中有专门的指令处理堆栈,可以灵活的使用堆栈。

Page 10: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

10

2.3 μC/OS-II 移植的主要工作

处理器和编译器相关代码

μC/OS-II 的 BSP 的编写

Page 11: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

11

COS-II 在 S3C44B0X 上的移植

设置 OS_CPU.H 中与处理器和编译器相关的代码 用 C 语言编写六个操作系统相关的函数( OS_CPU_C.C ) 用汇编语言编写四个与处理器相关的函数( OS_CPU.ASM )

Page 12: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

12

·OS_CPU.H 中需要设置一个常量来标识堆栈增长方向;

·OS_CPU.H 中需要声明几个用于开关中断和任务切换的宏;

·OS_CPU.H 中需要针对具体处理器的字长重新定义一系列数据类型;

·OS_CPU_A.ASM 需要改写 4 个汇编语言的函数;

·OS_CPU_C.C 需要用 C 语言编写 6 个简单函数;

Page 13: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

13

设置与处理器和编译器相关的代码

OS_CPU.H 中定义了与编译器相关的数据类型。比如:INT8U 、 INT8S 等。

与 ARM 处理器相关的代码,使用

OS_ENTER_CRITICAL() 和

OS_EXIT_CRITICAL() 宏开启/关闭中断设施堆栈的增长方向 :堆栈由高地址向低地址增长

Page 14: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

14

用 C 语言编写六个操作系统相关的函数

void *OSTaskStkInit (void (*task)(void *pd),void *pdata, void *ptos, INT16U opt)

void OSTaskCreateHook (OS_TCB *ptcb)

void OSTaskDelHook (OS_TCB *ptcb)

void OSTaskSwHook (void)

void OSTaskStatHook (void)

void OSTimeTickHook (void)

后 5 个函数为钩子函数,可以不加代码

Page 15: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

15

用汇编语言编写四个与处理器相关的函数

OSStartHighRdy()

OSCtxSw()

OSIntCtxSw()

OSTickISR()

Page 16: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

16

实现方法

在每个硬件时钟到来后, μC/OS-II 会在中断服务例程中调用 OSIntCtxSw ()进行任务调度;另外,当某个任务因等待资源而被挂起时,没有必要等到自己的时间片全都用完,可以自己主动放弃 CPU ,这可以通过调用一个任务级的任务调度函数 OSCtxSw()来实现。

其中相对复杂的是 OSIntCtxSw() 。由于 OSTickISR ()调用了OSIntExit (), OSIntExit ()又再次调用了 OSIntCtxSw() ,如果进行任务切换,那么两次调用都不会返回,而不同的 C 编译器、不同的编译选项处理 C 调用时对堆栈的使用也不尽相同。因此 OSIntCtxSw() 是编译器相关的。

Page 17: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

17

μC/OS-II 任务堆栈初始化

μC/OS-II 中每个任务都有自己的任务堆栈,在任务创建初期由 OSTaskStkInit ()初始化。初始化堆栈的目的就是模拟一次中断。任务堆栈中保存了任务代码的起始地址和一些 CPU 寄存器(初值是无关紧要的),这样一旦条件满足,就可以执行该任务了。

Page 18: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

18

2.4 μC/OS-II BSP 编写

BSP(板级支持包)是介于底层硬件和操作系统之间的软件层次,它完成系统上电后最初的硬件和软件初始化,并对底层硬件进行封装,使得操作系统不再面对具体的操作。

BSP的特点: 硬件相关性:因为嵌入式实时系统的硬件环境具有应用相关性,

所以,作为高层软件与硬件之间的接口, BSP 必须为操作系统提供操作和控制具体硬件的方法。

操作系统相关性:不同的操作系统具有各自的软件层次结构,因此,不同的操作系统具有特定的硬件接口形式。

Page 19: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

19

BSP 的功能

操作系统初始化

A 、片级初始化

B 、板级初始化

C 、系统级初始化

硬件相关的设备驱动程序

Page 20: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

20

嵌入式系统初始化过程及 BSP 功能

Page 21: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

21

系统调用通用设备驱动程序与 BSP 的关系

Page 22: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

22

设计 BSP 的方法

一、以典型的 BSP做为参考

二、参照操作系统或芯片厂商提供的 BSP模板

Page 23: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

23

μC/OS-II BSP for ARM

μC/OS-II 编写一个简单的 BSP 。它首先设置 CPU 内部寄存器和系统堆栈,并初始化堆栈指针,建立程序的运行和调用环境;

然后可以方便地使用 C 语言设置 ARM片选地址( CS0~ CS7)、 GPIO 以及 SDRAM 控制器,初始化串口( UART0 )作为默认打印口,并向操作系统提供一些硬件相关例程和函数如 dprintf() ,以方便调试;

在 CPU 、板级和程序自身初始化完成后,就可以把 CPU 的控制权交给操作系统了

Page 24: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

24

二、向嵌入式平台移植软件

  大部分嵌入式开发人员选用的软件开发模式是先在 PC机上编写软件,再进行软件的移植工作。在 PC机上编写软件时,要注意软件的可移植性。

1 、选用具有较高移植性的编程语言(如 C 语言)

2 、尽量少调用操作系统函数

3 、注意屏蔽不同硬件平台带来的字节顺序、字节对齐等问题。

Page 25: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

25

字节顺序

  字节顺序是指占内存多于一个字节类型的数据在内存中的存放顺序,通常有小端、大端两种字节顺序。小端字节序指低字节数据存放在内存低地址处,高字节数据存放在内存高地址处;大端字节序是高字节数据存放在低地址处,低字节数据存放在高地址处。基于 X86平台的 PC机是小端字节序的,而有的嵌入式平台则是大端字节序的。因而对 int 、 uint16、 uint32 等多于 1 字节类型的数据,在这些嵌入式平台上应该变换其存储顺序。

通常我们认为,在空中传输的字节的顺序即网络字节序为标准顺序,考虑到与协议的一致以及与同类其它平台产品的互通,在程序中发数据包时,将主机字节序转换为网络字节序,收数据包处将网络字节序转换为主机字节序。

Page 26: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

26

字节对齐

  有的嵌入式处理器的寻址方式决定了在内存中占 2 字节的 int16、 uint16等类型数据只能存放在偶数内存地址处,占 4 字节的 int32 、 uint32 等类型数据只能存放在 4 的整数倍的内存地址处;占8字节的类型数据只能存放在 8的整数倍的内存地址处;而在内存中只占 1 字节的类型数据可以存放在任意地址处。由于这些限制,在这些平台上编程时有很大的不同。首先,结构体成员之间会有空洞,比如这样一个结构:

typedef struct test{char a;uint16 b;}TEST

  结构 TEST在单字节对齐的平台上占内存三个字节,而在以上所述的嵌入式平台上有可能占三个或四个字节,视成员 a 的存储地址而定。当 a 存储地址为偶数时,该结构占四个字节,在 a 与 b之间存在一个字节的空洞。对于通信双方都是对结构成员操作的,这种情况不会出错,但如果有一方是逐字节读取内容的(通信协议大都如此),就会错误地读到其它字节的内容。其次,若对内存中数据以强制类型转换的方式读取,字节对齐的不同会引起数据读取的错误。因为假如指针指在基数内存地址处,我们想取得占内存两个字节的数据存放在uint16型的变量中,强制类型转换的结果是取得了该指针所指地址与前一地址处的数据,并没有按照我们的愿望取该指针所指地址与后一地址处的数据,这样就导致了数据读取的错误。

Page 27: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

27

位 段

  由于位段的空间分配方向因硬件平台的不同而不同,对 X86平台,位段是从右向左分配的;而一些嵌入式平台,位段是从左向右分配的。分配顺序的不同导致了数据存取的错误。解决这一问题的一种方法是采用条件编译的方式,针对不同的平台定义顺序不同的位段;也可以在前面所述的两个函数中加上对位段的处理。

Page 28: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

28

代码优化的问题

  嵌入式系统对应用软件的质量要求更高,因而在嵌入式开发中尤其须注意对代码进行优化,尽可能地提高代码的效率,减少代码的大小。虽然现代 C 和 C++编译器都提供了一定程度的代码优化,但大部分由编译器执行的优化技术仅涉及执行速度和代码大小的平衡,不可能使程序既快又小,因而必须在编写嵌入式软件时采取必要的措施。

Page 29: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

29

( 1 )提高代码的效率

  ① switch-case 语句。在程序中经常会使用 switch-case 语句,每一个由机器语言实现的测试和跳转仅仅是为了决定下一步要做什么,就浪费了处理器时间。为了提高速度,可以把具体的情况按照它们发生的相对频率排序。即把最可能发生的情况放在第一,最不可能发生的情况放在最后,这样会减少平均的代码执行时间。

  ② 全局变量。使用全局变量比向函数传递参数更加有效率,这样做去除了函数调用前参数入栈和函数完成后参数出栈的需要。当然,使用全局变量会对程序有一些负作用。

Page 30: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

30

( 2 )减小代码的大小

  嵌入式系统编程应避免使用标准库例程,因为很多大的库例程设法处理所有可能的情况,所以占用了庞大的内存空间,因而应尽可能地减少使用标准库例程。

Page 31: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

31

( 3 )避免内存泄漏

  用户内存空间(堆)为 RAM 中全局数据和任务堆栈空间都分配后的剩余空间,为了使程序能有足够的内存运行,必须在申请的内存不用后及时地将其释放,以确保再次申请时能有空间。如果程序中存在内存泄漏(即申请内存后没有及时释放)的情况,程序最终会因为没有足够的内存空间而无法运行。

Page 32: 嵌入式系统设计与实例开发 —— ARM 与  C/OS-Ⅱ 第五讲 嵌入式软件的移植

32

谢 谢 各 位谢 谢 各 位