找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 5954|回復(fù): 4
打印 上一主題 下一主題
收起左側(cè)

uCOS-II移植到LPC17XX方法

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:90762 發(fā)表于 2018-10-16 00:30 | 只看該作者 |只看大圖 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
1. 知識(shí)準(zhǔn)備
要想對(duì)ucos-ii的移植有較深的理解,需要兩方面知識(shí):
(1)目標(biāo)芯片,這里是lpc17xx系列芯片,它們都是基于ARMv7 Cortex-M3內(nèi)核,所以這一類芯片的ucos-ii移植幾乎都是一樣的,要想了解Cortex-M3內(nèi)核,推薦《ARM Cortex-M3權(quán)威指南》(宋巖譯);
(2)ucos-ii內(nèi)核原理,推薦《嵌入式實(shí)時(shí)操作系統(tǒng)uC/OS-II(第2版)》(邵貝貝譯)。
2. 下載文件
ucos-ii移植過(guò)程主要涉及三個(gè)文件:os_cpu.h, os_cpu_a.asm和os_cpu_c.c
實(shí)際上,一般情況下,我們想要移植的目標(biāo)芯片前輩們都已經(jīng)移植成功過(guò)了,我們需要做的就是下載就可以了。
需要下載兩類文件:
(1)lpc17xx芯片啟動(dòng)/初始化代碼:LPC17xx.h, system_LPC17xx.h, core_cm3.h, core_cm3.c, startup_LPC17xx.s和system_LPC17xx.c,這幾個(gè)文件都可以從lpc官方網(wǎng)站lpc17xx系列芯片的任何一個(gè)項(xiàng)目中找到;
(2)ucos-ii移植代碼:可以在Micrium官方網(wǎng)站中找到uCOS-II在LPC17xx上的移植代碼(IAR平臺(tái))。
3. 創(chuàng)建工程
(1)創(chuàng)建文件夾UCOS_II_V289,在該目錄下創(chuàng)建子目錄APP, lpc17xx, Output, uC-CPU, UCOS-II,在Output下創(chuàng)建obj和list子目錄,然后將第2步下載的文件添加進(jìn)相應(yīng)的文件夾中,文件拓?fù)鋱D如下:
UCOS_II_V289
├─APP
│      hello.c

├─lpc17xx
│      core_cm3.c
│      core_cm3.h
│      LPC17xx.h
│      startup_LPC17xx.s
│      system_LPC17xx.c
│      system_LPC17xx.h
│      type.h

├─Output
│  ├─list
│  └─obj
├─uC-CPU
│      os_cpu.h
│      os_cpu_a.asm
│      os_cpu_c.c
│      os_dbg.c

└─uCOS-II
        app_cfg.h
        os_cfg.h
        os_core.c
        os_flag.c
        os_mbox.c
        os_mem.c
        os_mutex.c
        os_q.c
        os_sem.c
        os_task.c
        os_time.c
        os_tmr.c
        ucos_ii.h
其中,hello.c中的文件代碼如下:
#include <LPC17xx.h>
#include <ucos_ii.h>
#define TASK_STK_SIZE 512
OS_STK TaskStartStk[TASK_STK_SIZE];
void TaskStart(void *data);
int main(void)
{
    OSInit();
    OSTaskCreate(TaskStart, (void *)0, &TaskStartStk[TASK_STK_SIZE - 1], 0);
    OSStart();
    return 0;
}
void  TaskStart(void *data)
{
    data=data;
    OS_CPU_SysTickInit(SystemFrequency/100);
    for(;;)
    {
        OSCtxSwCtr = 0;
        OSTimeDlyHMSM(0,0,0,10);
    }
}
(2)Keil uVision4創(chuàng)建新工程,選擇UCOS_II_V289作為工程目錄,選擇芯片型號(hào),需要注意的是當(dāng)提示“Copy NXP LPC17xx Startup Code to Project Folder and Add File to Project?”時(shí),選擇“否”,因?yàn)槲覀円呀?jīng)有這個(gè)文件了。創(chuàng)建組,添加相應(yīng)文件到組,如下所示:
右擊“UCOS_II_V289”,更改工程設(shè)置:
如果勾選“Run to main()”,那么在仿真的時(shí)候,就會(huì)跳過(guò)啟動(dòng)代碼,直接到main函數(shù)。
4. 編譯
編譯,會(huì)報(bào)很多錯(cuò)誤,下面一個(gè)一個(gè)改:
(1)將os_cpu_a.asm中的“public”改為“EXPORT”;
(2)將os_cpu_a.asm中的
        RSEG CODE:CODE:NOROOT(2)
        THUMB
改為
        AREA OSKernelschedular,code,READONLY
        THUMB
