ucosII的移植

一、引言

随着国内外工业化、数字化的步伐加快,嵌入式开发在IT行业中的重要性越来越显著。嵌入式系统也以其体积小、功耗低、性能高的优点得到了人们的广泛关注。嵌入式操作系统作为嵌入式软件运行的平台,负责管理各个进程间的创建、删除以及任务调度,统一管理系统的软硬件资源,因此进行嵌入式开发,首先要实现嵌入式操作系统在相关处理器上的移植,再以次为基础开发相应的应用软件。本文以公开源码的μC/OS-Ⅱ嵌入式实时操作系统为例,描述了该嵌入式实时操作系统在LPC2214上的移植,从而构成了一个软硬件都非常强大的开发平台,并以此为基础,建立了一个浮子式液位测量系统,来说明μC/OS-Ⅱ在嵌入式系统中的应用。

二、 μC/OS-Ⅱ在LPC2214上的移植

2.1  μC/OS-Ⅱ简介

μC/OS-Ⅱ是一个免费的、源码公开的、完整的、可移植、可固化、可剪裁的抢占式实时多任务内核,它提供了嵌入式系统所需的基本功能。μC/OS- Ⅱ已经在全世界范围内得到广泛应用,包括诸多领域,如手机、路由器、医疗设备与工业控制等,并且它还通过了美国航空管理局的认证,可以用在飞行器上,这充分说明了μC/OS- Ⅱ的稳定可靠性。应用μC/OS- Ⅱ进行开发,具有提高系统的实时响应速度、有利于软件设计的模块化、提高系统的整体性能以及提高抗干扰能力等突出优点。嵌入式系统的构成如图1所示。

2.2ARM微处理器LPC2214

LPC2214是一个基于实时仿真和跟踪的16/32位ARM7TDMI-S CPU的微处理器,并自带有256字节(KB)嵌入的高速Flash存储器,16K字节静态RAM。处理器内部包含有与片内存储器控制器接口的ARM7局部总线,与中断控制器接口的AMBA高性能总线(AHB)以及连接片内外设的VLSI外设总线。

AHB外设分配了2M字节的地址范围,它位于4G字节存储器空间的最顶端,其地址范围为0xFFE00000~0xFFFFFFFF,每个AHB外设都分配了16K字节的地址空间。LPC2214的外设都连接到VPB总线,VPB外设也分配了2M字节的地址范围,其地址范围为0xE0000000~0xE01FFFFF,同样每个VPB外设在VPB地址空间内都分配了16K字节的地址空间。

片内外设与器件管脚的连接由管脚连接模块控制。该模块必须由软件进行控制以符合外设功能与管脚在特定应用中的需求。

图1  嵌入式系统框架图

2.3 μC/OS- Ⅱ的移植

所谓移植,就是使一个实时内核能在其他的微处理器或微控制器上运行。要使μC/OS- Ⅱ正常运行,处理器必须满足以下要求:

◆处理器的C编译器能产生可重入型代码;

◆处理器支持中断,并且能够产生定时中断;

◆用C语言就可以开、关中断;

◆处理器能支持一定数量的输出存储硬件堆栈;

◆处理器有将堆栈指针以及其他CPU寄存器的内容读出、并存储到堆栈或内存中的指令。

LPC2214可以满足以上的全部要求,因此μC/OS- Ⅱ可以在LPC2214上移植并且正常运行。μC/OS- Ⅱ的体系结构以及它与系统硬件之间的关系见图2。

图2  μC/OS- Ⅱ硬件与软件结构图

