Keil ARTX(Advanced Real-Time eXecutive) 是keil 為ARM 系列所提供的一個小型實時操作系統,整合於其UV3 開發環境之中.
一,簡介
與以前大家使用keil for 51 時所熟悉RTX51 實時操作系統類似,整個OS 為keil IDE 定製,面向特定的處理器,以庫的形式提供,這就屏蔽了底層的操作,使得用戶可以專註於應用的開發,但同時也使得用戶無法接觸到操作系統底層.
ARTX 提供的基本功能包括任務的建立,運行,刪除,可以給任務指定優先順序,對任務進行切換,具體可以參考keil 的官方文檔ARARM.chm, 位於UV3 的安裝目錄.
ARTX 為任務間通信和共享資源的保護提供如下機制:
*事件標誌
*信號量
*互斥信號量
*郵箱
ARTX 的特徵如下:
任務數量 | 最大256 |
郵箱數量 | 軟體無限制,取決於硬體資源 |
信號量數量 | 軟體無限制 |
互斥信號量數量 | 軟體無限制 |
信號數量 | 每任務16 個事件標誌 |
用戶定時器 | 軟體無限制 |
RAM 空間需求 | 最小500 位元組 |
CODE 空間需求 | 小於5kB |
硬體要求 | 一個片上定時器 |
任務優先順序 | 1~255 |
上下文切換時間 | 在60MHz,0 等待時小於5us |
中斷鎖定時間 | 60MHz,0 等待時為1.8us |
由於ARTX 是keil 為UV3 所定製,所以使用UV3 可以方便地建立基於ARTX
的應用.簡單的說,只需要引用一個頭文件,並於連接時連接ARTX 庫. 下面例子來自keil(位於Keil\ARM\ARTX\Examples\Artx_ex1). 假定當前有兩個任務,稱作”do-this”與”do-that”.這些必須重複運行,例如間隔時
間為50ms.兩者都運行完成後會暫停一段時間,而”do-that”會在”do-this”運行后運行,
並暫停20ms. 按照如下步驟建立應用. 首先利用關鍵字__task 建立兩個任務:
void task1 (void) __task {
.... code of task 1 placed here ....
}
void task2 (void) __task {
.... code of task 2 placed here ....
}
任務必須建立於運行之前,可通過在main 函數中調用os_sys_init() 來啟動任務的運行. 如下例中,task1 最先啟動,然後其通過調用os_tsk_create 來啟動task2.
void task1 (void) __task {
os_tsk_create (task2, 0);
.... code of task 1 placed here ....
}
void task2 (void) __task {
.... code of task 2 placed here ....
}
void main (void) {
os_sys_init (task1);
}
完成最初所設定的應用任務的源代碼如下:
/* Include type and function declarations for ARTX */
#include "ARTX.H"
/* id1, id2 will contain task identifications at run-time */
OS_TID id1, id2;
/* Forward reference. */
void task1 (void) __task;
void task2 (void) __task;
void task1 (void) __task {
/* Obtain own system task identification number */
id1 = os_tsk_self ();
/* Assign system identification number of task2 to id2 */
id2 = os_tsk_create (task2, 0);
for (;;) { /* do-this */
/* Indicate to task2 completion of do-this */
os_evt_set (0x0004, id2);
/* Wait for completion of do-that (0xffff means no time-out)*/
os_evt_wait_or (0x0004, 0xffff);
/* Wait now for 50 ms */
os_dly_wait (5);
}
}
void task2 (void) __task {
for (;;) {
/* Wait for completion of do-this (0xffff means no time-out) */
os_evt_wait_or (0x0004, 0xffff); /* do-that */
/* Pause for 20 ms until signaling event to task1 */
os_dly_wait (2);
/* Indicate to task1 completion of do-that */
os_evt_set (0x0004, id1);
}
}
void main (void) {
os_sys_init (task1);
}
os_dly_wait() 用於將任務暫停一定的系統定時周期.
os_evt_wait_or() 用於os_evt_set() 等待和設置任務的事件標誌.
二,機制
1. 計時中斷
ARTX 需要使用一個硬體的定時器產生周期性的中斷.使用一個硬體定時器來實現,可在ARTX_Config.c 中配置.
2. 系統定時任務
系統定時任務(系統時鐘任務),在每一個系統定時中斷產生時被執行,其具有最高的優先順序且不可被搶佔.此任務基本可以說是一個任務切換器.
ARTX 給每個任務分配一個時間片(time slice),其時間的長短可以在ARTX_Config.c 中進行配置,由於時間片很短(默認為10ms),使得任務看上去像是在同時運行.
任務在自己分得的時間片內運行時,可通過os_tsk_pass() 或一些wait 函數放棄CPU 的控制權.然後ARTX 將切換到下一個就緒任務運行.
os_clock_demon() 作為系統定時任務管理用戶任務.它處理任務的延時, 使等待的任務進入休眠態,當有時間發生時,將相應的任務喚醒並進入就緒態. 這也就是其處於最高優先順序的原因.
3. 任務管理
任務可處於下列狀態:
RUNNING, READY, WAIT_DLY, WAIT_ITV, WAIT_OR,
WAIT_AND, WAIT_SEM, WAIT_MUT, WAIT_MBX, INACTIVE
4. 空閑任務
當無任務運行時,ARTX 調度任務os_idle_demon() 進入運行狀態,可在該任務添加代碼中使得系統休眠,從而降低系統功耗,具體可以在ARTX_Config.c 中配置.
5. 系統資源
ARTX 的任務有任務控制(TCB).這是一個可動態分配的內存塊,保存著所有任務的控制和狀態變數.TCB 可通過os_tsk_create() 或os_tsk_create_user() 於運行時分配.
TCB 內存池的大小可以在ARTX_Config.c 中根據系統中任務的狀況進行配置,不僅是任務的數量,還有實際任務的實例數,原因在於ARTX 支持一個任務(函數)的多個實例.
任務有其自己的堆棧,也於運行時被分配,然後棧指針被記錄到任務的TCB 中.
6. 協同任務調度
如果禁止了輪轉(Round-Robin)方式的任務調度,則用戶必須使得任務可以協同調度,比如,調用函數os_dly_wait() 或os_tsk_pass() 來通知ARTX 進行任務的切換.
如下例:
#include <ARTX.h>
int counter1; int counter2;
void task1 (void) __task; void task2 (void) __task;
void task1 (void) __task { os_tsk_create (task2, 0); /* Create task 2 and mark it as ready */
for (;;) { | /* loop forever */ | |
counter1++; | /* update the counter */ | |
os_tsk_pass (); | /* switch to 'task2' */ | |
} | | |
} | | |
void task2 (void) __task { | | |
| for (;;) { | /* loop forever */ |
| counter2++; | /* update the counter */ |
| os_tsk_pass (); | /* switch to 'task1' */ |
| } | |
} | | |
void main (void) { | | |
| os_sys_init(task1); | /* Initialize ARTX Kernel and start task 1 */ |
| for (;;); | |
} | | |
wait 系統調用與os_tsk_pass () 的區別在於前者使得任務等待一個事件,而後者直接切換到下一就緒任務運行.
7. 輪轉任務調度
ARTX 可配置為輪轉調度方式,任務將在一個分配的時間片內運行.
任務可連續運行時間片長度的時間(除非任務本身放棄時間片),然後,ARTX 將會切換到下一個就緒且優先順序相同的任務運行.如果沒有相同優先順序的任務就緒,則當前任務會繼續運行.
如下例:
#include <ARTX.h>
int counter1; int counter2;
void job1 (void) __task; | |
void job2 (void) __task; | |
void job1 (void) __task { | |
os_tsk_create (job2, 0); | /* Create task 2 and mark it as ready */ |
while (1) { | /* loop forever */ |
counter1++; | /* update the counter */ |
} | |
} | |
void job2 (void) __task { while (1) { /* loop forever */ counter2++; /* update the counter */ } }
void main (void) { os_sys_init (job1); /* Initialize ARTX Kernel and start task 1 */ for (;;);
}
注意:
不必等到時間片用完,任務就可以通過wait 系統調用或者os_tsk_pass () 來通知ARTX 可以切換到下一個就緒任務.wait 系統調用將使當前任務掛起(wait XXX 狀態),等待一個特定的事件發生(然後其進入ready 狀態).在這段等待的時間,其它的任務得以運行.
8. 搶佔式任務調度
ARTX 是一個搶佔式的多任務調度系統.如果一個高優先順序的任務就緒,它將打斷當前任務的運行,而使得高優先順序任務可以立即運行. 搶佔式任務切換髮生於:
*在系統定時中斷中,如果某一個高優先順序任務的延時時間到達,將使得當前任務被掛起而高優先順序任務被運行
*如果掛起中的高優先順序的任務接收到當前任務或中斷髮來的特定事件, 將會掛起當前任務,切換到高優先順序任務運行
*高優先順序任務等待到了所需的信號量
*一個高優先順序任務正在等待的互斥信號量被釋放
*一個高優先順序任務等待的消息被發往信箱
*信箱已滿,而一個高優先順序的任務等待往信箱發送一個消息.則當前任務或中斷從信箱中取走一個消息時,將使得該高優先順序任務被激活,並立即投入運行
*當前任務的優先順序下降,而有相對高優先順序任務就緒時請參考下例:
#include <ARTX.h>
OS_TID tsk1,tsk2;
int cnt1,cnt2;
void job1 (void) __task; void job2 (void) __task;
void job1 (void) __task { os_tsk_prio (2); os_tsk_create (job2, 1); while (1) {
os_evt_wait_or (0x0001, 0xffff); cnt1++; } }
void job2 (void) __task {
while (1) {
os_evt_set (0x0001, job1);
cnt2++;
} }
void main (void) { os_sys_init (job1); while (1);
}
任務job1 比任務job2 的優先順序高. 當job1 開始運行, 將創建任務job2 然後進入os_evt_wait_or() . 然後當前任務掛起並開始運行任務job2. 一旦任務job2 為任務job1
發送一個事件標誌, 它將被掛起然後job1 繼續運行. 任務job1 增加計數變數然後再次通過os_evt_wait_or() 調用掛起. 任務job2 將被繼續運行, 增加計數器變數 cnt2 ,然後再次發送事件…
9. 用戶定時器
用戶定時器是基於系統定時的簡單簡單定時器模塊.可在運行時動態創建與刪除用戶定時器.如果在用戶定時器溢出前未被刪除,該定時器的溢出將會調用用戶定義的回調os_tmr_call() 然後刪除這個定時器.
用戶定時器超時的值可以在調用os_tmr_create() 創建該定時器時指定. os_tmr_call() 可在ARTX_Config.c 中配置.
10.中斷函數
ARTX 支持中斷平行處理,但是仍建議不要使用中斷嵌套.最好使用短的中斷函數,發時間標誌到RTOS 的任務,這樣一來,中斷嵌套也就不必要了. 如下例:
#define EVT_KEY 0x0001
OS_TID pr_task; int num_ints;
/*----------------------------------------------------------------------------
* External 0 Interrupt Service Routine *---------------------------------------------------------------------------*/
void ext0_int (void) __irq | { | ||||
| isr_evt_set (EVT_KEY, pr_task); | /* Send event to 'process_task' | */ | ||
| EXTINT | = 0x01; | | /* Acknowledge Interrupt | */ |
| VICVectAddr = 0; | | | | |
} | | | | | |
/*----------------------------------------------------------------------------
* Task 'process_task' *---------------------------------------------------------------------------*/
void process_task (void) __task { num_ints = 0; while (1) {
os_evt_wait_or (EVT_KEY, 0xffff); num_ints++; } }
/*----------------------------------------------------------------------------
* Task 'init_task' *---------------------------------------------------------------------------*/
void init_task (void) __task { PINSEL1 &= ~0x00000003; /* Enable EINT0 */ PINSEL1 |= 0x00000001; EXTMODE = 0x03; /* Edge triggered lo->hi transition */ EXTPOLAR = 0x03;
pr_task = os_tsk_create (process_task, 100);
VICVectAddr14 = (U32)eint0_int; /* Task started, Enable interrupts */ VICVectCntl14 = 0x20 | 14;
os_tsk_delete_self (); /* Terminate this task */ }
[admin via 研發互助社區 ] Keil ARTX 介紹已經有7073次圍觀
http://cocdig.com/docs/show-post-42943.html