在SYS/BIOS中,一個線程就是控制單點,它能夠激活一個函數的調用,或者是激活一段中斷服務程序(ISR)。SYS/BIOS中提供了一系列具有不同屬性的線程,每個線程類型具有不同的優先權和執行特性,各種線程從最高優先級到最低優先級排列如下:
- HWI(硬件中斷):包括了定時器函數
- SWI(軟件中斷):包括了CLOCK函數
- TASK(任務)
- IDLE(後臺空閒線程)
本文主要講解SYS/BIOS中的HWI線程。HWI也成爲中斷服務程序(ISR)是SYS/BIOS中具有最高優先級的線程:
從上圖可以看出,在我們編寫一個main程序時,其後臺的處理流程是:先進行初始化,緊接着執行BIOS_start函數,執行SYS/BIOS中的HWI線程,處理完成後纔會執行空閒的循環線程。
鉤子:HWI,SWI,TASK線程在線程生命週期內可以提供插入點來插入用戶代碼,方便調試代碼,每個這種代碼叫做一個“鉤子”,提供給鉤子的函數叫鉤子函數。
HWI線程具有以下5種鉤子函數:
-
Register:在靜態創建的HWI下,運行時被初始化前調用的一個函數。在main函數前啓動,並且在中斷使能之前。
-
Create:創建HWI時調用的一個函數,包含靜態創建與動態創建。
-
Begin:在運行ISR函數前調用的一個函數。
-
End:在ISR運行完後調用的一個函數。
-
Delete:在運行時刪除HWI線程的一個函數 。
動態創建HWI線程:
hwi0是一個創建HWI對象的句柄,id是定義的中斷號,hwiFunc是與中斷相關的函數名,hwiParams是一個結構體,這裏將其參數設置爲5。eb是一個錯誤塊,通過它處理在創建硬件中斷對象時可能發生的錯誤。
靜態創建HWI線程:
結果與上面相同。
鉤子函數的結構體定義如下:
registerFxn:保存鉤組中的鉤子ID,該ID可以傳遞給Hwi_setHookContext、Hwi_getHookContext函數,分別用於設置和獲取鉤子定義的上下文。
createFxn:在任何時候HWI被創建時調用。
beginFxn:在調用ISR函數前被調用。
endFxn:從ISR函數返回時激活。
deleteFxn:刪除HWI時調用。
Hwi Hooks Example:
C code:
/* ======== HwiHookExample.c ========
* This example demonstrates basic Hwi hook usage. */
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Timestamp.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/hal/Timer.h>
#include <ti/sysbios/hal/Hwi.h>
extern Timer_Handle myTimer;
volatile Bool myEnd2Flag = FALSE;
Int myHookSetId1, myHookSetId2;
//Error_Block eb;
//Error_init(&eb);
/* HookSet 1 functions */
/* ======== myRegister1 ========
* invoked during Hwi module startup before main()
* for each HookSet */
Void myRegister1(Int hookSetId)//由registerFxn創建,在寄存器鉤子啓動時,main之前調用。以鉤子ID順序調用
{
System_printf("myRegister1: assigned hookSet Id = %d\n", hookSetId);
myHookSetId1 = hookSetId;
}
/* ======== myCreate1 ========
* invoked during Hwi module startup before main()
* for statically created Hwis */
Void myCreate1(Hwi_Handle hwi, Error_Block *eb)//由createFxn創建,當Hwi被創建時調用此函數,根據hookSetId順序激活相應的創建函數
{
Ptr pEnv;
pEnv = Hwi_getHookContext(hwi, myHookSetId1);//保存鉤組定義信息
/* pEnv should be 0 at this point. If not, there's a bug. */
System_printf("myCreate1: pEnv = 0x%x, time = %d\n", pEnv, Timestamp_get32());
Hwi_setHookContext(hwi, myHookSetId1, (Ptr)0xdead1);//初始設置上下文指針
}
/* ======== myBegin1 ========
* invoked before Timer Hwi func */
Void myBegin1(Hwi_Handle hwi)//由myBegin1創建,在調用isr前激活
{
Ptr pEnv;
pEnv = Hwi_getHookContext(hwi, myHookSetId1);//獲取上下文指針
System_printf("myBegin1: pEnv = 0x%x, time = %d\n", pEnv, Timestamp_get32());
Hwi_setHookContext(hwi, myHookSetId1, (Ptr)0xbeef1);
}
/* ======== myEnd1 ========
* invoked after Timer Hwi func */
Void myEnd1(Hwi_Handle hwi)//從ISR函數返回時被激活
{
Ptr pEnv;
pEnv = Hwi_getHookContext(hwi, myHookSetId1);
System_printf("myEnd1: pEnv = 0x%x, time = %d\n", pEnv, Timestamp_get32());
Hwi_setHookContext(hwi, myHookSetId1, (Ptr)0xc0de1);
}
/* HookSet 2 functions */
/* ======== myRegister2 ========
* invoked during Hwi module startup before main
* for each HookSet */
Void myRegister2(Int hookSetId)
{
System_printf("myRegister2: assigned hookSet Id = %d\n", hookSetId);
myHookSetId2 = hookSetId;
}
/* ======== myCreate2 ========
* invoked during Hwi module startup before main
* for statically created Hwis */
Void myCreate2(Hwi_Handle hwi, Error_Block *eb)
{
Ptr pEnv;
pEnv = Hwi_getHookContext(hwi, myHookSetId2);
/* pEnv should be 0 at this point. If not, there's a bug. */
System_printf("myCreate2: pEnv = 0x%x, time = %d\n", pEnv, Timestamp_get32());
Hwi_setHookContext(hwi, myHookSetId2, (Ptr)0xdead2);
}
/* ======== myBegin2 ========
* invoked before Timer Hwi func */
Void myBegin2(Hwi_Handle hwi)
{
Ptr pEnv;
pEnv = Hwi_getHookContext(hwi, myHookSetId2);
System_printf("myBegin2: pEnv = 0x%x, time = %d\n", pEnv, Timestamp_get32());
Hwi_setHookContext(hwi, myHookSetId2, (Ptr)0xbeef2);
}
/* ======== myEnd2 ========
* invoked after Timer Hwi func */
Void myEnd2(Hwi_Handle hwi)
{
Ptr pEnv;
pEnv = Hwi_getHookContext(hwi, myHookSetId2);
System_printf("myEnd2: pEnv = 0x%x, time = %d\n", pEnv, Timestamp_get32());
Hwi_setHookContext(hwi, myHookSetId2, (Ptr)0xc0de2);
myEnd2Flag = TRUE;
}
/* ======== myTimerFunc ========
* Timer interrupt handler */
Void myTimerFunc(UArg arg)
{
System_printf("Entering myTimerHwi\n");
}
/* ======== myTaskFunc ======== */
Void myTaskFunc(UArg arg0, UArg arg1)
{
System_printf("Entering myTask.\n");
Timer_start(myTimer);//定時器啓動
/* wait for timer interrupt and myEnd2 to complete */
while (!myEnd2Flag) {
;
}
System_printf("myTask exiting ...\n");
}
/* ======== myIdleFunc ======== */
Void myIdleFunc()
{
System_printf("Entering myIdleFunc().\n");
System_exit(0);
}
//main之前先執行鉤子寄存器函數
/* ======== main ======== */
Int main(Int argc, Char* argv[])
{
System_printf("Starting HwiHookExample...\n");//執行完寄存器函數再執行這裏
BIOS_start();//main函數後調用Bios_start函數
return (0);
}
CFG配置文件:
/* pull in Timestamp to print time in hook functions */
xdc.useModule('xdc.runtime.Timestamp');
/* Disable Clock so that ours is the only Timer allocated */
var BIOS = xdc.useModule('ti.sysbios.BIOS');
BIOS.clockEnabled = false;
var Idle = xdc.useModule('ti.sysbios.knl.Idle');
Idle.addFunc('&myIdleFunc');
/* Create myTask with default task params */
var Task = xdc.useModule('ti.sysbios.knl.Task');
var taskParams = new Task.Params();
Program.global.myTask = Task.create('&myTaskFunc', taskParams);
/* Create myTimer as source of Hwi */
var Timer = xdc.useModule('ti.sysbios.hal.Timer');
var timerParams = new Timer.Params();
timerParams.startMode = Timer.StartMode_USER;
timerParams.runMode = Timer.RunMode_ONESHOT;
timerParams.period = 1000; // 1ms
Program.global.myTimer = Timer.create(Timer.ANY, "&myTimerFunc", timerParams);
/* Define and add two Hwi HookSets
* Notice, no deleteFxn is provided.
*/
var Hwi = xdc.useModule('ti.sysbios.hal.Hwi');//創建Hwi
/* Hook Set 1 */
Hwi.addHookSet({ //創建鉤子集:不包含deleteFxn
registerFxn: '&myRegister1',//寄存器函數:在系統初始化時,中斷使能前被調用
createFxn: '&myCreate1', //創建函數:在Hwi創建時被調用
beginFxn: '&myBegin1', //開始鉤子函數:在中斷全局禁止時被調用,在調用ISR函數前激活
endFxn: '&myEnd1', //結束鉤子函數:從ISR函數返回時被激活
});
/* Hook Set 2 */
Hwi.addHookSet({
registerFxn: '&myRegister2',
createFxn: '&myCreate2',
beginFxn: '&myBegin2',
endFxn: '&myEnd2',
});
運行結果:
程序執行順序:
-
首先執行寄存器函數,由registerFxn創建的myRegister1和myRegister2函數,鉤子ID分別爲0,1。同時將hookSetId傳遞給Hwi_getHookContext和Hwi_setHookContext。
-
執行由createFxn創建的myCreate1和myCreate2函數,通過Hwi_getHookContext的返回值得到鉤子指針信息。Hwi_setHookContext設置指針信息值。
-
執行main函數中的System_printf("Starting HwiHookExample...\n")。
-
啓動BIOS_start,執行創建的任務函數myTaskFunc,啓動定時器中斷,即硬件中斷。
-
執行由beginFxn創建的myBegin1和myBegin2函數,在正要運行ISR函數前調用。
-
執行ISR的myTimerFunc函數。
-
在執行完ISR函數後執行由endFxn創建的myEnd1和myEnd2函數。
-
當myEnd2函數執行完畢後返回標誌位,表示定時器中斷執行完畢。打印System_printf("myTask exiting ...\n")。
-
空閒線程優先級最低,因此最後執行由Idle創建的myIdleFunc函數。