这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » rtthread系统提供的软件定时器框架分析

共3条 1/1 1 跳转至

rtthread系统提供的软件定时器框架分析

助工
2024-12-23 22:51:36     打赏

       前面分析完系统提供的硬件定时器入口时发现有宏RT_USING_TIMER_SOFT包裹的部分,这就意味着,RTT除了提供系统级的硬件定时器的基础上,还提供了一套软件定时器实现。此实现需要在Kconfig中开启宏RT_USING_TIMER_SOFT来实现。

软件定时器实现解析

软件定时器的启用入口

      为何不讲注册入口,是因为启用入口包含了注册入口所需的参数,具体如下:

rt_err_t rt_timer_start(rt_timer_t timer)
{
    //首部启用部分省略,和硬件定时器一致
    ...

#ifdef RT_USING_TIMER_SOFT
    if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER) 
    {// 注册时需置标记位RT_TIMER_FLAG_SOFT_TIMER启用软件定时器
        timer_list = _soft_timer_list;
        spinlock = &_stimer_lock;
    }
    else
#endif /* RT_USING_TIMER_SOFT */
    {
        timer_list = _timer_list;
        spinlock = &_htimer_lock;
    }
    
    //中间启用部分省略,和硬件定时器一致
    ...

#ifdef RT_USING_TIMER_SOFT
    if (err == RT_EOK && (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER))
    {    // 释放信号量,也就意味着,软件定时器的执行,有依赖信号量的部分
        rt_sem_release(&_soft_timer_sem);
    }
#endif /* RT_USING_TIMER_SOFT */

    // 尾部省略,与硬件定时器一致
    ...

    return err;
}

        经过对使能部分的分析,其实我们可以看出,软件定时器的注册和创建方法,与硬件定时器是一致的,唯一的区别为,函数传入的flag标记需增加RT_TIMER_FLAG_SOFT_TIMER标记位。

软件定时器对应用的其他入口

       软件定时器对应用的其他入口都与硬件定时器一致,这里就没必要再贴代码分析了,直接看硬件定时器部分即可。

软件定时器的执行解析

软件定时器系统注册入口

       说来也奇怪,软件定时器的系统注册入口,和硬件定时器的系统注册入口是分开的,个人并不太为何这么操作,从代码模块化的角度上考虑,软件定时器的实现放置于硬件定时器实现更好。

void rt_system_timer_thread_init(void)
{
#ifdef RT_USING_TIMER_SOFT
    int i;

    for (i = 0;
         i < sizeof(_soft_timer_list) / sizeof(_soft_timer_list[0]);
         i++)
    {
        //初始化软件定时器列表
        rt_list_init(_soft_timer_list + i);
    }
    // 软件定时器自旋锁初始化
    rt_spin_lock_init(&_stimer_lock);
    // 信号量初始化(基本可以确定,_timer_thread_entry会通过信号量快速调度了)
    rt_sem_init(&_soft_timer_sem, "stimer", 0, RT_IPC_FLAG_PRIO);
    /* 创建并启用定时器,定时周期为10ms,定时器优先级需要通过Kconfig配置*/
    rt_thread_init(&_timer_thread,
                   "timer",
                   _timer_thread_entry,
                   RT_NULL,
                   &_timer_thread_stack[0],
                   sizeof(_timer_thread_stack),
                   RT_TIMER_THREAD_PRIO,
                   10);

    rt_thread_startup(&_timer_thread);
#endif /* RT_USING_TIMER_SOFT */
}

int rtthread_startup(void)
{
    // 省略部分
    ...
    
    /* 系统硬件定时器初始化入口 */
    rt_system_timer_init();

    //省略部分
    ...

    /* 软件定时器入口 */
    rt_system_timer_thread_init();

    // 省略部分
    ...

    return 0;
}

软件定时器执行入口

// 获取下一个定时器的超时时间
static rt_err_t _timer_list_next_timeout(rt_list_t timer_list[], rt_tick_t *timeout_tick)
{
    struct rt_timer *timer;

    if (!rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
    {
        timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
                              struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
        *timeout_tick = timer->timeout_tick;
        return RT_EOK;
    }
    return -RT_ERROR;
}

static void _timer_thread_entry(void *parameter)
{
    rt_err_t ret = RT_ERROR;
    rt_tick_t next_timeout;
    rt_base_t level;

    RT_UNUSED(parameter);

    rt_sem_control(&_soft_timer_sem, RT_IPC_CMD_SET_VLIMIT, (void*)1);

    while (1)
    {
        /* 获取定时器列表中的下次定时器超时时间 */
        level = rt_spin_lock_irqsave(&_stimer_lock);
        ret = _timer_list_next_timeout(_soft_timer_list, &next_timeout);
        rt_spin_unlock_irqrestore(&_stimer_lock, level);

        if (ret != RT_EOK)
        {   // 如果定时器列表为空,则永远等待信号量,降低系统调度压力
            rt_sem_take(&_soft_timer_sem, RT_WAITING_FOREVER);
        }
        else
        {
            rt_tick_t current_tick;

            /* 获取当前时间 */
            current_tick = rt_tick_get();

            if ((next_timeout - current_tick) < RT_TICK_MAX / 2)
            {
                /* 如果超时时间大于当前时间,则延时对应时间再去调度
                由于延时无法退出,因此采用信号量的方式确保有新定时器插入时,
                可以及时退出并进行新的定时器检测周期 */
                next_timeout = next_timeout - current_tick;
                rt_sem_take(&_soft_timer_sem, next_timeout);
            }
        }

        // 检查软件定时器列表并执行定时器功能
        _timer_check(_soft_timer_list, &_stimer_lock); 
    }
}

总结

    至此,系统层的软件定时器实现也分析完毕了。我们可以看到,软件定时器的实现,本质上是基于线程,系统创建了一个软件定时器处理线程去处理软件定时器任务。而若不改系统代码,会发现软件定时器的精度更加低,但他也有明显的优势,由于定时器超时执行是在系统调度中完成,因此不存在中断嵌套问题,对系统调度的影响最小。因此,若定时器任务实时性要求不高的话,个人建议软件架构设计中尽量使用软件定时器实现来实现所需功能。





关键词: rtthread     系统     软件     定时器     框架     分析    

高工
2024-12-24 00:06:08     打赏
2楼

感谢楼主分享


专家
2024-12-24 00:10:33     打赏
3楼

感谢楼主分享


共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]