1. 程式人生 > >初學者EFM32上移植uC/OSII

初學者EFM32上移植uC/OSII

前言

之前大學接觸過uc/os,大學開了ARM這門課程,用的是周立功的教材,好像是大四開的,你懂的,實驗只帶手不帶腦,複製–編譯–下載–嘿,燈亮了–走人。
最近在接觸EFM32系列MCU,就想彌補一下大學的遺憾。為時間4天的準備和移植工作終於完成,還是,嘿燈亮了。
硬體:EFM32G890F128
IDE : IAR

準備工作

兩本書:Cortex-M3權威指南,uc/OSII作業系統原理(邵貝貝)。
因為核心之前已看過了,就琢磨了下uc,大學的時候接觸過點點還有點印象,所以看起來不費什麼勁,確實挺小的一個核。裡面關於移植的過程也挺詳細的。不過那裡關於移植的是ARM7核心。大同小異。原理性的東西是一樣的。
其餘,關於移植部分,各大晶片廠商都已經很完善了,對於求知的同學,這是一個理解CPU,作業系統的好地方。

建立模板

  1. 官網下載原始碼

    http://micrium.com/ ->downloads -> Application Notes ->
    這裡寫圖片描述
    壓縮包下載下來解壓最主要的就是這幾個檔案夾了。
    這裡寫圖片描述
    當然還有一個PDF文件,這個文件主要是教你怎樣使用它們的官方工程模板。英文好的可以照著上面的步驟一步一步來,沒什麼說的,當然你要有耐心看英語。我試了下:確實規範,一目瞭然。
    這裡寫圖片描述
    個人覺得學習的話還是自己建一個模板吧,這樣有利於理解各個模組之間的關係。所以我就以自己的習慣加參考官方的自己操作了。
    其實我們自己移植的話就只要uc/OSII的核心原始碼和三個移植檔案啦。最難的移植部分人家幫我們做好了,那就是那三個移植檔案了,即os_cpu.h,os_cpu_a.asm, os_cpu.c當然我們還是要看懂的。

  2. 接下來就是建工程,這是我自己的工程:
    這裡寫圖片描述

程式碼分析

這裡的程式碼分析就是與處理器相關的程式碼了,最接近處理器的程式碼:彙編。
主要乾了兩個個事情:

  1. 任務級和中斷級排程,這兩個函式的內容是一樣的,真正的排程則放到了PENDSVHandler。
  2. 系統開始啟動時,啟動最高優先順序任務。
  3. PENDVHandler儲存上下文切換環境。
    下面分析整個OS_CPU_A.ASM檔案
EXTERN  OSRunning                   ; External references,外部標號
EXTERN  OSPrioCur
EXTERN  OSPrioHighRdy
EXTERN  OSTCBCur
EXTERN  OSTCBHighRdy
EXTERN  OSIntExit
EXTERN  OSTaskSwHook
EXTERN  OS_CPU_ExceptStkBase


PUBLIC
OS_CPU_SR_Save ; Functions declared in this file,全域性函式,可被其他模組引用 PUBLIC OS_CPU_SR_Restore PUBLIC OSStartHighRdy PUBLIC OSCtxSw PUBLIC OSIntCtxSw PUBLIC PendSV_Handler NVIC_INT_CTRL EQU 0xE000ED04 ; Interrupt control state register. 中斷控制暫存器 NVIC_SYSPRI14 EQU 0xE000ED22 ; System priority register (priority 14).優先順序暫存器 NVIC_PENDSV_PRI EQU 0xFF ; PendSV priority value (lowest). PENDSV優先順序(最低) NVIC_PENDSVSET EQU 0x10000000 ; Value to trigger PendSV exception. 觸發PENDSV的值

;**********************************************************************************************
; 程式碼部分
;**********************************************************************************************
RSEG CODE:CODE:NOROOT(2)
THUMB
;RSEG 是段選擇指令。RSEG CODE:選擇段 code。第二個 CODE 表示程式碼段的意思,只讀。
;NOROOT 表示:如果這段中的程式碼沒呼叫,則允許聯結器丟棄這段.(2)表示:4 位元組對齊。假如是(n),則表示 2^n 對
;齊,更多關於IAR編譯指令參考IAR編譯手冊。
;THUMB則為程式碼為THUMB指令,M3為THUMB指令集。

