在SYS/BIOS中,一个线程就是控制单点,它能够激活一个函数的调用,或者是激活一段中断服务程序(ISR)。SYS/BIOS中提供了一系列具有不同属性的线程,每个线程类型具有不同的优先权和执行特性,各种线程从最高优先级到最低优先级排列如下:

  1. HWI(硬件中断):包括了定时器函数
  2. SWI(软件中断):包括了CLOCK函数
  3. TASK(任务)
  4. IDLE(后台空闲线程)

本文主要讲解SYS/BIOS中的HWI线程。HWI也成为中断服务程序(ISR)是SYS/BIOS中具有最高优先级的线程:

go2bios什么意思 gwi bios_System

 从上图可以看出,在我们编写一个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线程:

go2bios什么意思 gwi bios_System_02

 hwi0是一个创建HWI对象的句柄,id是定义的中断号,hwiFunc是与中断相关的函数名,hwiParams是一个结构体,这里将其参数设置为5。eb是一个错误块,通过它处理在创建硬件中断对象时可能发生的错误。

静态创建HWI线程: 

go2bios什么意思 gwi bios_#include_03

 结果与上面相同。

钩子函数的结构体定义如下:

go2bios什么意思 gwi bios_#include_04

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

运行结果:

go2bios什么意思 gwi bios_System_05

程序执行顺序:

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