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位)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM