標籤:
**
1. 概述
**
多任務是現代作業系統的核心功能,深入理解多任務並非易事,但學習者如果能嘗試去實現一個簡易的多任務程式,對理解作業系統的“多任務”概念會有很大的協助。若能進一步拓展這個多任務的程式,則可設計一個簡易的核心(Kernel)。
本文就是介紹一個十分簡易的多任務程式。
實驗程式中共有2個任務,Task1和Task2:
Task1中,閃爍LED1燈3次後,主動將CPU使用權切換給Task2;
Task2中,閃爍LED2燈3次後,主動將CPU使用權切換給Task1。
從而,實現2個任務的交替執行。
實驗環境說明:
本實驗的操作平台為TQ2440(ARM9)開發板,程式碼在S3C2440“SteppingStone”的4KB內部RAM中運行。程式就是利用這4KB的空間來實現多任務的切換。
請選擇從NAND Flash啟動,並將產生的二進位檔案燒到NAND Flash中。
當選擇從NAND Flash啟動CPU時,CPU會通過內部硬體將NAND Flash開始的4KB位元組資料複製到“SteppingStone” 的4KB內部RAM中(此時內部RAM的起始地址是0),然後跳到地址0開始執行。
Task1和Task2的代碼如下,
2. 詳解設計/實現部分
程式分為3大部分,
**–初始化
–儲存模型
–任務切換**
2.1 初始化
程式的初始化很簡單,_start是CPU reset後啟動並執行第一段代碼。
a. 因為要調用C函數,必須要先設定了SVC模式下的堆棧(CPU reset後,預設進入SVC模式);
b. 為了防止CPU不斷自動重啟,需要關閉WatchDog;
c. 接下來初始化4個LED燈(關閉4個LED燈);
d. 最後,啟動第一個任務Task1。
注意:Task1堆棧的初始化指標指向#4000,它工作在SVC模式中。
初始化代碼(_start)如下,
2.2儲存模型
Code存放地區: 0x00000000~0x000007FF (2KB);
Task2的堆棧地區: 0x00000C00~0x00000E03(516B);
Task1的堆棧地區: 0x00000E04~0x00000FA3(416B);
TCB指標存放地區: 0x00000FA4~0x00000FFF(92B)。
注意:
a. 棧的增長方向由高地址到低地址;
b. TCB指標存放地區,存放的是Task棧頂指標,如0x0000FFC儲存Task1的棧頂指標;0x00000FF8儲存Task2的棧頂指標。
儲存劃分圖表如下,
2.3任務切換
運行新任務之前,必須要為每個新任務初始化PCB(Process Control Block)。PCB是一個保留在RAM的資料結構,用於儲存所有ARM寄存器的一個副本(見下表)。
任務控制塊(PCB, Process Control Block)
測試代碼中,任務1是主程式並首先運行,不需要初始化PCB。
任務2運行之前,需要先初始化PCB,初始化代碼如下,
其中,函數“TaskCreate”的3個參數含義如下:
void(*Task)(void): Task地址
unsigned long *p_Stack: Task堆棧指標
unsigned long *Task_STK_PTR: 儲存Task棧頂指標的地址
下面以Task1切換到Task2為例,來說明任務切換的過程。
第一階段,儲存Task1啟動並執行上下文(Context)。
將PC/LR/R0-R12/CPSR壓入堆棧中,然後將棧頂指標儲存起來。代碼如下,
第二階段,恢複Task2的運行上下文(Context)。
首先取出Task2的棧頂指標;然後,PSR先出棧並恢複CPSR;接著R0-R12/LR/PC依次出棧。
至此,Task2恢複了之前的運行上下文並接管CPU的控制權。
簡易多任務的設計(v1.0) --基於TQ2440(ARM9)的實現(1)