图2中的应用程序软件是用户根据需求编写的可实现系统功能的程序代码,通过定制合适的内核服务功能,实现对μC/OS- Ⅱ的裁减,图中与处理器无关部分的代码就是操作系统的内核,移植完操作系统后,所有的系统服务均需通过调用系统内核进行,内核将应用程序与底层硬件相结合,构成一个实时操作系统。μC/OS- Ⅱ的内核代码是完全公开的,本文采用了μC/OS- Ⅱv2.52版本,代码由参考文献[2]的随书光盘提供。图2中与处理器相关代码可以看作是内核和硬件之间的中间层,它实现同一内核与不同硬件体系的目标,处理器不同,代码也不同,需要用户自行编写。μC/OS- Ⅱ的移植工作主要是完成该部分代码的编写,该部分代码由三个文件构成,三个文件分别是OS_CPU.H,OS_CPU_A.ASM,OS_CPU_C.C。下面以μC/OS- Ⅱ在LPC2214上的移植为例进行探讨,介绍移植过程中的主要步骤和需要修改的部分。开发工具选用ARM公司提供的ADS1.2集成开发环境。

OS_CPU.H

该文件中主要包括了数据类型、堆栈入口宽度、堆栈增长方向、开关中断的宏和进行任务切换的宏定义。由于C语言中short,int,和long等数据类型与处理器字长及编译器相关,是不可移植的,因此在OS_CPU.H中需对这些数据类型定义,以保证其可移植性。

移植需要修改的内容如下:

typedef unsigned char  BOOLEAN;           /* 布尔变量*/

typedef unsigned char  INT8U;               /* 无符号8位整型变量*/

ypedef signed   char  INT8S;                /* 有符号8位整型变量*/

typedef unsigned short INT16U;               /* 无符号16位整型变量*/

typedef signed   short INT16S;               /* 有符号16位整型变量*/

typedef unsigned int   INT32U;               /* 无符号32位整型变量*/

typedef signed   int   INT32S;              /* 有符号32位整型变量*/

typedef float          FP32;                /* 单精度浮点数(32位长度)*/         typedef double         FP64;               /* 双精度浮点数(64位长度)*/        

#define  INT32U  OS_STK                 /* 堆栈是32位宽度 */

#define OS_CRITICAL_METHOD   2        /*选择中断方式*/

#define OS_STK_GROWTH  1              /*定义堆栈增长方向*/

其中需要注意的是OS_STK_GROWTH必须定义为1,即堆栈增长方向为从高地址向低地址递减,因为ADS编译器仅支持该种方式。

此外,本移植使用软件中断指令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);      /*开中断*/

OS_CPU_A.ASM

该部分需要对处理器的寄存器进行操作,因此必须用汇编语言来编写,该文件需要修改三个与处理器相关的函数,分别是:

OSStartHighRdy( ):最高优先级任务调用函数;

OSCtxSw( ):任务切换函数;

OSIntCtxSw( ): 中断任务切换函数;

OSStartHighRdy( )通过OSStart( )进行调用,在启动多任务函数OSStart( )之前,系统需建立至少一个任务,随后OSStart( )调用OSStartHighRdy( )函数,使就绪态任务中优先级最高的任务开始运行。

OSCtxSw( )函数由任务级任务切换函数OS_TASK_SW调用,实现由低优先级任务向高优先级任务切换。在本移植中,任务级切换是通过SWI软中断来实现的。该中断完成如下操作:保存当前任务环境;载入最高优先级任务的堆栈指针,恢复最高优先级任务环境;中断返回。

OSIntCtxSw( )函数在中断退出时由函数OSIntExit( )调用,在中断服务程序中,当有更高优先级任务被建立,则在中断退出时,OSIntCtxSw( )不返回原先被中断任务,而是直接调度最高优先级任务执行,保证系统的实时性。OSIntCtxSw( )函数基本原理与OSCtxSw( )函数相同,区别在于,在进入中断时,中断服务程序已经保存了被中断任务的环境,则在OSIntCtxSw( )就不需要执行类似操作,实际上如果需要,可以跳转到OSCtxSw( )中相同的代码,以减少代码量。

如需要源代码,请发邮件至tiger6835@sina.com索取。

OS_CPU_C.C

该部分需要用C语言编写10个简单的C函数,分别是:OSTaskStkInit();OSTaskCreateHook( );OSTaskDelHook( );OSTaskSwHook( ); OSTaskIdleHook( );OSTaskStatHook( ); OSTimeTickHook( );OSInitHookBegin( );OSInitHookEnd( );OSTCBInitHook( );