(3)將os_cfg.h中“OS_APP_HOOKS_EN”、“OS_DEBUG_EN”和“OS_TASK_STAT_EN”設(shè)置為0;
(4)將startup_LPC17xx.s中的所有的“PendSVHandler”改為“OS_CPU_PendSVHandler”,所有的“SysTickHandler”改為“OS_CPU_SysTickHandler”。
編譯通過(guò)。
5. 軟件仿真調(diào)試
在步驟4中已經(jīng)設(shè)置為軟件仿真調(diào)試,編譯成功后,即可添加斷點(diǎn)進(jìn)行軟件仿真調(diào)試,查看代碼運(yùn)行是否符合預(yù)期。至此,移植結(jié)束。
6. 相關(guān)說(shuō)明
1)啟動(dòng)文件與啟動(dòng)流程
i)啟動(dòng)文件
啟動(dòng)文件為以下幾個(gè)文件core_cm3.c, core_cm3.h, LPC17xx.h, startup_LPC17xx.s, system_LPC17xx.c 和 system_LPC17xx.h,下面分別說(shuō)明它們的功能。
startup_LPC17xx.s:該文件是Cortex-M3的啟動(dòng)匯編代碼,閱讀源代碼不難發(fā)現(xiàn),它的作用是:堆和棧的初始化以及向量表的定義。Cortex-M3的向量表其實(shí)就是一個(gè)32位整數(shù)數(shù)組,每個(gè)下標(biāo)對(duì)應(yīng)一個(gè)向量,該下標(biāo)元素的值則是該中斷服務(wù)子程序的入口地址。向量表在地址空間中的位置是可以設(shè)置的,通過(guò)NVIC(向量中斷控制器)中的一個(gè)重定位七寸器來(lái)指出向量表的地址。復(fù)位后,該寄存器的值為0,因此,在地址0處必須包含一張向量表,用于初始時(shí)的中斷分配。
中斷類型
表項(xiàng)地址偏移量
中斷向量
0
0x00
MSP的初始值
1
0x04
復(fù)位
2
0x08
NMI
其中,向量表中的第一個(gè)元素并非中斷向量,而是MSP(主堆棧寄存器)的初始值。
LPC17xx.h:該文件是CM3(Cortex-M3,下同)內(nèi)核芯片的頭文件,它定義了芯片寄存器的結(jié)構(gòu)體。
core_cm3.h和core_cm3.c:這兩個(gè)文件分別是CM3內(nèi)核芯片的外圍驅(qū)動(dòng)頭文件和源代碼。
system_LPC17xx.h和system_LPC17xx.c:這兩個(gè)文件為我們提供了一個(gè)系統(tǒng)初始化函數(shù)SystemInit(),CM3的初始化包括時(shí)鐘配置、電源管理、功耗管理等。其中時(shí)鐘配置比較復(fù)雜,因?yàn)樗▋蓚(gè)PLL倍頻電路,一個(gè)是主PLL0,主要為系統(tǒng)和USB提供時(shí)鐘,另一個(gè)是PLL1,專門(mén)為USB提供48M時(shí)鐘。默認(rèn)情況下,系統(tǒng)使用12M外部晶振,通過(guò)PLL0倍頻到一個(gè)較高的頻率,之后可以通過(guò)分頻為CPU、外設(shè)以及可選的USB子系統(tǒng)提供精確的時(shí)鐘。
ii)啟動(dòng)流程
由Cortex-M3的啟動(dòng)步驟可知,系統(tǒng)上電后,首先執(zhí)行復(fù)位的5個(gè)步驟:
    ①NVIC復(fù)位,控制內(nèi)核;
    ②NVIC從復(fù)位中釋放內(nèi)核;
    ③內(nèi)核配置堆棧;
    ④從地址0x00000000處取出MSP的初始值,從地址0x00000004處取出PC的初始值——這個(gè)值是復(fù)位向量;
    ⑤運(yùn)行復(fù)位中斷服務(wù)子程序;
其中,復(fù)位中斷服務(wù)子程序的代碼如下:
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  SystemInit
                IMPORT  __main
                LDR     R0, =SystemInit
                BLX     R0
                LDR     R0, =__main
                BX      R0
                ENDP
