本帖最后由 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。这是我的体会,也是建议。
你也可以来补充。
|