基于Cortex-M0的UCOS移植

来源:互联网 发布:php函数strip tags 编辑:程序博客网 时间:2024/05/16 07:20

上个星期突然想做一下ucos在cortex-m0平台上的移植,所以就看cortex-m0的内核架构和指令集,接着就开始着手移植了。先说明一下,我的开发板是新唐(Nuvoton)的NuTiny-EVB M051,芯片是M0516LAN。

 

可以分两步走。第一步,移植ucos的底层代码。第二步,建立新任务。

 

第一步:移植ucos就是修改这么几个文件:os_cpu_c.c , os_cpu.h , os_cpu_a.asm

其中,os_cpu.h主要是定义数据类型的定义,和有关处理器的一些设置,如栈的生长方向,进入临界代码段的方式,数据存储的大小端设置等等。

 

1. os_cpu.h:

 1.1 定义好数据类型。这个简单,所以不用怎么说。

1.2 定义进行临界代码段的方式,我定义为方式3。即进入时保存PSR,然后关中断,出来是恢复PSR的值。

对应的函数为:OS_CPU_SR  OS_CPU_SR_Save(void), void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr)

1.3 定义栈的生长方向。我定义为从高向下生长的方向。

1.4 函数的声明。这里有5个函数需要声明。分别是:

void OSCtxSw(void)

void OSIntCtxSw(void)

void OSStartHighRdy(void)

OS_CPU_SR  OS_CPU_SR_Save(void)

void OS_CPU_SR_Restore(OS_CPU_SR cpu_sr)

由于OSIntCtxSw和OSCtxSw代码可以一致,所以只定义OSCtxSw。

 

1.5 具体代码如下:

#ifndef OS_CPU_H#define OS_CPU_H#ifdef OS_CPU_GLOBALS#define OS_CPU_EXT#else#define OS_CPU_EXT extern#endif#ifndef OS_CPU_EXCEPT_STK_SIZE#define OS_CPU_EXCEPT_STK_SIZE 1 /* Default exception stack size is 128 OS_STK entries */#endiftypedef unsigned char BOOLEAN;typedef unsigned char INT8U; /* Unsigned 8 bit quantity */typedef signed char INT8S; /* Signed 8 bit quantity */typedef unsigned short INT16U; /* Unsigned 16 bit quantity */typedef signed short INT16S; /* Signed 16 bit quantity */typedef unsigned int INT32U; /* Unsigned 32 bit quantity */typedef signed int INT32S; /* Signed 32 bit quantity */typedef float FP32; /* Single precision floating point */typedef double FP64; /* Double precision floating point */typedef unsigned int OS_STK; /* Each stack entry is 32-bit wide */typedef unsigned int OS_CPU_SR; /* Define size of CPU status register (PSR = 32 bits) */#define OS_CRITICAL_METHOD 3#if OS_CRITICAL_METHOD == 3#define OS_ENTER_CRITICAL() {cpu_sr = OS_CPU_SR_Save();}#define OS_EXIT_CRITICAL()   {OS_CPU_SR_Restore(cpu_sr);}#endif#define OS_STK_GROWTH 1 /* Stack grows from HIGH to LOW memory on ARM */#define OS_TASK_SW() OSCtxSw()#if OS_CRITICAL_METHOD == 3 OS_CPU_SR OS_CPU_SR_Save (void);void OS_CPU_SR_Restore (OS_CPU_SR cpu_sr);#endifvoid OSCtxSw (void);           void OSStartHighRdy (void);

#define OSIntCtxSw()         OSCtxSw();#endif

 

2. os_cpu_c.c

2.1 定义函数OSTaskStkInit(),对于其它的函数可以不用理,因为如果你不需要用到钩子函数的话,是不用实现的。

OSTaskStkInit()主要初始化各个任务的栈。

2.2 由于cortex-m0的架构决定,当产生异常(包括中断)时,进栈的顺序如下:(这是Full descending的模式)

XXX<---SP before exception

xPSR 

PC

LR

R12

R3

R2

R1

R0    <--SP after before exception

2.3 代码如下:

OS_STK *OSTaskStkInit (void (*task)(void *p_arg), void *p_arg, OS_STK *ptos, INT16U opt){ OS_STK *stk; (void)opt;   // 'opt' is not used, prevent warning stk = ptos; // Load stack pointer /* Registers stacked as if auto-saved on exception */ *(--stk) = (INT32U)0x01000000L; // xPSR *(--stk) = (INT32U)task;      // Entry Point (PC) *(--stk) = (INT32U)0xefefefefL;      // LR *(--stk) = (INT32U)0x12121212L;  // R12 *(--stk) = (INT32U)0x03030303L; // R3 *(--stk) = (INT32U)0x02020202L; // R2 *(--stk) = (INT32U)0x01010101L; // R1 *(--stk) = (INT32U)p_arg;       // R0 : argument /* Remaining registers saved on process stack */ *(--stk) = (INT32U)0x07070707L; //R7 *(--stk) = (INT32U)0x06060606L; // R6 *(--stk) = (INT32U)0x05050505L; // R5 *(--stk) = (INT32U)0x04040404L; // R4 *(--stk) = (INT32U)0x11111111L; // R11 *(--stk) = (INT32U)0x10101010L; // R10 *(--stk) = (INT32U)0x09090909L;  // R9 *(--stk) = (INT32U)0x08080808L; // R8 return (stk);}

 

 

3. os_cpu_a.asm

 

这个文件是对头文件 os_cpu.h所定义的函数进行实现。都是汇编代码,不过不是很难懂。

 

;2011-05-23 xiaoben

 EXTERN  OSRunning

 EXTERN  OSPrioCur

 EXTERN  OSPrioHighRdy

 EXTERN  OSTCBCur

 EXTERN  OSTCBHighRdy

 EXTERN  OSIntNesting

 EXTERN  OSIntExit

 EXTERN  OSTaskSwHook

 

 

EXPORTOS_CPU_SR_Save

EXPORTOS_CPU_SR_Restore

EXPORTOSStartHighRdy

EXPORTOSCtxSw

EXPORTOSIntCtxSw

AREA os_cpu_asm, CODE, READONLY, ALIGN=2

THUMB

REQUIRE8

PRESERVE8

 

OS_CPU_SR_Save

MRSR0, PRIMASK

CPSIDI

BXLR

 

 

 

OS_CPU_SR_Restore

MSRPRIMASK, R0

BXLR

 

 

 

OSStartHighRdy

    LDR     R0, __OSTaskSwHook  ; Call OSTaskSwHook()

    BLX     R0  

 

    LDR     R0, __OSRunning  ; OSRunning=1

    MOVS    R1, #0x01

    STRB    R1, [R0]   

 

    LDR     R0, __OSTCBHighRdy  ; SP = OSTCBHighRdy->OSTCBStkPtr

    LDR     R1, [R0]

    LDR     R2, [R1]

    MSR     MSP, R2

 ; Restore registers from new task stack

    POP    {R0-R7}  ; Restore R4-R7, R8-R11

    MOV    R11, R3

    MOV    R10, R2

    MOV    R9, R1

    MOV    R8, R0

 

    ADD    SP, #0x10  ; Restore PSR, PC, LR, R12

    POP    {R0-R3}

    MOV    R12, R0

    MOV    LR,R1

    PUSH   {R2}  ; Push PC into stack

    MSR    PSR, R3

     

    SUB    SP, #0x1C  ; Restore R0-R3

    POP    {R0-R3}

    ADD    SP, #0x0C

    CPSIE  I  ; Enable interrupts. NOTE: must not omit!

    POP    {PC}  ; Jump to the task and execute, not return.

 

 

 

 

 

OSCtxSw

CPSIDI  

 ; Save registers into current task stack

SUBSP, #0x20  ; Save R4-R7

PUSH{R4-R7}

ADDSP, #0x30  ; Save PSR, PC, LR, R12, R0-R3

MRS R7, PSR

MOV R6, LR  ; NOTE!

MOV R5, LR

MOV R4, R12

PUSH{R0-R7}  

SUBSP, #0x10  ; Save R8-R11

MOV R3, R11

MOV R2, R10

MOV R1, R9

MOV R0, R8

PUSH{R0-R3}

 ; Save SP in current stask stack

MRSR0, MSP  ; OSTCBCur->OSTCBStkPtr = SP

LDRR1, __OSTCBCur

LDRR2, [R1]

STRR0, [R2]

LDRR0, __OSTaskSwHook  ; Call OSTaskSwHook()

BLXR0

LDRR0, __OSPrioCur  ; OSPrioCur = OSPrioHighRdy

LDRR1, __OSPrioHighRdy

LDRBR2, [R1]

STRBR2, [R0]

LDR R0, __OSTCBCur  ; OSTCBCur = OSTCBHighRdy

LDRR1, __OSTCBHighRdy

LDRR2, [R1]

STRR2, [R0]

LDR R0, [R2]  ; SP = OSTCBHighRdy->OSTCBStkPtr

MSRMSP, R0

 ; Restore registers from new task (with high priority) stack

POP{R0-R7}  ; Restore R4-R7, R8-R11

MOV R11, R3

MOV R10, R2

MOV R9, R1

MOV R8, R0

ADD SP, #0X10  ; Restore PSR, PC, LR, R12

POP{R0-R3}

MSR PSR, R3

PUSH{R2}

MOV LR, R1

MOV R12, R0

SUB SP, #0X1C  ; Restore R0-R3

POP{R0-R3}

ADDSP, #0X0C

CPSIEI  ; Enable interrupts! NOTE: must not omit!

POP{PC}  ; Jump to task and execute, not return

NOP

 

 

 

__OSRunning

    DCD    OSRunning

 

__OSTaskSwHook

    DCD    OSTaskSwHook

 

__OSIntExit

    DCD    OSIntExit

 

__OSIntNesting

    DCD    OSIntNesting

 

__OSPrioCur

    DCD    OSPrioCur

 

__OSPrioHighRdy

    DCD    OSPrioHighRdy

 

__OSTCBCur

    DCD    OSTCBCur

 

__OSTCBHighRdy

    DCD    OSTCBHighRdy

 

    END

 

第二步: 到了这里,整个ucos内核就算移植好了。接下来就要建立任务了。对于任务的建立,与头文件 os_cfg.h有关。我们要在os_cfg.h设置一下有关任务的东西。

1. os_cfg.h里面有很多开关量,对于任务里用不到的东西,比如说信号量、定时器之类的,我们可以把它关掉,以减少系统的内存占有率。对于最低优先级OS_LOWEST_PRIO和最大任务数OS_MAX_TASKS要注意一下。还有OS_TICKS_PER_SEC,关于系统的节拍,也要设置一下,一般100到200之间就可以了。

 

2. 对于任务时钟的节拍,采用cortex-m0的SYSTick来作为节拍源,所以还要加上SysTick的异常处理函数!!!!我在main函数里面添加。

 

3. main函数里面任务的建立。我们先建立一个闪烁的LED任务。代码如下:

 

#include <stdio.h>

 

#include "M051Series.h"

#include "Driver/DrvGPIO.h"

#include "Driver/DrvSYS.h"

#include "ucos_ii.h"

 

 

/* LED 任务相关 */

#define LED_STK_SIZE64

#define TASK_LED_PRIO 10 //不要大于OS_LOWEST_PRIO

 

OS_STK TaskLEDStk[LED_STK_SIZE];      //任务栈

 

void task_led(void *pdata);

 

 

/* 与开发板相关的函数定义 */

void init_target(void);

void init_sys_clock(void);

void init_led(void);

void led_on(void);

void led_off(void);

 

 

 

/* SysTick Exception ISR */

void SysTick_Handler(void)

{

OSIntEnter();

OSTimeTick();

OSIntExit();

}

 

 

/* main */

int main()

{

__disable_irq();

init_target();

 

OSInit();

 

OSTaskCreate( task_led, (void*)0, TaskLEDStk[LED_STK_SIZE-1], TASK_LED_PRIO );

 

OSStart();

return 0;

}

 

 

void task_led(void *pdata)

{

(void)pdata;

while(1)

{

led_on();

OSTimeDlyHMSM(0, 0, 1, 0);

led_off();

OSTimeDlyHMSMj(0, 0, 1, 0);

}

}

 

void init_target(void)

{

init_sys_clock();

init_led();

/* Note: Important */

SysTick_Config(DrvSYS_GetHCLKFreq()/OS_TICKS_PER_SEC-1); //Init system tick

}

 

 

void init_sys_colock(void)

{

UNLOCKREG();// Unlock the protected registersDrvSYS_SetOscCtrl(E_SYS_XTL12M, 1);// Enable the 12MHz oscillator oscillationwhile (DrvSYS_GetChipClockSourceStatus(E_SYS_XTL12M) != 1);// Waiting for 12M Xtal stable

DrvSYS_SelectHCLKSource(0);LOCKREG();// Lock the protected registersDrvSYS_SetClockDivider(E_SYS_HCLK_DIV, 0); // HCLK clock frequency = HCLK clock source / (HCLK_N + 1)

}

 

void init_led(void)

{

DrvGPIO_Open(E_PORT3, E_PIN6, E_IO_OUTPUT);DrvGPIO_SetBit(E_PORT3, E_PIN6);//led 接P3.6引脚

}

 

void led_on(void)

{

DrvGPIO_ClrBit(E_PORT3, E_PIN6);

}

 

void led_off(void)

{

DrvGPIO_ClrBit(E_PORT3, E_PIN6);

}

 

 

到此,整个UCOS在cortex-m0就移植成功并且可以运行任务啦。。。从晚上跑到天亮,都非常稳定。

第二天,我又结合之前做过的TXT阅读器,在UCOS上也做了一个TXT电子书阅读器,也挺流畅,也很稳定。感觉很不错!