其中OSTaskStkInit( )为堆栈初始化函数,必须根据具体的堆栈结构进行编写,只要用户确定了任务的堆栈结构,可以很容易写出OSTaskStkInit( )函数。OSTaskCreate()和OSTaskCreateExt( )通过调用该函数,初始化任务的堆栈结构。其余9个函数为钩子函数,必须声明,单不一定要包含任何代码,可以为空函数,在本移植中无修改。

三、μC/OS- Ⅱ嵌入式系统的应用

进行完上述的工作后,μC/OS- Ⅱ就可以正常运行ARM微处理器LPC2214上了,在此基础上,笔者构建了一个浮子式液位测量系统,整个系统分为了几个主要模块,分别是:键盘输入和数码管显示模块、上位机通讯模块、数据采集处理模块,键盘输入和数码管显示模块采用了ZLG7290芯片通过I2C总线与LPC2214进行通讯,上位机通讯模块通过一片MAX3232与PC机通讯,数据采集模块采用了MAX3491全双工RS422/485转换芯片与海德汉出产的ROQ425绝对编码器进行通信,采集数据。通过μC/OS- Ⅱ中的OSTaskCreate( )函数创建了三个任务以对应三个主要模块,并赋予了不同的任务优先级,其中数据采集模块的任务优先级为最高。数据采集模块电路原理图如下:

图3  数据采集模块原理图

四、结语

论文成功移植了μC/OS- Ⅱ操作系统至LPC2214微处理器,并在此基础上实现了一个基于ARM处理器的浮子式液位测量系统,与传统的液位计相比,采用ARM处理器的浮子式液位计功能更加强大,且性能更加可靠。相信随着ARM体系的不断发展,嵌入式系统的应用将越来越广泛。

本文作者创新点:在移植中采用软中断指令SWI作为底层接口,使用不同的功能号区分不同的函数,这样使得底层接口函数与处理器状态无关,即无论处理器是处于ARM指令集还是Thumb指令集下时,或系统模式或用户模式,都可通过调用SWI软中断实现任务切换,大大简化了移植代码。

参考文献:

[1]  周立功等. ARM微控制器基础与实验. 广州周立功单片机发展有限公司, 2003.8

[2]  JENAJ.LABROSSE著, 邵贝贝等译. 嵌人式实时操作系统μC/OS- Ⅱ[M]. 北京:北京航空航天大学出版社, 2003.5

[3]  李明. μC/OS- Ⅱ在ARM上的移植[J]. 电子设计应用, 2003,4:24~26

[4]  王芳等. 基于μC/OS- Ⅱ嵌入式系统构件的研究与设计. 微计算机信息, 2007,3:65~67

