【沁恒 CH58x 应用】如何使用 TMOS 系统自定义新 Task

自定义新Task的一般步骤

//做好使用TMOS的预备工作,调用以下函数:
//0. 初始化好GPIO、串口等外设
//1. 初始化蓝牙:
CH58X_BLEInit();//(注意,此处不能省略!!!这里分配了任务链表的内存,如果没有分配后续将无法正确执行)
//2. 初始化时钟
while(!(SUCCESS == TMOS_TimerInit(0)))
{
    PRINT("Timer Init failed!\n");
    DelayMs(1000);
}
PRINT("Timer Init succeed!\n");

int ret = 0;
//3-注册task id,同时把该task的event处理函数传进去
demo_task_id  = TMOS_ProcessEventRegister( demo_task_process_event );
if(demo_task_id ==INVALID_TASK_ID)
{
    PRINT("TaskID is INVALID!!!\n");
}else {
    PRINT("TaskID SUCCEED!!!\n");
    PRINT("TaskID=%d\n", demo_task_id);
}
//4. 设置任务工作方式:方式1:立即开始一个event
ret = tmos_set_event(demo_task_id,DEMO_TASK_TMOS_EVT_TEST_1);
if(ret!=SUCCESS)
{
    PRINT("tmos_set_event FAILED\n");
}else {
    PRINT("tmos_set_event SUCCEED\n");
}
//4. 设置任务工作方式:方式2:开始一个定时event,1s后产生,当前语句只会产生一次event
//可以在event产生后去开启event,可以是别的task的,也可以是当前task的event
ret = tmos_start_task(demo_task_id,DEMO_TASK_TMOS_EVT_TEST_2,1600);
if(ret!=TRUE)
{
    PRINT("tmos_start_task FAILED\n");
}else {
    PRINT("tmos_start_task SUCCEED\n");
}

//5. 最后,无限循环执行TMOS_SystemProcess()
while(1)
{
    TMOS_SystemProcess();
}

 

扩展:认识 TMOS 到底是什么?

介绍:TMOS是沁恒微针对蓝牙协议栈开发的简化版的闭源OSAL,一种以实现多任务为核心的系统资源调度机制。量级小于FreeRtos/TI的SYSBIOS等最小系统。主要服务于协议栈的闭源解耦。对于单芯片用户态能实现ble复合设备(observer+center、center+perioheral等)非常关键。

原理:TMOS是通过时间片轮询实现多任务调度运行,系统时钟来源于芯片RTC,单位为625us。用户通过注册各种任务Task或者说是线程Thread,用户将自定义的隶属于某个Task的各种触发、定时事件Event添加到对应的任务链表中,由OS进行调度运行。Task注册API会分配一个ID,用户可以做操作任务/事件的句柄,ID同时作为OS调度(遍历Task链表)的优先级(越小优先级越高), 每个Task最多包含16个Event,其中包括缺省的1个消息事件SYS_EVENT_MSG (0x8000)和15个自定义事件,采用位带的方式定义Event标志,这里不再赘述。

API:

从API可以看出TMOS的api比较精简,不提供信号量、通知、邮箱等OS组件,但是对于BLE开发是完全够用的

库函数

extern uint32_t tmos_rand( void ); // pseudo-random number
extern BOOL tmos_memcmp( const void *src1, const void *src2, uint32_t len ); // TRUE - same, FALSE - different
extern BOOL tmos_isbufset( uint8_t *buf, uint8_t val, uint32_t len ); // TRUE if all "val",FALSE otherwise
extern uint32_t tmos_strlen( char *pString );
extern void tmos_memset( void * pDst, uint8_t Value, uint32_t len );
extern void tmos_memcpy( void *dst, const void *src, uint32_t len ); // Generic memory copy.

常用的主要触发Event接口、定时Event接口、系统Task注册、系统初始化和启动

//定义任务,向系统注册任务,这里可以理解为注册一个线程,入参:事件的回调函数
extern tmosTaskID TMOS_ProcessEventRegister( pTaskEventHandlerFn eventCb );
//立即启动句柄为taskID任务中对应的某个event事件,调用一次执行一次
extern bStatus_t tmos_set_event( tmosTaskID taskID, tmosEvents event ); 
//定时625*time us执行句柄为taskID任务中对应的某个event事件,调用一次执行一次
extern bStatus_t tmos_start_task( tmosTaskID taskID, tmosEvents event, tmosTimer time );
//定时625*time us执行句柄为taskID任务中对应的某个event事件,调用一次循环执行
extern bStatus_t tmos_start_reload_task( tmosTaskID taskID, tmosEvents event, tmosTimer time );
//停止/删除系统内的一个定时事件
bStatus_t tmos_stop_task( tmosTaskID taskID, tmosEvents event );

//TMOS系统初始化,入参一般为0,表示用RTC 625us时基
extern bStatus_t TMOS_TimerInit( pfnGetSysClock fnGetClock );
//TMOS系统调度
extern void TMOS_SystemProcess( void );
注:上述函数不要在中断中调用

任务交互消息队列

//发送消息函数,对应句柄的Task的消息事件Event会立即生效(#define SYS_EVENT_MSG (0x8000))
extern bStatus_t tmos_msg_send( tmosTaskID taskID, uint8_t *msg_ptr );
// 接收消息函数,返回消息指针 注:接受以后的指针处理完需要tmos_msg_deallocate释放
extern uint8_t *tmos_msg_receive( tmosTaskID taskID );
//申请内存函数,入参申请的长度,返回内存指针,注:发送消息之前需要先给消息申请内存空间
extern uint8_t *tmos_msg_allocate( uint16_t len );
//释放消息占用内存的函数
extern bStatus_t tmos_msg_deallocate( uint8_t *msg_ptr );

FLASH操作,NV存储区

读:tmos_snv_read->readFlashCB->Lib_Read_Flash->EEPROM_READ
写:tmos_snv_write->writeFlashCB->Lib_Write_Flash->EEPROM_ERASE+EEPROM_WRITE
注:NV区的读写操作尽量在TMOS系统起来之前调用,不要频繁调用特别写的阻塞时间较长,特别是写操作,需要先擦除
extern uint8_t tmos_snv_read( uint8_t id, uint8_t len, void *pBuf );
extern uint8_t tmos_snv_write( uint8_t id, uint8_t len, void *pBuf );

 

转载自:https://zhuanlan.zhihu.com/p/454057990?utm_id=0

精华文章:

官方论坛答疑:《TMOS_ProcessEventRegister 返回0xff (无效taskid) 问题解决》https://www.wch.cn/bbs/thread-95834-1.html

posted @ 2023-12-13 22:51  FBshark  阅读(222)  评论(0编辑  收藏  举报