可知,通過(guò)復(fù)位中斷服務(wù)子程序,首先引導(dǎo)程序進(jìn)入SystemInit()函數(shù),然后進(jìn)入__main(此__main是C_Library中的函數(shù),非main())。
2SysTick定時(shí)器、SysTickInitSysTickHandler
i)SysTick定時(shí)器
Cortex-M3內(nèi)核內(nèi)部包含了一個(gè)簡(jiǎn)單的定時(shí)器——SysTick定時(shí)器。SysTick定時(shí)器被捆綁在NVIC中,用于產(chǎn)生SysTick中斷。一般情況下,操作系統(tǒng)以及所有使用了時(shí)基的系統(tǒng),都必須由硬件定時(shí)器來(lái)產(chǎn)生需要的“滴答”中斷,作為整個(gè)系統(tǒng)的時(shí)基。SysTick定時(shí)器就是用來(lái)產(chǎn)生周期性的中斷,以維持操作系統(tǒng)“心跳”節(jié)律的。SysTick定時(shí)器的時(shí)鐘源可以是內(nèi)部時(shí)鐘(FCLK,CM3上的自由運(yùn)行時(shí)鐘),或者是外部時(shí)鐘(CM3上的STCLK信號(hào))。
SysTick定時(shí)器能產(chǎn)生中斷,CM3為它專門(mén)開(kāi)出一個(gè)中斷類型,并且在向量表中有它的一席之地——SysTickHandler,它使得操作系統(tǒng)和其它軟件系統(tǒng)在CM3內(nèi)核的移植變得更加簡(jiǎn)單,因?yàn)樵谒械腃M3微處理器上,SysTick的處理方式都是相同的。
有4個(gè)寄存器控制SysTick定時(shí)器,下面只介紹其中經(jīng)常用到的三個(gè):
①SysTick控制及狀態(tài)寄存器(地址:0xE000E010)
位段
名稱
類型
復(fù)位值
描述
16
COUNTFLAG
R
0
如果在上次讀取本寄存器后,SysTick已經(jīng)計(jì)到了0,則該位為1;如果讀取該位,該位自動(dòng)清0
2
CLKSOURCE
R/W
0
0=外部時(shí)鐘源(STCLK)
1=內(nèi)核時(shí)鐘源(FCLK)
1
TICKINT
R/W
0
1=SysTick倒數(shù)計(jì)數(shù)到0時(shí)產(chǎn)生SysTick異常請(qǐng)求
0=倒數(shù)到0時(shí)無(wú)動(dòng)作
0
ENABLE
R/W
0
SysTick定時(shí)器的使能位
②SysTick重裝載數(shù)值寄存器(地址:0xE000E014)
位段
名稱
類型
復(fù)位值
描述
23:0
RELOAD
R/W
0
當(dāng)?shù)箶?shù)計(jì)數(shù)到0時(shí),將被重裝載的值
③SysTick當(dāng)前數(shù)值寄存器(地址:0xE000E018)
位段
名稱
類型
復(fù)位值
描述
23:0
CURRENT
R/Wc
0
讀取時(shí)返回當(dāng)前倒數(shù)計(jì)數(shù)的值,寫(xiě)它則使之清零,同時(shí)還會(huì)清除在SysTick控制及狀態(tài)寄存器中的COUNTFLAG標(biāo)志
ii SysTickInit()函數(shù)
該函數(shù)用于初始化SysTick定時(shí)器,在本移植實(shí)例中,它位于os_cpu_c.c文件中,其函數(shù)名被更改為“OS_CPU_SysTickInit”,源代碼如下:
void  OS_CPU_SysTickInit (INT32U  cnts)
{
    OS_CPU_CM3_NVIC_ST_RELOAD = cnts - 1u;
   /* 設(shè)置SysTickHandler中斷優(yōu)先級(jí)為最低優(yōu)先級(jí)           */
    OS_CPU_CM3_NVIC_PRIO_ST   = OS_CPU_CM3_NVIC_PRIO_MIN;
     /* 使能定時(shí)器                                      */
    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
      /* 使能SysTickHandler中斷                            */
    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
}
第一行用于裝載SysTick重裝載數(shù)值寄存器,其他幾行都有注釋,在此不再解釋。
iii)SysTickHandler
當(dāng)SysTick定時(shí)器倒數(shù)計(jì)數(shù)到0時(shí),將產(chǎn)生SysTick中斷,該中斷位于向量表15號(hào)位置(中斷向量號(hào):15,下同)。在本移植實(shí)例中,該中斷服務(wù)子程序的名稱被更改為“OS_CPU_SysTickHandler”,其位于os_cpu_c.c文件中,源碼如下:
void  OS_CPU_SysTickHandler (void)
{
    OS_CPU_SR  cpu_sr;
    OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR  */
    OSIntNesting++;
    OS_EXIT_CRITICAL();

    OSTimeTick();  /* Call uC/OS-II's OSTimeTick()    */

    OSIntExit();        /* Tell uC/OS-II that we are leaving the ISR          */
}
(3) OSCtxSwPendSVHandler
iPendSV中斷
Cortex-M3內(nèi)核內(nèi)置了一個(gè)重要的中斷——PendSV中斷(可掛起的系統(tǒng)調(diào)用)。與SVC中斷(系統(tǒng)服務(wù)調(diào)用,簡(jiǎn)稱系統(tǒng)調(diào)用)不同的是,PendSV可以像普通的中斷一樣被掛起,OS可以利用它“緩期執(zhí)行”一個(gè)中斷——直到其他重要的任務(wù)完成后才執(zhí)行動(dòng)作。掛起PendSV的方法是:手動(dòng)往NVIC的PendSV掛起寄存器中寫(xiě)1,掛起后,如果該中斷優(yōu)先級(jí)不夠高,則將緩期等待執(zhí)行。
PendSV的典型功能是上下文(任務(wù))切換。若在即將做上下文(任務(wù))切換時(shí)發(fā)現(xiàn)CPU正在響應(yīng)一個(gè)中斷,這時(shí),OS是不能執(zhí)行上下文(任務(wù))切換的,否則將使中斷請(qǐng)求被延遲,而這在實(shí)時(shí)系統(tǒng)中是絕不能容忍的。PendSV可以完美地解決這個(gè)問(wèn)題,PendSV中斷會(huì)自動(dòng)延遲上下文(任務(wù))切換的請(qǐng)求,直到其他的中斷請(qǐng)求都完成后才響應(yīng)。為實(shí)現(xiàn)這個(gè)機(jī)制,需要把PendSV的優(yōu)先級(jí)設(shè)置為最低,當(dāng)OS需要做上下文(任務(wù))切換時(shí)掛起一個(gè)PendSV中斷即可。
PendSV中斷位于向量表14號(hào)位置,在本移植實(shí)例中,該中斷服務(wù)子程序的名稱被更改為“OS_CPU_PendSVHandler”,其位于os_cpu_a.asm文件中,源碼如下:
OS_CPU_PendSVHandler
    CPSID   I ; Prevent interruption during context switch
    MRS     R0, PSP ; PSP is process stack pointer
    CBZ     R0, OS_CPU_PendSVHandler_nosave ; Skip register save the first time

    SUBS    R0, R0, #0x20    ; Save remaining regs r4-11 on process stack
    STM     R0, {R4-R11}

    LDR     R1, =OSTCBCur                                       ; OSTCBCur->OSTCBStkPtr = SP;
    LDR     R1, [R1]
    STR     R0, [R1]    ; R0 is SP of process being switched out

                      ; At this point, entire context of process has been saved