/*********************** (C) COPYLEFT 2010 Leafgrass *************************/ This project runs on uC/OS-II V2.52 and is based on STM32F103RBT6(ARM Cortex-M3 Core) Take care of the configuration of project. There're some Include Paths while linking which cannot be modified. Procedure of driving a device(IMPORTANT!!!): 1.Connect hardware correctly. 2.Prepare DEVICE_NAME.h and DEVICE_NAME.c. 3.Enable clock of related components. 4.Enable related interrupt while configure NVIC. 5.Configure related IO pins. 6.Finish test code and begin testing. 2010-06-10( original ): Sucessfully port uCOS-II V2.52. 2010-06-11: Add code "SysTick_CounterCmd(SysTick_Counter_Enable);" in SysTick_Configuration(), solve the problem that the program can't get into SysTickHandler(), as below: /******************************************************************************* * Function Name : SysTick_Config * Description : Configures SysTick * Input : None * Output : None * Return : None *******************************************************************************/ void SysTick_Configuration(void) { NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 0, 1); /* Configure HCLK clock as SysTick clock source */ SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); /* SysTick interrupt each 1000 Hz with HCLK equal to 72MHz */ SysTick_SetReload(9000); /* Enable the SysTick Interrupt */ SysTick_ITConfig(ENABLE); SysTick_CounterCmd(SysTick_Counter_Enable); //Important!! Solve "the program can't get into SysTickHandler()!! } 2010-06-12( updates to V1.0 ): 1. Add EXTI8, EXTI9 on PC8, PC9, only for EXTI test. 2. Modify some comments in LCD5110_lib. 3. (in main.c) Modifiy tasks' priority LED_TASK_Prio 1 -> 5 START_TASK_Prio 2 -> 10 4. (in main.c) Modify code "OSTaskDel(START_TASK_Prio);" to "OSTaskSuspend(START_TASK_Prio);" 2010-07-13 1.Drive LTM022A69B LCD ok. Just use I/O to imitate SPI. Still cannot use internal SPI to drive it. 2.Move LCD library of LTM022A69B into "LCD_lib.c". 2010-07-15: Add color bar display in LCD_test(). 2010-07-16( updates to V1.1 ): 1.Solve problem about position error and color error, when display a set of 16-bit color data. Mainly resulted from CPU type, big endian or little endian. STM32F103RBT6 is little endian while in default set. 2.Add Draw_img(); 3.Add colorful characters and strings, add parameters about colors in display functions.(colors are defined in LTM022A69B.h) 2010-07-17: 1.Add comments in LCD_Init(). 2.Add parameter "color" to function Draw_dot(). 3.Add function SetCursor(). 4.Unify LCD related functions' name. Add prefix "LCD_". 2010-07-19: Modify data type in LCD_Lib. normal --> const. At one time, modify the pointers type to const. 2010-07-20: 1.Correct the error that OSTimeDlyHMSM() can't delay an accurate time, by modifying SysTick_Configuration() to get an correct clock frequency. 2010-07-31: Add STM32_Init.c but is not referenced, for future use of Configuration Wizard. 2010-08-01: Configure SPI ok, and do some test(SPI2 tx -> SPI1 rx, display on LCD). 2010-08-03: 1.Add SPI test code in main.c, SPI2 send data, SPI1 receive data , display info on LCD, use soft SPI. 2.Add exported macro "USESPI" to choose if use SPI to drive LCD or not. 3.After several days researching about hard SPI to drive LCD, failed. So switch to use a faster GPIO method, as below: Replace "#define LCD_RST_H() GPIO_SetBits(LCD_CTRL_PORT, LCD_RST)" in ST library with "#define LCD_RST_H() ( LCD_CTRL_PORT->BSRR = LCD_RST )" for a faster LCD refresh speed. 4.Modify name "LCD_SCI" to "LCD_SI", 'cause it means Serial Interface. 5.Modify function name "LCD_test()" to "LCD_Test()". 2010-08-06: Comment off "typedef enum {FALSE = 0, TRUE = !FALSE} bool;" in stm32f10x.type.h in order to avoid warning. 2010-08-09: Prepare to update to v2.0. 2010-08-10( Update to v2.0, use ST's FWLib3.1.2 ): 1. Set project(Keil RealView MDK). (1) RO memory area : IROM1 -- start at 0x08000000, size 0x20000. (2) RW memory area : IRAM1 -- start at 0x20000000, size 0x5000. (3) Output setup. (4) Listing setup, no assembler list. (5) C/C++ setup. Preprocessor Symbols : Define -- USE_STDPERIPH_DRIVER, STM32F10X_MD. Include Paths : ..\; ..\..\Libraries\CMSIS\Core\CM3; ..\..\Libraries\STM32F10x_StdPeriph_Driver\inc; ..\..\App; ..\..\Driver; ..\..\OS; ..\..\OS\port (6) Linker, Use memory layout from target dialog. (7) Debug and Utilities, Cortex-M/R J-Link/J-Trace. Disable Trace. 2. Modify code in "includes.h". 3. Modify startup code, did not use the st original one. Port those used in FWLib2.0 instead. Of course, some code are revised for FWLib3.1.2(StdPeriph_Driver and CMSIS). Mainly rewrite the names of the ISR. The most important two are : "PendSV_Handler" and "SysTick_Handler". ---> "OSPendSV" and "SysTick_Handler". (in "os_cpu_a.asm") (in "stm32f10x_it.c") 4. Modify initial code for SysTick in "SysTick_Configuration()" in "CPU_Init.c" because of the changing of library. Note : A general problem is that program always go into "B OSStartHang" in "OSStartHighRdy" in "os_cpu_a.asm", and will die in there... That's caused by program hasn't step into the correct ISR yet. Enable the SysTick interrupt, check if the name of Interrupt Service Routines are right, then all will be OK. 5. Still some problem with retargeting "printf()". If use "printf()" in program, system wouldn't run. 6. Change Project name to "RTOS_STM32". 2010-08-11( Update to v2.1, use ST's FWLib3.3.0 ): 1. Modify Include Path in Target Options. 2. Comment "typedef enum {FALSE = 0, TRUE = !FALSE} bool;" off in order to avoid error: "..\stm32f10x.h(454): error: #40: expected an identifier". 2010-08-12( Update to v2.2 ): 1. Remove the incorrect use of SPI in LCD display, add a new schedule( maily used SPI busy flag ). 2. Commen off code "assert_param(IS_SPI_ALL_PERIPH(SPIx));" in "SPI_I2S_SendData()", "SPI_I2S_ReceiveData()", and "SPI_I2S_GetFlagStatus" in "stm32f10x_spi.h", in order to improve LCD refresh frequency. 3. Finish to retarget C library printf() to UART. As a foundation, change the setup of KEIL in "Target Options" --> "Code Generation" --> tick "Use MicroLIB". There are still some problem with building, modify a few lines in "stm32f10x_startup.s" : ================================ IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ELSE IMPORT __use_two_region_memory EXPORT __user_initial_stackheap ================================ Then rebuild. Add retarget code in main.c : ================================================================ #ifdef __GNUC__ // With GCC/RAISONANCE, small printf // (option LD Linker->Libraries->Small printf set to 'Yes') // calls __io_putchar() #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif // __GNUC__ ---------------------------------------------------------------- PUTCHAR_PROTOTYPE { // Place your implementation of fputc here // e.g. write a character to the USART USART_SendData(USARTx, (u8)ch); // Loop until the end of transmission while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {} return ch; } ================================================================ 2010-08-14(update to v2.3): 1. Rewrite the different part of code into its C file. 2. Drive TIM3 output PWM wave successfully. 3. Add "servo" file, for servo control. 2010-08-19(update to v2.4, GPS data receive ok): 1. Add "gps" file. 2. Add code in "USART3_IRQHandler()", mainly to receive data from GPS. But there's still someting confusing, that the pair "USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);" and "USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);" cannot work well. Because once use them, some data will be lost. 2010-08-22: Refresh firmware of GPS, modify to Baudrate 9600, China timezone, WGS-84 coordinate. 2010-09-02: Replace those two old startup files "cortexm3_macro.s" and "stm32f10x_startup.s" with the one "startup_stm32f10x_md.s" which is created by MCD Application Team in FWLib3.3.0. 2010-09-13: 1. Add general_task.h and .c for miscellaneous experimental purpose. 2. Add uart output infomation in booting stage. 3. Add macro "LED_TOGGLE()" use "(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_1))" 4. Create Logo: _ _ / / | | ___ __ _ _| |_ __ _ _ __ __ _ _ _ | | / _ \/ _` |_ _/ _` | \/ _)/ _` | / / / / | |_ _ __( (_| | | | (_| | | | ( (_| | \ \ \ \ |_ _ _\___|\__,_| | | \__, / | | \__,_| /_/ /_/ /_/ \_ _/ 5. EXTI again. setup procedure: GPIO IN FLOATING -> NVIC IRQ -> EXTI Config -> _it.c /*********************** (C) COPYLEFT 2010 Leafgrass *************************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值