一 TMOS诞生背景
CH573是南京沁恒推出的一款Risc-V的BLE芯片,该芯片相比较于普通的Risc-V 32位单片机,又增加了BLE通讯功能和USB全速通讯功能。沁恒的BLE方案为软核方式,也就是说,该器件的数据编码部分完全由软件实现。 根据蓝牙通讯标准,蓝牙每隔625us需要进行一次跳频操作。为了维持稳定的主从蓝牙设备通讯,处理器必须每625us进行一次数据发送。 为了既满足于BLE通讯要求,又满足其他逻辑控制功能,实现处理器的分时复用,就需要一个机制进行精确的时间调度, TMOS就是在这样的一个需求背景下出现的。
二 TMOS是什么
TMOS作为调度核心,BLE协议栈、profile定义、所有的应用都围绕它来实现。TMOS是一个允许软件建立和执行事件的多任务循环调度系统。多任务管理方式在某一时刻实际上只有一个任务在运行,但是可以使用任务调度的策略将多个任务进行调度,每个任务占用一定的时间,所有的任务通过时间分片的方式处理。TMOS 系统的调度周期是 625us,以 RTC 为基准得到所有需要系统的时间,每隔625us,系统自动切换一次任务。
三 TMOS使用方法
TMOS主要由三个步骤来实现
1. Task ID 初始化
static unit8 Peripheral_TaskID = INVALID_TASK_ID;
Peripheral_TaskID 是您要新建的任务的ID号,这句语句给他赋一个无效的空值作为初始化
2. 创建 user_ProcessEvent 函数
uint16 user_ProcessEvent(uint8 task_id, uint16 events)
user_ProcessEvent是一个自定义的回调函数,用户在这个函数里写自己要要完成的业务代码。这个函数在任务函数注册后由系统调用,系统将返回两个参数:
task_id, 这是返回的调用该任务的taskID值,我们一般不用
events,传入的unit16参数,代表触发该人物函数的事件,沁恒公司的代码推荐按位使用,共有16个状态位,某个状态位被置1则意味着该状态位对应的事件触发了这个回调函数。除最高位被系统保留用来表示系统消息外,低位的15个状态位都可以由用户自定义,每个状态位的具体含义由用户自定义。
3. 任务函数注册并创建任务Task
Peripheral_TaskID = TMOS_ProcessEventRegister (user_ProcessEvent)
使用沁恒TMOS调度系统底层封装的 TMOS_ProcessEventResister 函数注册该任务, 并取得系统分配的 TaskID
4. 启动任务task
有两种方式启动task 一种是立即启动,使用这个底层系统函数可以立即执行user_TaskID所标识的任务函数
tmos_set_event(user_TaskID,events)
另一种是延迟启动,使用这个底层系统函数可以挂起user_TaskID所标识的任务函数一定时间后再执行,挂起的时间为625us的整倍数,调用参数为n,则延迟n*625us,
tmos_start_task(user_TaskID,events,n)
5 任务的循环执行
以上的两种任务执行方式都是单次执行,为了使任务能够定期重复执行,我们需要利用event事件,在回调函数里循环调用,当任务执行完成后,调用 tmos_start_task 函数,挂起一定时间后继续执行该任务
tmos_start_task(user_TaskID,events,n)
{
...
if (events & SBP_PERIODIC_EVENT)
{
//延迟6.25ms后再次执行该任务
tmos_start_task(user_TaskID,SBP_PERIODIC_EVT,10);
return(events ^ SBP_PERIODIC_EVT);
}
}
四 例子
下面我们以一个完整的例子介绍一下上面的整个内容,建立两个独立的TMOS任务,每隔0.625秒分别打印Task1 running 和 Task2 running
static tmosTaskID task1;
static tmosTaskID task2;
tmosEvents Task1_ProcessEvent( tmosTaskID task_id, tmosEvents events )
{
int * msgPtr;
if( events & 0x01 )
{
PRINT("%s\n","Task1 running");
tmos_start_task( task_id , 0x01 ,1000 ); // 0.625s 后循环启动
return events ^ 0x01;
}
return 0;
}
tmosEvents Task2_ProcessEvent( tmosTaskID task_id, tmosEvents events )
{
int * msgPtr;
if( events & 0x01 )
{
PRINT("%s\n","Task2 running");
tmos_start_task( task_id , 0x01 ,1000 ); // 0.625s 后循环启动
return events ^ 0x01;
}
return 0;
}
void TEST_Init( )
{
task1 = TMOS_ProcessEventRegister(Task1_ProcessEvent);
task2 = TMOS_ProcessEventRegister(Task2_ProcessEvent);
tmos_set_event(task1, 0x01); // 添加一个测试任务
tmos_set_event(task2, 0x01); // 添加一个测试任务
}
执行效果如下
Task1 running Task2 running ...
您可以在附件中下载例子源码,谢谢。 源文件下载