【WCH蓝牙系列芯片】-基于CH32V208开发板—TMOS系统说明(一)

-------------------------------------------------------------------------------------------------------------------------------------

    在CH32V208芯片中使用蓝牙过程中,针对蓝牙协议栈开发的“操作系统”——TMOS系统,这是一种简化版的OSAL嵌入式系统。由于蓝牙使用过程中,需要蓝牙与多个设备连接并实现多功能和多任务,这就会导致了调度问题。因此,TMOS被作为一个操作系统抽象层,使用TMOS处理多事件和多任务切换,将事件和任务对应起来。
    TMOS系统任务管理——通过时间片轮询的方式进行多个任务的调度,但是实际上每次只有一个任务运行。但是可以使用任务调度的策略将多个任务进行调度,每个任务占用一定的时间,所有的任务通过时间分片的方式处理。
    TMOS 系统时钟单位为 625us,来源于芯片RTC。
    用户通过注册任务(Task)将自定义的事件(Event)添加到TMOS的任务链表中,由TMOS进行调度运行。在任务初始化完成后,tmos在循环中轮询任务事件,事件的标志存储在16位变量中,每一位在同一个任务中对应一个唯一的事件。标志位为1表示该位对应的事件运行,为0表示不运行。
    每个Task用户最多可以定义15个事件其中0x8000为系统预留的SYS_EVENT_MSG事件,是系统消息传递事件,不可被定义。根据任务ID确定优先级,优先级越低,任务越先运行。每个任务运行完一个事件后便通过异或的方式清除已运行的事件,同时return未运行的事件标志,接着运行下一个任务;当任务调度系统运行一遍后,再次回来运行任务链表头的一个事件,如此循环下去。

    在CH32V208的从机例程中,创建一个1s点灯的TMOS任务,进行说明如何使用TMOS。

1、在peripheral.c中创建Peripheral_TaskID,并存储当前Peripheral_TaskID的全局变量

 2、定义一个点灯事件标志

 3、在Peripheral_Init从机初始化中,注册任务事件,将事件的回调函数注册到TMOS中。

4、在任务事件处理函数中,添加一个1S的LED闪烁的事件。

static void LED_init (void)
{

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA、GPIOC时钟

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;   //(|按位或运算)
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    //速度最大50MHZ
    GPIO_Init(GPIOA,&GPIO_InitStruct); //调用GPIOA端口

    GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    GPIO_ResetBits(GPIOA, GPIO_Pin_2);

}

static void LED_change(void)
{
    static uint8_t LED_State;
    if(LED_State)
    {
        LED_State = 0;
        GPIO_ResetBits(GPIOA, GPIO_Pin_1);
        GPIO_ResetBits(GPIOA, GPIO_Pin_2);

    }
    else {
        LED_State = 1;
        GPIO_SetBits(GPIOA, GPIO_Pin_1);
        GPIO_SetBits(GPIOA, GPIO_Pin_2);
    }
}

并声明这个两个函数

5、调用事件,在Peripheral_LinkEstablished用于处理连接建立事件的回调函数中,检查是否已经存在连接,
   如果已经连接,将会终止当前连接,同时打印一条信息以示连接已达到最大限制。
   如果还没有连接,就会执行tmos_start_task 函数设置定时器来触发一些事件,包括周期性事件、参数更新事件和读取 RSSI 事件,还有IS点灯的事件。从而开启点灯的这个事件。

static void Peripheral_LinkEstablished(gapRoleEvent_t *pEvent)
{
    gapEstLinkReqEvent_t *event = (gapEstLinkReqEvent_t *)pEvent;

    // See if already connected
    if(peripheralConnList.connHandle != GAP_CONNHANDLE_INIT)
    {
        GAPRole_TerminateLink(pEvent->linkCmpl.connectionHandle);
        PRINT("Connection max...\n");
    }
    else
    {
        peripheralConnList.connHandle = event->connectionHandle;
        peripheralConnList.connInterval = event->connInterval;
        peripheralConnList.connSlaveLatency = event->connLatency;
        peripheralConnList.connTimeout = event->connTimeout;
        peripheralMTU = ATT_MTU_SIZE;
        // Set timer for periodic event
        tmos_start_task(Peripheral_TaskID, SBP_PERIODIC_EVT, SBP_PERIODIC_EVT_PERIOD);

        // Set timer for param update event
        tmos_start_task(Peripheral_TaskID, SBP_PARAM_UPDATE_EVT, SBP_PARAM_UPDATE_DELAY);

        // Start read rssi
        tmos_start_task(Peripheral_TaskID, SBP_READ_RSSI_EVT, SBP_READ_RSSI_EVT_PERIOD);


        // 添加一个点灯的TMOS事件
        tmos_start_task(Peripheral_TaskID, SBP_LED_EVT, 1600);  //1600*0.625uS = 1S


        PRINT("Conn %x - Int %x \n", event->connectionHandle, event->connInterval);
    }
}

 这样通过手机连接蓝牙后,可以看到LED1和LED2就会以1s的时间进行闪烁。

 

 

在TMOS使用的注意事项:
1. 禁止在中断中调用TMOS函数
2. 使用蓝牙过程中,建议不要在单个任务中执行超过连接间隔一半时长的任务,否则将影响蓝牙通讯
3. 在中断中建议不要执行超过连接间隔一半时长的任务,否则将影响蓝牙通讯
4. 在事件生效执行的代码中调用延时执行函数(tmos_start_task)时,延时时间以当前事件生效时间点为基准偏移,

   所以对调用延时执行函数(tmos_start_task)在生效执行的代码中摆放的位置没有要求。
5. 任务存在优先级,根据在xxx_ProcessEvent函数中判断的先后顺序决定,同时生效的任务,先执行先判断,后执行后判断。

   注意,执行完先判断的事件任务后,要等到任务调度系统轮巡一遍后,才会执行后判断的事件任务。
6. 事件名按位定义,每一层taskID最多包含1个消息事件和15个任务事件(共16位)

 

posted on 2024-01-08 16:28  凡仕  阅读(576)  评论(0编辑  收藏  举报