1、SYS/BIOS--HWI

在SYS/BIOS中,一個線程就是控制單點,它能夠激活一個函數的調用,或者是激活一段中斷服務程序(ISR)。SYS/BIOS中提供了一系列具有不同屬性的線程,每個線程類型具有不同的優先權和執行特性,各種線程從最高優先級到最低優先級排列如下:

  1. HWI(硬件中斷):包括了定時器函數
  2. SWI(軟件中斷):包括了CLOCK函數
  3. TASK(任務)
  4. IDLE(後臺空閒線程)

本文主要講解SYS/BIOS中的HWI線程。HWI也成爲中斷服務程序(ISR)是SYS/BIOS中具有最高優先級的線程:

 從上圖可以看出,在我們編寫一個main程序時,其後臺的處理流程是:先進行初始化,緊接着執行BIOS_start函數,執行SYS/BIOS中的HWI線程,處理完成後纔會執行空閒的循環線程。

鉤子:HWI,SWI,TASK線程在線程生命週期內可以提供插入點來插入用戶代碼,方便調試代碼,每個這種代碼叫做一個“鉤子”,提供給鉤子的函數叫鉤子函數。

HWI線程具有以下5種鉤子函數:

  1. Register:在靜態創建的HWI下,運行時被初始化前調用的一個函數。在main函數前啓動,並且在中斷使能之前。

  2. Create:創建HWI時調用的一個函數,包含靜態創建與動態創建。

  3. Begin:在運行ISR函數前調用的一個函數。

  4. End:在ISR運行完後調用的一個函數。

  5. 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',
});

運行結果:

程序執行順序:

  1. 首先執行寄存器函數,由registerFxn創建的myRegister1和myRegister2函數,鉤子ID分別爲0,1。同時將hookSetId傳遞給Hwi_getHookContext和Hwi_setHookContext。

  2. 執行由createFxn創建的myCreate1和myCreate2函數,通過Hwi_getHookContext的返回值得到鉤子指針信息。Hwi_setHookContext設置指針信息值。

  3. 執行main函數中的System_printf("Starting HwiHookExample...\n")。

  4. 啓動BIOS_start,執行創建的任務函數myTaskFunc,啓動定時器中斷,即硬件中斷。

  5. 執行由beginFxn創建的myBegin1和myBegin2函數,在正要運行ISR函數前調用。

  6. 執行ISR的myTimerFunc函數。

  7. 在執行完ISR函數後執行由endFxn創建的myEnd1和myEnd2函數。

  8. 當myEnd2函數執行完畢後返回標誌位,表示定時器中斷執行完畢。打印System_printf("myTask exiting ...\n")。

  9. 空閒線程優先級最低,因此最後執行由Idle創建的myIdleFunc函數。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章