本帖最后由 msblast 于 2013-12-25 14:55 编辑
本例中使用到的BIOS的组件有BUF,QUE,MBX,PRD,TSK等,现在将这过程与大家分享。
一、新建一个优先级最高的task,如下图
二、软件通用定时器
因为在软件运行过程中,有很多地方需要用到定时。所以写了一个软件定时器,方便使用。
在BIOS中配置,如下图
每一个定时器实例都给分配了内存空间,这是通过BIOS的内存池来实现的,如下图
CtmrCreate/CtmrRelease就是基于这个内存池来实现的
通用定时器的CtmrStart/CtmrStop是通过队列的入列和出列来实现的,也是用的BIOS的队列机制,如下图
队列的数据存储空间也是基于BIOS的BUF组件实现的,如下图
代码实现如下
- /*Ctmr.h*/
- #ifndef __CTMR_H__
- #define __CTMR_H__
- #include <std.h>
- #include <log.h>
- #include <mem.h>
- #include <que.h>
- #include <sys.h>
- #include <tsk.h>
- typedef void (*fxn_ptr)(void);
- typedef void (*fxn_tmr_cb)(void *cb);
- typedef struct _Ctmr {
- Int32 tmrcnt;
- Int32 delay;
- Int32 exe_times;
- Int32 execnt;
- void *params;
- fxn_tmr_cb cb;
- Uint8 bSync;
- } CtmrObj;
- typedef struct _CtmrQ_Obj {
- QUE_Elem elem;
- CtmrObj *ct;
- } CtmrQ_Obj, *CtmrQ;
- #define CTMR_BASIC_TICK (10)
- #define CTMR_EXE_FOR_EVER (0)
- Uint32 CtmrCreate(Int32 dly, Int32 exe_times, void *params, fxn_tmr_cb cb);
- void CtmrRelease(Uint32 nHdlr);
- void CtmrStart(Uint32 nHdlr);
- void CtmrStop(Uint32 nHdlr);
- void CtmrExeCB(Uint32 nHdlr);
- #endif
- /*Ctmr.c*/
- #include <std.h>
- #include <tsk.h>
- #include <stdio.h>
- #include "timer.h"
- #include "c6x.h"
- #include "ctrl_task.h"
- #include "ctmr.h"
- #include "xxxcfg.h"
- /*xxxcfg.h由配置工具自动生成*/
- /*CtmrCreate给一个新创建的定时器实例分配内存并进行初始化,然后返回内存地址,如果分配不到内存则返回0*/
- Uint32 CtmrCreate(Int32 dly, Int32 exe_times, void *params, fxn_tmr_cb cb) {
- Uint32 nHdlr = 0;
- CtmrObj *hTmr = 0;
- do {
- hTmr = (CtmrObj *)BUF_alloc(&Ctmr);
- if(!hTmr) {
- break;
- }
- if(!dly) {
- dly = CTMR_BASIC_TICK;
- }
- dly = ((dly+(CTMR_BASIC_TICK-1))/CTMR_BASIC_TICK)*CTMR_BASIC_TICK;
- hTmr->cb = cb;
- hTmr->delay = dly;
- hTmr->tmrcnt = 0;
- hTmr->exe_times = exe_times;
- hTmr->execnt = 0;
- hTmr->params = params;
- hTmr->bSync = 0;
- nHdlr = (Uint32)hTmr;
- }while(0);
- return nHdlr;
- }
- /*CtmrRelease释放给定时器实例分配的内存,在这之前先关闭定时器,这主要是防止使用的人忘记停止定时器*/
- void CtmrRelease(Uint32 nHdlr) {
- CtmrObj *hTmr = (CtmrObj *)nHdlr;
- if(hTmr) {
- CtmrStop((Uint32)hTmr);
- BUF_free(&Ctmr, (void *)hTmr);
- }
- }
- /*CtmrStart启动一个定时器,将定时器实例加入队列;如果这个定时器实例之前已在队列中则先移出队列*/
- void CtmrStart(Uint32 nHdlr) {
- Uns oldCSR;
- CtmrObj *hTmr = (CtmrObj *)nHdlr;
- CtmrQ ctqelem = 0;
- QUE_Elem *qelem = QUE_head(&CtmrQue);
- if(hTmr) {
- while (qelem != &CtmrQue) {
- if(((CtmrQ)qelem)->ct == hTmr) {
- break;
- }
- qelem = QUE_next(qelem);
- }
- if (qelem != &CtmrQue) {
- oldCSR = HWI_disable();
- QUE_remove(qelem);
- HWI_restore(oldCSR);
- BUF_free(&CtmrQueBuf, (void *)qelem);
- }
- ctqelem = (CtmrQ)BUF_alloc(&CtmrQueBuf);
- if(ctqelem) {
- hTmr->tmrcnt = 0;
- hTmr->execnt = 0;
- hTmr->bSync = 0;
- ctqelem->ct = hTmr;
- oldCSR = HWI_disable();
- QUE_put(&CtmrQue, ctqelem);
- HWI_restore(oldCSR);
- }
- }
- }
- /*CtmrStop将定时器实例移出队列,并释放为队列分配的内存*/
- void CtmrStop(Uint32 nHdlr) {
- Uns oldCSR;
- CtmrObj *hTmr = (CtmrObj *)nHdlr;
- QUE_Elem *qelem = QUE_head(&CtmrQue);
- if(hTmr) {
- while (qelem != &CtmrQue) {
- if(((CtmrQ)qelem)->ct == hTmr) {
- break;
- }
- qelem = QUE_next(qelem);
- }
-
- if (qelem != &CtmrQue) {
- oldCSR = HWI_disable();
- QUE_remove(qelem);
- HWI_restore(oldCSR);
- BUF_free(&CtmrQueBuf, (void *)qelem);
- }
- }
- }
- /*CtmrExeCB执行CtmrCreate注册的回调函数*/
- void CtmrExeCB(Uint32 nHdlr) {
- CtmrObj *hTmr = (CtmrObj *)nHdlr;
- if(hTmr) {
- if(hTmr->cb) {
- hTmr->cb(hTmr);
- }
- }
- }
- /*CtmrExe在prd_tmr中周期执行*/
- void CtmrExe(void) {
- MsgObj msg;
- CtmrObj *hTmr = 0;
- QUE_Elem *qelem = QUE_head(&CtmrQue);
- while (qelem != &CtmrQue) {
- hTmr = ((CtmrQ)qelem)->ct;
- if(hTmr) {
- if(hTmr->bSync) {
- hTmr->tmrcnt++;
- if((hTmr->tmrcnt*CTMR_BASIC_TICK) == hTmr->delay) {
- msg.id = EVT_IND_CTMR_EXE_CB;
- msg.val = (Uint32)hTmr;
- MBX_post(&CtrlEvt, &msg, 0);
- hTmr->tmrcnt = 0;
- if(hTmr->exe_times != VTIMER_EXE_FOR_EVER) {
- hTmr->execnt++;
- if(hTmr->execnt == hTmr->exe_times) {
- msg.id = EVT_IND_CTMR_EXE_POST_CB;
- msg.val = (Uint32)hTmr;
- MBX_post(&CtrlEvt, &msg, 0);
- }
- }
- }
- }
- else {
- hTmr->bSync = 1;
- }
- }
- qelem = QUE_next(qelem);
- }
- }
- void prd_tmr() {
- CtmrExe();
- }
通用定时器的使用,遵守以下步骤
1.CtmrCreate,创建一个定时器实例
2.CtmrStart,启动定时器实例
3.CtmrStop,停止定时器实例,定时器实例仍然存在,没有销毁
4.CtmrRelease,销毁定时器实例
三、使用mailbox实现事件驱动架构
事件驱动的架使得代码看起来更清晰明了,基于BIOS的MBX和BUF实现的,如下
代码实现如下
- /*Ctrl_task.h*/
- #ifndef __CTRL_TASK_H__
- #define __CTRL_TASK_H__
- #include<stdlib.h>
- #include "ctmr.h"
- .
- .
- .
- typedef struct MsgObj {
- Uint32 id; /* event id */
- Uint32 val; /* message value , address of content*/
- } MsgObj, *Msg;
- enum {
- .
- .
- .
- ,EVT_IND_CTMR_EXE_CB
- ,EVT_IND_CTMR_EXE_POST_CB
- .
- .
- .
- ,EVT_NUM
- };
- .
- .
- .
- #endif
- /*Ctrl_task.c*/
- #include <std.h>
- #include <c6x.h>
- #include "pal_os.h"
- #include "psputils.h"
- #include "ctrl_task.h"
- #include "xxxcfg.h"
- /*xxxcfg.h由配置工具自动生成*/
- .
- .
- .
- void Task_Ctrl(){
- MsgObj msg;
- Uint32 Evtid;
- .
- .
- .
- do {
- if (MBX_pend(&CtrlEvt, &msg, SYS_FOREVER)) {
- Evtid = msg.id;
- switch(Evtid) {
- .
- .
- .
- case EVT_IND_CTMR_EXE_CB:
- CtmrExeCB((Uint32) msg.val);
- break;
- case EVT_IND_CTMR_EXE_POST_CB:
- CtmrStop((Uint32)msg.val);
- break;
- default:break;
- }
- }
- }while(1);
- }
四、一些体会和建议
掌握通过通用定时器和事件驱动框架,可以很方便的扩展和衍生出很多的功能。
有些问题是在实践过程中才逐步暴露出来的,一段成熟的代码需要一个不断完善的过程。
有细心的童鞋会发现我没有用malloc/free和MEM_alloc/MEM_free,而是用了BUF_alloc/BUF_free 。如果你没有经过我的提醒就意识到了这个问题,我会很高兴看到同道。是的,BIOS HWI中不允许调用malloc/free和MEM_alloc/MEM_free。另外,就算是在TSK中也不要过于频繁的调用malloc/free和MEM_alloc/MEM_free。这是我的体会,也是建议。
你也可以来补充。
|