wahahahehehe

Tips:

1. 博客内容主要为博主的学习笔记,引用已表明出处,如有侵犯请联系我删除;

2. 如有错误请指出,万分感谢;

3. 博主邮箱:yukai_tao@163.com。

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任务链表

TMOS循环查询任务链表,根据任务ID确定优先级,越小越高。每个任务运行完一个事件后便通过异或的方式清除已运行的事件,同时return未运行的事件标志,接着运行下一个任务;当任务调度系统运行一遍后,再次回来运行任务链表头的一个事件,如此循环下去。

TMOS调度机制如下:

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 运行现象

  1. 芯片先运行 PRINT("DEMO_TASK_TMOS_EVT_TEST_1 evt test \r\n");
  2. 一秒后运行 PRINT("DEMO_TASK_TMOS_EVT_TEST_2 evt test \r\n");
  3. 然后按照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  阅读(3574)  评论(3编辑  收藏  举报

导航