OS_CPU_SR_Save
    MRS     R0, PRIMASK                          ; 儲存PRIMASK值至R0,OS_CPU_SR_Save返回時,R0中值送入
                                                 ; cpu_sr.
    CPSID   I                                    ; PRIMASK =1 ,關中斷.
    BX      LR

OS_CPU_SR_Restore
    MSR     PRIMASK, R0                         ;把R0的值載入到PRIMASK,R0為呼叫OS_CPU_SR_Restore的函
                                                ;數的引數cpu_sr.                                        
    BX      LR
/*-----啟動最高優先順序任務--作業系統啟動第一個任務時------*/
OSStartHighRdy
    LDR     R0, =NVIC_SYSPRI14                         ; 設定PENDSV為最低優先順序
    LDR     R1, =NVIC_PENDSV_PRI
    STRB    R1, [R0]                                      

    MOVS    R0, #0                                     ; 把從堆疊置0,在排程器排程時通過判斷PSP是否 
    MSR     PSP, R0                                    ; 0來判斷系統是否為首次排程。
    STRB    R1, [R0]

    LDR     R0, =OS_CPU_ExceptStkBase                  ; 初始化主堆疊 
    LDR     R1, [R0]
    MSR     MSP, R1                                            

    LDR     R0, =OSRunning                             ; OSRunning = TRUE
    MOVS    R1, #1                                             
    STRB    R1, [R0]

    LDR     R0, =NVIC_INT_CTRL                         ; 觸發一次PENDSV 
    LDR     R1, =NVIC_PENDSVSET                        
    STR     R1, [R0]

    CPSIE   I                                          ; 開啟中斷                                                          
OSStartHang
    B       OSStartHang                                ; 程式到這裡就崩了。

這裡寫圖片描述

;************************************************************************************************
                                        任務級切換與中斷級切換
;************************************************************************************************

OSIntCtxSw
    LDR     R0, =NVIC_INT_CTRL                                 ; 觸發一次PENDSV 
    LDR     R1, =NVIC_PENDSVSET                                 
    STR     R1, [R0]
    BX      LR  
;********************************************************************************************************
;                                     void OS_CPU_PendSVHandler(void)
;

;              a) 獲取SP, 通過判斷sp是否為第一次任務切換,如果不是則跳過如果是則跳轉到
               OS_CPU_PendSVHandler_nosave,第一次任務不需要進行現場保護。
;              b) 如果不是第一次任務切換,需儲存R4-R11的值至PSP;
;              c) 將上一任務的SP儲存在OSTCBCur->OSTCBStkPtr = SP;
;              d) 呼叫鉤子函式 OSTaskSwHook();
;              e) 獲取最高優先順序任務, OSPrioCur = OSPrioHighRdy;
;              f) 獲得最高優先順序任務控制塊, OSTCBCur = OSTCBHighRdy;
;              g) 從任務快做獲取其SP堆疊指標, SP = OSTCBHighRdy->OSTCBStkPtr;
;              h) 從起任務堆疊SP中恢復R4-R11;
;              i) 啟動異常返回序列xPSR, PC, LR, R12, R0-R3
;
;           3)  PendSV handler中斷髮生時:
;              a) xPSR, PC, LR, R12, R0-R3自動入棧程序堆疊PSP
;              b) 處理器模式從執行緒模式轉換到異常模式
;              c) 此時堆疊使用主堆疊MSP
;              d) OSTCBCur      指標指向的為被掛起的任務
;                 OSTCBHighRdy  指標指向將被排程的任務
;
;           4) 因為PendSV為最低優先順序,所以只有當沒有任何異常中斷的時候PendSV才會相應。
;               
;              
;************************************************************************************************

