基于TI-RTOS的CC2650DK开发(10)---空闲循环

3.7 The Idle Loop
Idle Loop是 SYS/BIOS中的后台线程,在没有Hwi、Swi或Task时持续运行。任何其它线程在任何时间可抢占Idle Loop。

Idle管理器允许你在Idle Loop中插入函数运行。在configured. Idle_loop中会调用的每个Idle对象所相联的函数。Idle Loop每次调用一个函数,并在一个连续循环中往复调用所有函数。

所有Idle线程都按顺序运行于相同的优先级。函数按照创建的顺序依次运行。一个Idle函数必须完成后才会开始另一个Idle函数。当最后一个Idle函数完成,则又重新运行第一个Idle函数。

Idle Loop函数经常用于轮询那些不会(或不能)产生中断的非时实设备,用于监测系统状态或执行其它后台活动。

在SYS/BIOS应用程序中,Idle Loop的优先级最低,仅在没有Hwis、Swis或Tasks时运行。

CPU和线程的载入是在Idle Loop函数中计算完成的(目标和主机间的数据传送由一个低优先级task完成)。

如果在配置文件中将Task.enableIdleTask设置为false,将无法创建Idle任务并不会执行Idle函数。如果你希望在没有其它线程准备运行时运行一个函数,可以使用Task.allBlockedFunc来指定这样的函数。

如果你希望在无需创建一个专用Idle task的情况下执行Idle Loop,可以禁用Task.enableIdleTask,并按以下方法配置Task.allBlockedFunc。这类声明将导致Idle运行栈中最后一个等待的Task。
Task.enableIdleTask =  false;
Task.allBlockedFunc = Idle.run;

3.8 使用Hwi、Swi和Task线程的例子
此例描述了程式化版本的SYS/BIOS时钟模块设计。它联合使用了Hwi、Swi和Task线程。

一个周期计时器中断提交一个Swi用于处理时钟对象列表。时钟对象列表中的每个条目都拥有它自己的周期和时钟函数。当一个对象的时间到期,时钟函数被调用,周期重新开始。

由于没有限制列表中可旋转时钟对象的个数,也无法确定每个时钟函数的开销,所以维护所有时钟对象所消耗的时间也无法确定。因此,在计时器的Hwi线程中维护时钟对象是不切实际的。此类问题使用Swi来解决更能成为轻量级解决方案(相对使用Task来说)。
(书上的代码还是无法直接运行,还得改,但发现改着改着也改习惯了,呵呵)
C代码:
#include <xdc/std.h>
#include <xdc/runtime/System.h>
#include <xdc/runtime/Error.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/hal/Timer.h>
#include <ti/sysbios/knl/Semaphore.h>
#include <ti/sysbios/knl/Swi.h>
#include <ti/sysbios/knl/Task.h>
#include <ti/sysbios/knl/Queue.h>
#include <xdc/cfg/global.h>

typedef  struct
{
    Queue_Elem elem;
    UInt32 timeout;
    UInt32 period;
    Void (*fxn)(UArg);
    UArg arg;
} Clock_Object;

Clock_Object clk1, clk2;
Timer_Handle timer;
Semaphore_Handle sem;
Swi_Handle swi;
Task_Handle task;
Queue_Handle clockQueue;
/* Here on Timer interrupt */
Void hwiFxn(UArg arg)
{
    Swi_post(swi);
}
/* Swi thread to handle Timer interrupt */
Void swiFxn(UArg arg1, UArg arg2)
{
    Queue_Elem *elem;
    Clock_Object *obj;
     /* point to first clock object in the clockQueue */
    elem = Queue_next((Queue_Elem *)clockQueue);
     /* service all the Clock Objects in the clockQueue */
     while (elem != (Queue_Elem *)clockQueue)
    {
        obj = (Clock_Object *)elem;
         /* decrement the timeout counter */
        obj->timeout -=  1;
         /* if period has expired, refresh the timeout
        * value and invoke the clock func */

         if (obj->timeout ==  0)
        {
            obj->timeout = obj->period;
            (obj->fxn)(obj->arg);
        }
         /* advance to next clock object in clockQueue */
        elem = Queue_next(elem);
    }
}
/* Task thread pends on Semaphore posted by Clock thread */
Void taskFxn(UArg arg1, UArg arg2)
{
    System_printf( "In taskFxn pending on Sempahore.\n");
    Semaphore_pend(sem, BIOS_WAIT_FOREVER);
    System_printf( "In taskFxn returned from Sempahore.\n");
    System_exit( 0);
}
/* First Clock function, invoked every 5 timer interrupts */
Void clk1Fxn(UArg arg)
{
    System_printf( "In clk1Fxn, arg = %d.\n", arg);
    clk1.arg++;
}
/* Second Clock function, invoked every 20 timer interrupts */
Void clk2Fxn(UArg sem)
{
    System_printf( "In clk2Fxn, posting Semaphore.\n");
    Semaphore_post((Semaphore_Object *)sem);
}
/* main() */
Int main(Int argc,  char *argv[])
{
    Timer_Params timerParams;
    Task_Params taskParams;
    Error_Block eb;
    System_printf( "Starting HwiSwiTask example.\n");
    Error_init(&eb);
    Timer_Params_init(&timerParams);
    Task_Params_init(&taskParams);
     /* Create a Swi with default priority (15).
    * Swi handler is 'swiFxn' which runs as a Swi thread. */

    swi = Swi_create(swiFxn,  NULL, &eb);
     if (swi ==  NULL)
    {
        System_abort( "Swi create failed");
    }
     /* Create a Task with priority 3.
    * Task function is 'taskFxn' which runs as a Task thread. */

    taskParams.priority =  3;
    task = Task_create(taskFxn, &taskParams, &eb);
     if (task ==  NULL)
    {
        System_abort( "Task create failed");
    }
     /* Create a binary Semaphore for example task to pend on */
    sem = Semaphore_create( 0NULL, &eb);
     if (sem ==  NULL)
    {
        System_abort( "Semaphore create failed");
    }
     /* Create a Queue to hold the Clock Objects on */
    clockQueue = Queue_create( NULL, &eb);
     if (clockQueue ==  NULL)
    {
        System_abort( "Queue create failed");
    }
     /* setup clk1 to go off every 5 timer interrupts. */
    clk1.fxn = clk1Fxn;
    clk1.period =  5;
    clk1.timeout =  5;
    clk1.arg =  1;
     /* add the Clock object to the clockQueue */
    Queue_put(clockQueue, &clk1.elem);
     /* setup clk2 to go off every 20 timer interrupts. */
    clk2.fxn = clk2Fxn;
    clk2.period =  20;
    clk2.timeout =  20;
    clk2.arg = (UArg)sem;
     /* add the Clock object to the clockQueue */
    Queue_put(clockQueue, &clk2.elem);
     /* Configure a periodic interrupt using any available Timer
    * with a 1000 microsecond (1ms) interrupt period.
    *
    * The Timer interrupt will be handled by 'hwiFxn' which
    * will run as a Hwi thread.
    */

    timerParams.period =  1000;
    timer = Timer_create(Timer_ANY, hwiFxn, &timerParams, &eb);
     if (timer ==  NULL)
    {
        System_abort( "Timer create failed");
    }
    BIOS_start();
     return( 0);
}