OS_CPU_PendSVHandler_nosave
PUSH    {R14} ;
Save LR exc_return value
LDR     R0, =OSTaskSwHook;      
OSTaskSwHook();
    BLX     R0
    POP     {R14}
LDR     R0, =OSPrioCur;
OSPrioCur = OSPrioHighRdy;
    LDR     R1, =OSPrioHighRdy
    LDRB    R2, [R1]
    STRB    R2, [R0]

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

LDR     R0, [R2] ; R0 is new process SP;
LDM     R0, {R4-R11}  ; Restore r4-11 from new process stack
    ADDS    R0, R0, #0x20
MSR     PSP, R0 ; Load PSP with new process SP
ORR     LR, LR, #0x04 ; Ensure exception return uses process stack
    CPSIE   I
    BX      LR   ; Exception return will restore remaining context

    END
ii)OSCtxSw
ucos-ii中,OSCtxSw的功能是上下文(任務(wù))切換。而由上面的介紹可知,真正的切換工作是在PendSV中斷中完成的,那么可想而知,OSCtxSw只需觸發(fā)一個(gè)PendSV中斷即可完成上下文(任務(wù))切換的工作。OSCtxSw位于os_cpu_a.asm文件中,源碼如下:
OSCtxSw
    LDR     R0, =NVIC_INT_CTRL   ; Trigger the PendSV exception (causes context switch)
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

7. 工程源碼
工程源碼鏈接: UCOS_II_V289.rar (606.79 KB, 下載次數(shù): 24)
uCOS-II 移植到LPC17XX方法.zip (175.71 KB, 下載次數(shù): 20)

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏3 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:85181 發(fā)表于 2018-12-29 17:46 | 只看該作者
看看在說(shuō)話吧啊
回復(fù)

使用道具 舉報(bào)

板凳
ID:469739 發(fā)表于 2019-1-17 16:19

1.png (150 Bytes, 下載次數(shù): 193)

1.png

地板
ID:223999 發(fā)表于 2019-2-27 10:53 | 只看該作者
先看看再說(shuō)
回復(fù)

使用道具 舉報(bào)

5#
ID:573345 發(fā)表于 2019-6-27 13:47 | 只看該作者
繼續(xù)努力學(xué)習(xí)
回復(fù)

使用道具 舉報(bào)

6#
ID:260263 發(fā)表于 2019-9-26 14:06 | 只看該作者
謝謝分享
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表