PendSV_Handler
    CPSID   I                                    ; 關中斷

    MRS     R0, PSP                              
    CBZ     R0, OS_CPU_PendSVHandler_nosave      ; 第一次任務開始時,PSP為0,故跳過對R4-R11的儲存              

    SUBS    R0, R0, #0x20                        ; 總共需要儲存8個暫存器的值,即 8個字*4=32位元組=0x20,將
                                                 ;r4-r11儲存到psp中
    STM     R0, {R4-R11}
    LDR     R1, =OSTCBCur                       ; 儲存被中斷任務的堆疊
    LDR     R1, [R1]                            ; 獲取堆疊指標,任務堆疊指標在TCB的頂部。                  
    STR     R0, [R1]                                       ```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]

    LDR     R0, [R2]                             ; 獲得最高優先順序任務堆疊指標;
    LDM     R0, {R4-R11}                         ; 從PSP從恢復r4-11
    ADDS    R0, R0, #0x20
    MSR     PSP, R0                              ;更新PSP,已啟動正確的返回序列
    ORR     LR, LR, #0x04                        ;確保異常返回後使用PSP(詳見M3異常返回) 
    CPSIE   I                                    ;開啟中斷
    BX      LR                                   ;啟動中斷返回序列,獲取PC到任務斷點處。                                          

這裡寫圖片描述

程式碼修改

這裡的程式碼修改主要是開發板上的啟動程式碼和OS核心的掛接了。因為我們下載下來的程式碼本身是IAR下的程式碼,所以很多關於編譯器的程式碼我們就可以省了,至於什麼是與編譯器相關的程式碼,那隻能翻書了。
ARM晶片都有一個啟動程式碼.S檔案,就是放置向量表的地方。
1、函式名稱的對應
在OS核心os_cpu_a_asm中PENDSV中斷的名稱為OS_CPU_PendSvHandler.。而開發板啟動程式碼的PENDSV中斷標號為PendSV_Handler,保證兩者標號一直即可,我這裡將OS_CPU_PendSvHandler.改為PendSV_Handler。
Os_cpu_a_asm:
這裡寫圖片描述這裡寫圖片描述

因為我自己開發板工程目錄下core_cm3.h下有關於SysTick的函式:所以我們得把os_cpu_c.c關於SystemTick的函式和巨集定義都註釋掉:
自己工程下的SysTick_Config()

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk)  return (1);     

  SysTick->LOAD  = ticks - 1;                                 
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  
  SysTick->VAL   = 0;                                         
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                    
  return (0);                                                 
}

將os_cpu_c.c關於SystemTick的函式和巨集定義都註釋掉:

#if 0 //-------註釋掉
void  OS_CPU_SysTickInit (INT32U  cnts)
{
    OS_CPU_CM3_NVIC_ST_RELOAD = cnts - 1u;
    OS_CPU_CM3_NVIC_PRIO_ST   = OS_CPU_CM3_NVIC_PRIO_MIN;
    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC | OS_CPU_CM3_NVIC_ST_CTRL_ENABLE;
    OS_CPU_CM3_NVIC_ST_CTRL  |= OS_CPU_CM3_NVIC_ST_CTRL_INTEN;
}
#endif 

#if 0 //-------註釋掉
#define  OS_CPU_CM3_NVIC_ST_CTRL    (*((volatile INT32U *)0xE000E010uL)) 
#define  OS_CPU_CM3_NVIC_ST_RELOAD  (*((volatile INT32U *)0xE000E014uL)) 
#define  OS_CPU_CM3_NVIC_ST_CURRENT (*((volatile INT32U *)0xE000E018uL)) 
#define  OS_CPU_CM3_NVIC_ST_CAL     (*((volatile INT32U *)0xE000E01CuL)) 
#define  OS_CPU_CM3_NVIC_PRIO_ST    (*((volatile INT8U  *)0xE000ED23uL)) 


    #define  OS_CPU_CM3_NVIC_ST_CTRL_COUNT                    0x00010000uL   
    #define  OS_CPU_CM3_NVIC_ST_CTRL_CLK_SRC                  0x00000004uL   
    #define  OS_CPU_CM3_NVIC_ST_CTRL_INTEN                    0x00000002uL   
    #define  OS_CPU_CM3_NVIC_ST_CTRL_ENABLE                   0x00000001uL   
    #define  OS_CPU_CM3_NVIC_PRIO_MIN                               0xFFu    
    #endif

總結

  1、光知道移植這個操作肯定是不行的,還要知道為什麼這樣移植。這就要參考很多資料了,我是讀了邵貝貝的那本書,其實也不難,當然,我是懷著一股好奇的態度去閱讀的,我就想搞清楚,作業系統到底是個啥玩意。
  2、瞭解Cortex-M3核心,只要接觸過微控制器,不管是大學裡微機原理中的8086還是C51,只要仔細研究過微控制器的工作原理,其實也無非就是指令集,中斷,記憶體對映。。。至於外設操作大同小異。對於M3應該是很簡單的。
  3、此次移植的收穫很大,人家的程式設計方式,人家的程式碼一看就舒服,人家的檔案structure。當然以前許多C語言教程微微提到過的東西,也終於見到他的影子了,總之,學習一個作業系統的原始碼,對自己的程式設計能力和見識是很有幫助的。
  4、英文真的很重要,其實向這種移植過程micrim的網站上都有其應用文件。自己能看懂,就不必去羨慕那些輔導機構的人為什麼知道的那麼多了哦。。。他們也是從國外的網站上借鑑過來的。做技術的,英語無處不在啊!
  5、中國的科技道路還有很長的路要走啊。
  最後,說一下,關於ucos方面的移植,網上的文章講爛了都,但捫心自問一下,自己是否真正徹底弄明白過!

相關推薦

初學者EFM32移植uC/OSII

前言 之前大學接觸過uc/os,大學開了ARM這門課程,用的是周立功的教材,好像是大四開的,你懂的,實驗只帶手不帶腦,複製–編譯–下載–嘿,燈亮了–走人。 最近在接觸EFM32系列MCU,就想彌補一下大學的遺憾。為時間4天的準備和移植工作終於完成,還是,嘿燈

【轉】stm32CubeMx移植自己的printf()和scanf()函數

smi config 用戶 type 連接器 標準庫 can 修改 esp 要想printf()和scanf() 函數工作,我們需要把printf()和scanf() 重新定向到串口中。重定向是指用戶可以自己重寫C 的庫函數,當連接器檢查到用戶編寫了與C 庫函數相同名字的函

嵌入式Linux移植unzip工具

16px 文件 bsp ont div 嵌入 for .gz .tar.gz   由於busybox編譯出來的unzip不支持有密碼的壓縮包解壓,因此基於unzip60源碼包,交叉編譯一個嵌入式Linux上的unzip工具。 1.下載地址是: http://sourcefo

uC/OSii之任務劃分

滿足以下幾個指標將會使軟體設計比較簡潔高效。 滿足實時性指標 任務數目合理 簡化軟體系統 降低資源需求 裝置依賴性劃分:主要是對於一些輸入輸出裝置進行劃分,輸入輸出裝置分為主動型和被動性。主動型有一個儘可能短的中斷服務程式和一個與之關聯的任務組成;被動性任務由於不能主動觸發,必

hikey970學習-012 hikey970移植影象去雨深度神經網路演算法

摘要:本文在hikey970嵌入式裝置上執行影象去雨深度神經網路演算法,驗證hikey970執行神經網路模型的效能與效果。 一、影象去雨簡介     影象去雨處理指的是對於一張雨中的圖片,去除畫面中的雨滴,得到還原後的圖片,與圖片去霧、超解析度等同屬CV領域中影

qt5.5.1在Cortex-a8移植記錄

使用Qt5.5.1原始碼包進行編譯:下載地址 http://download.qt.io/official_releases/qt/ tslib1.4編譯 1.解壓並進入Tslib目錄 2.gedit tests/ts_calibrate.c    230行在o

購買開發板後在iTOP4412開發板移植SDIO介面WIFI方法

       近期需要把WiFi無線網路功能移植到在iTOP4412 開發平臺,查閱了相關資料,經過一段時間的研究、除錯,終於成功,將WiFi功能移植到了開發板上面,這裡筆者記錄移植過程及注意事項,方便以後工作需要。     iTOP4412開發板的WiFi模組與板卡之間

一、在Tiny4412移植3602代WIFI的AP模式

下文的ap模式,不需要hostaod就能產生熱點,目前只能讓其和手機連線,並且能夠ping通。(還沒支援上網@[email protected],後期可以在更新) 一、開發環境 宿主機 :redhat5.3 交叉編譯器 :arm-linux-gcc(4.5.1)

itop4412移植360WiFi 二代AP模式

        最近要在4412的板子上實現無線AP模式,但是給的資料都是作為STA模式的,在網上找了相應的資料,終於根據網上的資料移植360隨身WIFI 2代的AP模式成功。 (我去,我放的圖呢?

I.mx6s移植wm8960驅動(基於linux3.0.101版本)

注意上面最後的引數:--disable-alsamixer 若不加此引數編譯會報錯:configure error required courses helper header not found 具體原因不清楚!!7.2 編譯make7.3安裝(需要root許可權)sudo make install

龍芯3A2000移植NASA WorldWind指南

http://www.loongson.cn/news/company/467.html 一、初識NASA WORLDWIND    NASA World Wind是NASA(美國)國家航空和宇宙航行局聯合出品,類似Earthview 3D的鳥瞰工具,更加權威而且完全免費

Arm板子移植putty

For building on Unix: - unix/configure is for Unix and GTK. If you don't have GTK, you   should still be able to build the command-line utilities (PSCP,   

在JZ2440移植裝置樹---下:核心和裝置樹移植

在JZ2440上移植裝置樹—下:核心和裝置樹移植 2、核心移植 在www.kernel.org上下載原始碼,我這裡選取的是linux-4.15.10版本。 解壓後,檔名重新命名為linux-4.15.10-jz2440。 cd進入 既然要使用裝置

在STM32移植FreeModbus RTU的一點經驗總結

    廢話少說,首先去下載原始碼,我下載的是freemodbus-v1.5.0,解壓後如圖所示:   在demo資料夾中有很多移植好的例子,但是沒有STM32的,不要緊,我們參考已有的例子來操作就可以了。在demo資料夾下新建一個資料夾,命名為STM32,將BARE資料夾裡的檔案全部複製過來。    

在JZ2440移植裝置樹---:u-boot移植

在JZ2440上移植裝置樹–上:u-boot移植 為了用上買了之後就一直在吃灰的JZ2440,決定下一番功夫在jz2440上移植裝置樹。由於韋老師的視訊中沒有講到裝置樹相關,前前後後總共花了我約五個晚上,一個週末的時間。 1、移植u-boot u-boot

在vxworks移植netperf工具

最近需要測一下vxworks上的網路效能,在網上搜了一下,發現iperf支援vxworks,但是並沒有找到對應的原始碼,加了一個vxworks的QQ群,裡面有人提到自己就是用netperf在vxworks上測試網路效能的,因此決定將netperf移植到vxworks上。 手

嵌入式系統移植iperf

1. 先把iperf-2.0.2.tar.gz解壓到你的目錄下。2. cd iperf-2.0.23. ./configure --host=mips  CXX=mips_4KC-g++ CC=mips_4KC-gcc   這裡的mips_4KC-改成你自己的交叉編譯器的字首

(二)U-boot在開發板移植過程詳解--bootloader架構分析

 本例中採用的同樣是前邊一貫的實驗板,這裡就不對板子資源做進一步介紹了。     我們知道,bootloader是系統上電後最初載入執行的程式碼。它提供了處理器上電覆位後最開始需要執行的初始化程式碼。在PC機上載入程式一般由BIOS開始執行,然後讀取硬碟中位於MBR(Main Boot Record,主引

qt應用程式向arm板移植中文不能正確顯示的解決辦法

QApplication a(argc, argv); QTextCodec *codec = QTextCodec::codecForName("gbk"); QTextCodec::setCodecForLocale(codec); QTextCodec::setCodecForCStrings(code

無人機專案外篇-在NanopiM1跟T3的debian8移植ROS

首先因為最近在做無人機專案,學以致用就想的在實際的專案中應用, 肯定得在實際的板子上進行移植,在移植過程中遇到非常多的問題, 也參考過官方的說明以及一大堆的帖子,總結一下經驗 一、安裝前準備 1.1.新增ROS源 $ sudo sh -c 'echo "deb http