在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函数。