配置文件cfg代码:
/* ======== HwiSwiTaskExample.cfg ======== */
var Defaults = xdc.useModule( 'xdc.runtime.Defaults');
var Diags = xdc.useModule( 'xdc.runtime.Diags');
var Error = xdc.useModule( 'xdc.runtime.Error');
var Log = xdc.useModule( 'xdc.runtime.Log');
var LoggerBuf = xdc.useModule( 'xdc.runtime.LoggerBuf');
var Main = xdc.useModule( 'xdc.runtime.Main');
var Memory = xdc.useModule( 'xdc.runtime.Memory')
var SysMin = xdc.useModule( 'xdc.runtime.SysMin');
var System = xdc.useModule( 'xdc.runtime.System');
var Text = xdc.useModule( 'xdc.runtime.Text');
var BIOS = xdc.useModule( 'ti.sysbios.BIOS');
var Task = xdc.useModule( 'ti.sysbios.knl.Task');
var Semaphore = xdc.useModule( 'ti.sysbios.knl.Semaphore');
var Queue = xdc.useModule( 'ti.sysbios.knl.Queue');
var Hwi = xdc.useModule( 'ti.sysbios.hal.Hwi');
var HeapMem = xdc.useModule( 'ti.sysbios.heaps.HeapMem');
var Timer = xdc.useModule( 'ti.sysbios.hal.Timer');
Program.argSize = 0x0;
System.maxAtexitHandlers =  4;
BIOS.heapSize = 0x2000;
/* System stack size (used by ISRs and Swis) */
Program.stack = 0x1000;
/* Circular buffer size for System_printf() */
SysMin.bufSize = 0x400;
/* Create and install logger for the whole system */
var loggerBufParams =  new LoggerBuf.Params();
loggerBufParams.numEntries =  32;
var logger0 = LoggerBuf.create(loggerBufParams);
Defaults.common$.logger = logger0;
Main.common$.diags_INFO = Diags.ALWAYS_ON;
System.SupportProxy = SysMin;
BIOS.libType = BIOS.LibType_Custom;

运行结果:
[Cortex_M3_0] Starting HwiSwiTask example.
In taskFxn pending on Sempahore.
In clk1Fxn, arg =  1.
In clk1Fxn, arg =  2.
In clk1Fxn, arg =  3.
In clk1Fxn, arg =  4.
In clk2Fxn, posting Semaphore.
In taskFxn returned from Sempahore.

这个程序演示了如何用Hwi和Swi模拟一个时钟,注意,不是系统自带的那个时钟'ti.sysbios.knl.Clock'。我估计实现原理我系统自带时钟会有似之处吧。

计时这块使用的是系统的timer,我们知道它是硬中断,但硬中断用来处理复杂操作肯定不合适,所以在硬中断中只是简单调用Swi_post,把真正的处理交由Swi进行。Swi实际就是计算每个时钟是否到期,如果到期就触发相应的函数。模拟出来的时钟1是一个周期时钟,重复运行;时钟2则是一个单周期(one shot)时钟,用于关闭程序。当然,它也不是直接关闭,而是通过一个信号量发信号给task来关闭。

通过这个例子,我们也可以了解到timer(计时器)和clock(时钟)的区别。timer属硬中断,执行那些操作少,对时间要求极为精准的操作。clock属软中断,执行那些操作复杂,对时间要求不太精准的操作。我们已经看到在Swi函数中,需要遍历时钟列表,并一一进行操作,这样是无法保证时间非常精准的。

有了这个思路再去看代码,相信会简单很多,我就不哆嗦了。这回总算是把TI-RTOS中的所有线程给学完了,当然,这远远不够,估计我得把这本书翻译完。好在翻译这类文章比翻译RFC文档容易得多了
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值