TMOS使用说明
1、TMOS简介
TMOS是沁恒微电子针对蓝牙协议栈开发的“操作系统”,是简化版的OSAL(Operating System Abstraction Layer),即操作系统抽象层,一种以实现多任务为核心的系统资源管理机制。简单而言,TMOS实现了类似操作系统的某些功能,但并不能称之为真正意义上的操作系统。
2、TMOS工作机制分析
TMOS是通过时间片轮询的方式实现多任务调度运行,实际上每次只有一个任务运行。系统时钟来源于芯片RTC,单位为625us。
用户通过注册任务(Task)将自定义的事件(Event)添加到TMOS的任务链表中,由TMOS进行调度运行。
每个Task注册后分配一个ID;每个Task最多包含16个Event,其中包括1个消息事件(0x8000)和15个自定义事件,采用BitMap的方式定义事件标志,如:(0x0001、0x0002、0x0004……0x8000)。
Event事件标志位,为1则运行,为0则不运行。
bit0 | bit1 | bit2 | bit3 | bit4 | bit5 | bit6 | bit7 | bit8 | bit9 | bit10 | bit11 | bit12 | bit13 | bit14 | bit15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 | 0/1 |
TMOS任务链表如下:
TMOS循环查询任务链表,根据任务ID确定优先级,越小越高。每个任务运行完一个事件后便通过异或的方式清除已运行的事件,同时return未运行的事件标志,接着运行下一个任务;当任务调度系统运行一遍后,再次回来运行任务链表头的一个事件,如此循环下去。
TMOS调度机制如下:
3、常用API分析
//注册任务,传入任务事件回调函数,返回任务ID。 tmosTaskID TMOS_ProcessEventRegister( pTaskEventHandlerFn eventCb ); //立即启动taskID任务中对应的event事件,事件只执行一次 bStatus_t tmos_set_event( tmosTaskID taskID, tmosEvents event ); //定时time*625us后启动taskID任务中对应的event事件,事件只执行一次 bStatus_t tmos_start_task( tmosTaskID taskID, tmosEvents event, tmosTimer time ); //停止一个定时事件 bStatus_t tmos_stop_task( tmosTaskID taskID, tmosEvents event ); //清理一个已经超时的event事件,不能在自己的event函数内执行 bStatus_t tmos_clear_event( tmosTaskID taskID, tmosEvents event ); //开始一个定时事件,不断的执行,除非运行tmos_stop_task关掉, bStatus_t tmos_start_reload_task( tmosTaskID taskID, tmosEvents event, tmosTimer time ); //获取对应taskID 和event 的最后一个周期时长,返回0是没有找到 tmosTimer tmos_get_task_timer( tmosTaskID taskID, tmosEvents event ); //TMOS时钟初始化 bStatus_t TMOS_TimerInit( pfnGetSysClock fnGetClock ); //返回tmos系统运行时长,单位为625us,如1600=1s uint32_t TMOS_GetSystemClock( void ); //tmos的系统处理函数,需要不断在主函数中运行 void TMOS_SystemProcess( void ); /**************消息相关*************/ //发送消息函数,参数为消息想要发送到哪一层的taskID以及消息指针。当调用此函数时,对应参数taskID层的消息事件将会立即置1生效 bStatus_t tmos_msg_send( tmosTaskID taskID, uint8_t *msg_ptr ); // 接收消息函数,参数为需要接收任务taskID的消息。 uint8_t *tmos_msg_receive( tmosTaskID taskID ); //申请内存函数,发送消息之前需要先给消息申请内存空间。如果返回为NULL,则申请失败 uint8_t *tmos_msg_allocate( uint16_t len ); //释放消息占用内存的函数,处理完消息后需要释放内存占用。 bStatus_t tmos_msg_deallocate( uint8_t *msg_ptr ); /******TMOS定义的函数,较C库函数节省内存,功能类似******/ uint32_t tmos_rand( void ); // pseudo-random number bool tmos_memcmp( const void *src1, const void *src2, uint32_t len ); // TRUE - same, FALSE - different bool tmos_isbufset( uint8_t *buf, uint8_t val, uint32_t len ); // TRUE if all "val",FALSE otherwise uint32_t tmos_strlen( char *pString ); uint32_t tmos_memset( void * pDst, uint8_t Value, uint32_t len ); void tmos_memcpy( void *dst, const void *src, uint32_t len ); // Generic memory copy.
4、TMOS 使用Demo
4.1 任务管理
4.1.1 示例代码
tmos_demo_task.h
#ifndef _TMOS_DEMO_TASK_H_ #dedine _TMOS_DEMO_TASK_H_ #include "CH57x_common.h" #include "CH57xBLE_LIB.H" #include "stdint.h" #define DEMO_TASK_TMOS_EVT_TEST_1 (0x0001<<0) #define DEMO_TASK_TMOS_EVT_TEST_2 (0x0001<<1) #define DEMO_TASK_TMOS_EVT_TEST_3 (0x0001<<2) #define DEMO_TASK_TMOS_EVT_TEST_4 (0x0001<<3) #define DEMO_TASK_TMOS_EVT_TEST_5 (0x0001<<4) void demo_task_init(void); #endif
tmos_demo_task.C
#include "tmos_demo_task.h" //存储 当前task id 的全局变量 tmosTaskID demo_task_id = INVALID_TASK_ID; //task的event处理回调函数,需要在注册task时候,传进去 static uint16_t demo_task_process_event( uint8_t task_id, uint16_t events ) { //event 处理 if(events & DEMO_TASK_TMOS_EVT_TEST_1) { PRINT("DEMO_TASK_TMOS_EVT_TEST_1 evt test \r\n"); return (events ^ DEMO_TASK_TMOS_EVT_TEST_1); //异或的方式清除该事件运行标志,并返回未运行的事件标志 } //event 处理 if(events & DEMO_TASK_TMOS_EVT_TEST_2) { tmos_start_task(demo_task_id,DEMO_TASK_TMOS_EVT_TEST_3,1600); PRINT("DEMO_TASK_TMOS_EVT_TEST_2 evt test \r\n"); return (events ^ DEMO_TASK_TMOS_EVT_TEST_2); } //event 处理 if(events & DEMO_TASK_TMOS_EVT_TEST_3) { tmos_start_task(demo_task_id,DEMO_TASK_TMOS_EVT_TEST_3,1600); PRINT("DEMO_TASK_TMOS_EVT_TEST_3 evt test \r\n"); return (events ^ DEMO_TASK_TMOS_EVT_TEST_3); } // Discard unknown events return 0; } //初始化task //包括注册函数,可以注册后去开启event void demo_task_init( void ) { //注册task id,同事把该task的event处理函数传进去 demo_task_id = TMOS_ProcessEventRegister( demo_task_process_event ); //立即开始一个event tmos_set_event(demo_task_id,DEMO_TASK_TMOS_EVT_TEST_1); //开始一个定时event,1s后产生,当前语句只会产生一次event //可以在event产生后去开启event,可以是别的task的,也可以是当前task的event tmos_start_task(demo_task_id,DEMO_TASK_TMOS_EVT_TEST_2,1600); }
4.1.2 使用方法
-
把上面"tmos_demo_task.c" 和 "tmos_demo_task.h" 两个文件加到工程里面
-
在main函数里的while(1)之前上面调用函数 demo_task_init();
4.1.3 运行现象
- 芯片先运行
PRINT("DEMO_TASK_TMOS_EVT_TEST_1 evt test \r\n");
- 一秒后运行
PRINT("DEMO_TASK_TMOS_EVT_TEST_2 evt test \r\n");
- 然后按照1s一次不断运行
PRINT("DEMO_TASK_TMOS_EVT_TEST_3 evt test \r\n");
4.2 消息管理
4.2.1 示例代码
tmos_message_demo_message.h
#ifndef _TMOS_DEMO_MESSAGE_H_ #define _TMOS_DEMO_MESSAGE_H_ #include "CH57x_common.h" #include "CH57xBLE_LIB.H" #include "stdint.h" // Test Task Events #define TEST_EVENT_1 (0x0001<<0) #define TEST_EVENT_2 (0x0001<<1) void TMOS_init(void); uint16_t test_process_event_1(uint8_t taskID,uint16_t event); uint16_t test_process_event_2(uint8_t taskID,uint16_t event); #endif
tmos_demo_message.c
#include "tmos_demo_message.h" #define MSG_EVENT_TEST 0x10 uint8_t TestTaskID1 = INVALID_TASK_ID; uint8_t TestTaskID2 = INVALID_TASK_ID; void TMOS_init(void) { TestTaskID1 = TMOS_ProcessEventRegister(test_process_event_1); TestTaskID2 = TMOS_ProcessEventRegister(test_process_event_2); tmos_start_task( TestTaskID1, TEST_EVENT_1, 1600 ); tmos_start_task( TestTaskID2, TEST_EVENT_2, 1600 ); //延时启动 TEST_EVENT_2事件 延时时间:1600*625us } //消息处理的函数 static void demo_task_process_TMOSMsg( tmos_event_hdr_t *pMsg ) { switch ( pMsg->event ) { case MSG_EVENT_TEST: PRINT("pMsg->event=%x,pMsg->status=%x\r\n",pMsg->event,pMsg->status); break; default: PRINT("pMsg->event %04x\r\n",pMsg->event); break; } } uint16_t test_process_event_1(uint8_t taskID,uint16_t events) { tmos_event_hdr_t *test_message; if ( events & TEST_EVENT_1 ) { PRINT("Run TEST_EVENT_1 in task 1\r\n"); //申请消息内存空间 test_message =(tmos_event_hdr_t*) tmos_msg_allocate(sizeof(tmos_event_hdr_t)); if(test_message) { test_message->event = MSG_EVENT_TEST; test_message->status = 0x55; //发送消息至 TestTaskID2 任务 tmos_msg_send(TestTaskID2 ,(uint8_t *)test_message); } tmos_start_task( taskID, TEST_EVENT_1, 1600 ); return ( events ^ TEST_EVENT_1 ); } return 0; } uint16_t test_process_event_2(uint8_t taskID,uint16_t events) { //消息处理 if ( events & SYS_EVENT_MSG ) { uint8_t *pMsg; if ( (pMsg = tmos_msg_receive( taskID )) != NULL ) { //消息处理 demo_task_process_TMOSMsg( (tmos_event_hdr_t *)pMsg ); //释放消息空间 tmos_msg_deallocate( pMsg ); } // return unprocessed events return (events ^ SYS_EVENT_MSG); } //事件处理 if ( events & TEST_EVENT_2 ) { PRINT("Run TEST_EVENT_2 in task 2\r\n"); tmos_start_task( taskID, TEST_EVENT_2, 1600 ); return ( events ^ TEST_EVENT_2 ); } return 0; }
4.2.2 使用方法
- 把上面"tmos_demo_message.c" 和 "tmos_demo_message.h" 两个文件加到工程里面
- 在main函数里的while(1)之前上面调用函数 demo_task_init();
4.2.3 运行现象
间隔1S,重复运行:
PRINT("Run TEST_EVENT_1 in task 1\r\n");
PRINT("Run TEST_EVENT_2 in task 2\r\n");
PRINT("pMsg->event=%x,pMsg->status=%x\r\n",pMsg->event,pMsg->status);
5、TMOS使用注意事项
- 禁止在中断中调用任务调度函数
- 如果使用了ble,建议不要在单个任务中执行超过连接间隔一半时长的任务,否则将影响蓝牙通讯
- 在事件生效执行的代码中调用
tmos_start_task
函数时,延时时间以当前事件生效时间点为基准偏移,所以对调用延时执行函数在生效执行的代码中摆放的位置没有要求。 - 任务存在优先级,根据在xxx_ProcessEvent函数中判断的先后顺序决定,同时生效的任务,先执行先判断,后执行后判断。注意,执行完先判断的事件任务后,要等到任务调度系统轮巡一遍后,才会执行后判断的事件任务。
- 事件名按位定义,每一层taskID最多包含1个消息事件和15个任务事件(共16位)
posted on 2021-05-10 20:16 Wahahahehehe 阅读(4455) 评论(3) 编辑 收藏 举报
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库