这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » rtthread内核时钟模块代码分析

共3条 1/1 1 跳转至

rtthread内核时钟模块代码分析

工程师
2025-01-12 01:12:00     打赏

      确切地说,这部分和之前分析的定时器关系不大,但是由于其实现逻辑和定时器比较类似,因此在分析时也就同步看了。

代码入口

components\drivers\ktime

代码分析

    确切的说,ktime模块分为3个组成部分,一个部分叫boottime,可以理解为启动后经历的时间相关的功能。另一个叫cputime,用于系统滴答时钟方式的计时相关功能,最后一个叫hrtime,粗看实现是利用硬件定时器实现的us级精度的延时,休眠等控制,但还需要详细分析。

cputime源码分析

     cputime的实现很依赖芯片架构,从目前开源出来的代码看,只有支持aarch64和virt64两种架构的芯片可以使用该模块,而如果是非这两种架构的芯片,cputime也会利用系统的滴答时钟进行计时,但此计时的精度就没那么高了。出于简化分析的考量,后面的分析仅针对aarch64架构源码进行分析。

初始化入口

.globl rt_hw_get_cntpct_val
rt_hw_get_cntpct_val:
    MRS X0, CNTPCT_EL0
    RET

static volatile unsigned long _init_cnt = 0;

// aarch64架构实现
void rt_ktime_cputimer_init(void)
{
    _init_cnt = rt_hw_get_cntpct_val();
}

// 通用入口
rt_weak void rt_ktime_cputimer_init(void)
{
    return;
}

    从实现上看,aarch64的cputimer初始化部分仅仅是读取了当前的芯片系统的滴答值并保存。

获取当前计数值入口

unsigned long rt_ktime_cputimer_getcnt(void)
{
    return rt_hw_get_cntpct_val() - _init_cnt;
}

// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getcnt(void)
{
    return rt_tick_get();
}

    可以很明显的看到,在初始化时读到的计数值,是用于初始化计数的部分。也就是说,在调用了rt_ktime_cputimer_init才开始从0往上计数。

获取滴答频率入口

.globl rt_hw_get_gtimer_frq
rt_hw_get_gtimer_frq:
    MRS X0,CNTFRQ_EL0
    RET

unsigned long rt_ktime_cputimer_getfrq(void)
{
    return rt_hw_get_gtimer_frq();
}

// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getfrq(void)
{
    return RT_TICK_PER_SECOND;
}

    这个接口也就是直接读取芯片的滴答频率并上报。

获取步进值入口

// aarch64架构实现
unsigned long rt_ktime_cputimer_getstep(void)
{
    return rt_ktime_cputimer_getfrq() / RT_TICK_PER_SECOND;
}

// 通用入口
rt_weak unsigned long rt_ktime_cputimer_getstep(void)
{
    return 1;
}

获取定时器的分辨率

#define RT_KTIME_RESMUL (1000000UL)

unsigned long rt_ktime_cputimer_getres(void)
{
    return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / rt_hw_get_gtimer_frq();
}

// 通用实现
rt_weak unsigned long rt_ktime_cputimer_getres(void)
{
    return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
}

boottime分析

    从功能上看,bootime实现的功能是获取启动后所经过的时间,其精度分为s,us和ns。而在实现上,boottime的实现是基于cputime的实现而实现的。

获取秒级计时入口

rt_weak rt_err_t rt_ktime_boottime_get_s(time_t *t)
{
    RT_ASSERT(t != RT_NULL);

    unsigned long ns = (rt_ktime_cputimer_getcnt() * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;

    *t = ns / (1000UL * 1000 * 1000);

    return RT_EOK;
}

获取微妙级计时入口

rt_weak rt_err_t rt_ktime_boottime_get_us(struct timeval *tv)
{
    RT_ASSERT(tv != RT_NULL);

    unsigned long ns = (rt_ktime_cputimer_getcnt() * rt_ktime_cputimer_getres()) / RT_KTIME_RESMUL;

    tv->tv_sec  = ns / (1000UL * 1000 * 1000);
    tv->tv_usec = (ns % (1000UL * 1000 * 1000)) / 1000;

    return RT_EOK;
}

获取纳秒级计时入口

hrtime分析

      从hrtime暴露出来的接口看,此模块最主要的功能是实现us,ns和ms级别的延时。而其用法可以在nanosleep中看到,具体如下:

#if defined(RT_USING_POSIX_DELAY) && defined(RT_USING_KTIME)
int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
    struct timespec old_ts = {0};
    struct timespec new_ts = {0};
    struct rt_ktime_hrtimer timer;

    // 初始化结构体timer
    rt_ktime_hrtimer_delay_init(&timer);

    if (rqtp == RT_NULL)
    {
        rt_set_errno(EFAULT);
        return -1;
    }

    if (rqtp->tv_sec < 0 || rqtp->tv_nsec < 0 || rqtp->tv_nsec >= NANOSECOND_PER_SECOND)
    {
        rt_set_errno(EINVAL);
        return -1;
    }
    unsigned long ns = rqtp->tv_sec * NANOSECOND_PER_SECOND + rqtp->tv_nsec;
    rt_ktime_boottime_get_ns(&old_ts); // 获取ns精度的启动计时
    rt_ktime_hrtimer_ndelay(&timer, ns); // 休眠ns的时长
    if (rt_get_errno() == RT_EINTR)
    { // 如果是中断中返回,则说明是执行异常,此时通过rmtp将已执行的时间向上报,以便上层做后续处理
      // 并销毁timer运行时占用的资源
        if (rmtp)
        {
            rt_base_t rsec, rnsec;
            rt_ktime_boottime_get_ns(&new_ts);

            rsec = old_ts.tv_sec + rqtp->tv_sec - new_ts.tv_sec;
            rnsec = old_ts.tv_nsec + rqtp->tv_nsec - new_ts.tv_nsec;
            if (rnsec < 0)
            {
                rmtp->tv_sec = rsec - 1;
                rmtp->tv_nsec = NANOSECOND_PER_SECOND + rnsec;
            }
            else
            {
                rmtp->tv_sec = rsec;
                rmtp->tv_nsec = rnsec;
            }
        }

        rt_ktime_hrtimer_delay_detach(&timer);
        rt_set_errno(EINTR);
        return -1;
    }

    // 销毁timer运行时所产生的资源
    rt_ktime_hrtimer_delay_detach(&timer);
    return 0;
}
RTM_EXPORT(nanosleep);
#endif /* RT_USING_POSIX_DELAY && RT_USING_KTIME */

rt_ktime_hrtimer_delay_init

static void _sleep_timeout(void *parameter)
{ // 超时后通过完成量唤醒任务,通过nanosleep的实现看,
  // 这个等待完成量的操作就在函数rt_ktime_hrtimer_ndelay中执行
    struct rt_ktime_hrtimer *timer = parameter;
    rt_completion_done(&timer->completion);
}

// 仅仅是做了资源的初始化,并未做具体功能的执行
void rt_ktime_hrtimer_init(rt_ktime_hrtimer_t timer,
                           const char        *name,
                           unsigned long      cnt,
                           rt_uint8_t         flag,
                           void (*timeout)(void *parameter),
                           void *parameter)
{
    /* parameter check */
    RT_ASSERT(timer != RT_NULL);
    RT_ASSERT(timeout != RT_NULL);
    RT_ASSERT(cnt < (_HRTIMER_MAX_CNT / 2));

    /* set flag */
    timer->parent.flag = flag;

    /* set deactivated */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    timer->timeout_func = timeout;
    timer->parameter    = parameter;
    timer->timeout_cnt  = cnt + rt_ktime_cputimer_getcnt();
    timer->init_cnt     = cnt;

    rt_list_init(&(timer->row));
    rt_completion_init(&timer->completion);
}

void rt_ktime_hrtimer_delay_init(struct rt_ktime_hrtimer *timer)
{ // 可以发现,nanosleep的执行,依赖系统滴答时钟,本质上属于系统调度的一部分
    rt_ktime_hrtimer_init(timer, "hrtimer_sleep", 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
                          _sleep_timeout, timer);
}

rt_ktime_hrtimer_sleep

    其实对外暴露的并不是这个入口,而是rt_ktime_hrtimer_ndelay,rt_ktime_hrtimer_udelay和rt_ktime_hrtimer_mdelay,但奈何这三个函数的实现,本质上都是rt_ktime_hrtimer_sleep,因此这里也就分析此函数了。

对外暴露的延时函数实现

    会发现三个函数本质上都是基于rt_ktime_hrtimer_sleep实现的。

rt_err_t rt_ktime_hrtimer_ndelay(struct rt_ktime_hrtimer *timer, unsigned long ns)
{
    unsigned long res = rt_ktime_cputimer_getres();
    return rt_ktime_hrtimer_sleep(timer, (ns * RT_KTIME_RESMUL) / res);
}

rt_err_t rt_ktime_hrtimer_udelay(struct rt_ktime_hrtimer *timer, unsigned long us)
{
    return rt_ktime_hrtimer_ndelay(timer, us * 1000);
}

rt_err_t rt_ktime_hrtimer_mdelay(struct rt_ktime_hrtimer *timer, unsigned long ms)
{
    return rt_ktime_hrtimer_ndelay(timer, ms * 1000000);
}

rt_ktime_hrtimer_sleep

#ifdef ARCH_CPU_64BIT
#define _HRTIMER_MAX_CNT UINT64_MAX
#else
#define _HRTIMER_MAX_CNT UINT32_MAX
#endif

static rt_list_t          _timer_list = RT_LIST_OBJECT_INIT(_timer_list);
static rt_ktime_hrtimer_t _nowtimer   = RT_NULL;
static RT_DEFINE_SPINLOCK(_spinlock);

rt_weak unsigned long rt_ktime_hrtimer_getres(void)
{
    return ((1000UL * 1000 * 1000) * RT_KTIME_RESMUL) / RT_TICK_PER_SECOND;
}

static void (*_outcb)(void *param) = RT_NULL;

static void _hrtimer_timeout(void *parameter)
{
    if (_outcb)
        _outcb(parameter);
}

rt_weak rt_err_t rt_ktime_hrtimer_settimeout(unsigned long cnt, void (*timeout)(void *param), void *param)
{
    static rt_timer_t timer = RT_NULL;

    _outcb = timeout;
    if (cnt == 0)
    {
        if (timer != RT_NULL)
        {
            if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
            {
                rt_timer_stop(timer);
            }
        }

        if (_outcb)
            _outcb(param);

        return RT_EOK;
    }

    if (timer == RT_NULL)
    {    // 从此处可以发现,其实ktime的实现是依赖系统调度定时器实现的
        timer = rt_timer_create("shrtimer", _hrtimer_timeout, param, cnt, RT_TIMER_FLAG_ONE_SHOT);
    }
    else
    {
        rt_tick_t tick = cnt;
        rt_timer_control(timer, RT_TIMER_CTRL_SET_TIME, &tick);
        rt_timer_control(timer, RT_TIMER_CTRL_SET_PARM, param);
    }

    if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
    {
        rt_timer_stop(timer);
    }
    rt_timer_start(timer);
    return RT_EOK;
}

// 将计数值换算成实际滴答周期数
static unsigned long _cnt_convert(unsigned long cnt)
{
    unsigned long rtn   = 0;
    unsigned long count = cnt - rt_ktime_cputimer_getcnt();
    if (count > (_HRTIMER_MAX_CNT / 2))
        return 0;

    rtn = (count * rt_ktime_cputimer_getres()) / rt_ktime_hrtimer_getres();
    return rtn == 0 ? 1 : rtn; /* at least 1 */
}

static void _set_next_timeout_n_unlock(rt_base_t level)
{
    rt_ktime_hrtimer_t t;

    if (&_timer_list != _timer_list.prev)
    { // 如果列表非空,则说明存在定时器,此时需要启用定时器
        t = rt_list_entry((&_timer_list)->next, struct rt_ktime_hrtimer, row);
        if (_nowtimer != RT_NULL)
        {  // 如果当前已有定时器在执行,则判断新插入的定时器是否比已有定时器更早执行
           // 若有,则将_nowtimer替换成新插入的定时器并执行
           // 否则直接启用定时器
            if (t != _nowtimer && t->timeout_cnt < _nowtimer->timeout_cnt)
            {
                _nowtimer = t;
                rt_spin_unlock_irqrestore(&_spinlock, level);
                rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t);
            }
            else
            {
                rt_spin_unlock_irqrestore(&_spinlock, level);
            }
        }
        else
        {    // 如果当前没有定时器执行,则启用最新插入的定时器
            _nowtimer = t;
            rt_spin_unlock_irqrestore(&_spinlock, level);
            rt_ktime_hrtimer_settimeout(_cnt_convert(t->timeout_cnt), _timeout_callback, t);
        }
    }
    else
    { // 如果定时器列表为空,则说明所有的定时器任务都已经执行完毕,此时仅需要恢复现场并停用定时器即可
        _nowtimer = RT_NULL;
        rt_spin_unlock_irqrestore(&_spinlock, level);
        rt_ktime_hrtimer_settimeout(0, RT_NULL, RT_NULL);
    }
}

rt_err_t rt_ktime_hrtimer_start(rt_ktime_hrtimer_t timer)
{
    rt_list_t *timer_list;
    rt_base_t  level;

    /* 检查定时器 */
    RT_ASSERT(timer != RT_NULL);

    level = rt_spin_lock_irqsave(&_spinlock);
    rt_list_remove(&timer->row); /* 将定时器从定时器执行列表中移除 */
    /* 禁用定时器 */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    /* 从已有定时器列表中插入timer(列表时间从小到大排列)*/
    timer_list = &_timer_list;
    for (; timer_list != _timer_list.prev; timer_list = timer_list->next)
    {
        rt_ktime_hrtimer_t t;
        rt_list_t         *p = timer_list->next;

        t = rt_list_entry(p, struct rt_ktime_hrtimer, row);

        if ((t->timeout_cnt - timer->timeout_cnt) == 0)
        {
            continue;
        }
        else if ((t->timeout_cnt - timer->timeout_cnt) < (_HRTIMER_MAX_CNT / 2))
        {
            break;
        }
    }
    rt_list_insert_after(timer_list, &(timer->row));
    // 启用定时器
    timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;

    // 设置下一次定时器超时解锁时间
    _set_next_timeout_n_unlock(level);

    return RT_EOK;
}

// 记录执行结果
rt_inline void rt_ktime_hrtimer_keep_errno(rt_ktime_hrtimer_t timer, rt_err_t err)
{
    RT_ASSERT(timer != RT_NULL);

    timer->error = err;
    rt_set_errno(-err);
}

rt_err_t rt_ktime_hrtimer_sleep(struct rt_ktime_hrtimer *timer, unsigned long cnt)
{
    rt_err_t err;

    if (cnt == 0)
        return -RT_EINVAL;

    // 初始化定时器参数
    timer->timeout_cnt  = cnt + rt_ktime_cputimer_getcnt();
    timer->init_cnt     = cnt;

    // 启用定时器
    rt_ktime_hrtimer_start(timer);
    // 等待定时器超时
    err = rt_completion_wait_flags(&(timer->completion), RT_WAITING_FOREVER,
                                   RT_INTERRUPTIBLE);
    // 记录定时器执行结果
    rt_ktime_hrtimer_keep_errno(timer, err);

    return RT_EOK;
}

rt_ktime_hrtimer_detach

      其实对外暴露的是rt_ktime_hrtimer_delay_detach,而rt_ktime_hrtimer_delay_detach的实现,其实只是直接调用rt_ktime_hrtimer_detach,因此直接分析rt_ktime_hrtimer_detach。

rt_err_t rt_ktime_hrtimer_detach(rt_ktime_hrtimer_t timer)
{
    rt_base_t level;

    /* 有效性检查 */
    RT_ASSERT(timer != RT_NULL);

    /* 通知定时器结束等待 */
    rt_completion_wakeup_by_errno(&timer->completion, RT_ERROR);

    level = rt_spin_lock_irqsave(&_spinlock);

    /* 关闭定时器 */
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
    /* 如果此时定时器在中断中,表明此时定时器已经执行了,需要将定时器从定时器列表中移除 */
    if (timer->error == -RT_EINTR || timer->error == RT_EINTR)
    {
        _nowtimer = RT_NULL;
        rt_list_remove(&timer->row);
        _set_next_timeout_n_unlock(level);
    }
    else
    {
        rt_spin_unlock_irqrestore(&_spinlock, level);
    }

    return RT_EOK;
}

其余接口

      这些接口并没有直接暴露给应用,而是暴露到了ctime模块中的timer_create和timer_delete,具体调用实现如下:

#define TIMER_ID_MAX 50
static struct rt_spinlock _timer_id_lock = RT_SPINLOCK_INIT;
static struct timer_obj *_g_timerid[TIMER_ID_MAX];
static void *timer_id[TIMER_ID_MAX];
static resource_id_t id_timer = RESOURCE_ID_INIT(TIMER_ID_MAX, timer_id);

int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid)
{
    static int num = 0;
    int _timerid = 0;
    struct timer_obj *timer;
    char timername[RT_NAME_MAX] = {0};

    if (evp == RT_NULL || timerid == RT_NULL)
    {
        rt_set_errno(EINVAL);
        return -1;
    }

    if (evp->sigev_notify == SIGEV_THREAD)  // TODO need to implement
    {
        rt_set_errno(EINVAL);
        return -1;
    }

    switch (clockid)
    {
        case CLOCK_REALTIME:
        case CLOCK_REALTIME_ALARM:
        case CLOCK_MONOTONIC:
        case CLOCK_BOOTTIME:
        case CLOCK_BOOTTIME_ALARM:
        case CLOCK_PROCESS_CPUTIME_ID:
        case CLOCK_THREAD_CPUTIME_ID:
            break;  // Only these ids are supported
        default:
            rt_set_errno(EINVAL);
            return -1;
    }

    // 申请并初始化timer资源,初始化信息来自evp
    timer = rt_malloc(sizeof(struct timer_obj));
    if(timer == RT_NULL)
    {
        rt_set_errno(ENOMEM);
        return -1;
    }

    rt_snprintf(timername, RT_NAME_MAX, "psx_tm%02d", num++);
    num %= 100;
    timer->sigev_signo = evp->sigev_signo;
#ifdef RT_USING_SMART // RT_SMART相关的代码,暂时不需要关注
    struct rt_work *work;
    struct rt_lwp *lwp = lwp_self();
    struct lwp_timer_event_param *param;
    param = rt_malloc(sizeof(struct lwp_timer_event_param));
    work = ¶m->work;

    if (!work)
    {
        rt_set_errno(ENOMEM);
        return -1;
    }

    if (lwp)
    {
        timer->pid = lwp_self()->pid;
        rt_list_insert_after(&lwp->timer, &timer->lwp_node);
    }
    else
    {
        timer->pid = 0; /* pid 0 is never used */
    }

    timer->work = work;
#endif /* RT_USING_SMART */
    timer->sigev_notify_function = evp->sigev_notify_function;
    timer->val = evp->sigev_value;
    timer->interval.tv_sec = 0;
    timer->interval.tv_nsec = 0;
    timer->reload = 0U;
    timer->status = NOT_ACTIVE;
    timer->clockid = clockid;

    // 初始化hrtimer
    rt_ktime_hrtimer_init(&timer->hrtimer, timername, 0, RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
                          rtthread_timer_wrapper, timer);

    // 获取资源ID号并将定时器挂载在此ID号上
    _timerid = resource_id_get(&id_timer);
    if (_timerid < 0)
    { // 如果ID号小于0,则说明timer已经注册满了,不能再注册新的timer了,此时需要销毁资源并返回错误信息
#ifdef RT_USING_SMART
        rt_free(param);
#endif /* RT_USING_SMART */

        rt_ktime_hrtimer_detach(&timer->hrtimer);
        rt_free(timer);
        rt_set_errno(ENOMEM);
        return -1;
    }
    _g_timerid[_timerid] = timer;

    timer->timer_id = (timer_t)(rt_ubase_t)_timerid;
    *timerid = (timer_t)(rt_ubase_t)_timerid;

    return 0;
}
RTM_EXPORT(timer_create);


int timer_delete(timer_t timerid)
{
    struct timer_obj *timer;
    rt_ubase_t ktimerid;

    ktimerid = (rt_ubase_t)timerid;

    if (ktimerid < 0 || ktimerid >= TIMER_ID_MAX)
    {    // 如果定时器编号不再有效范围内,则报错返回
        rt_set_errno(EINVAL);
        return -1;
    }

    RT_DEBUG_NOT_IN_INTERRUPT; // 要求不能在中断中删除定时器
    // 从定时器列表中取出timer,并将维护的_g_timerid和id_timer标记为未使用
    rt_spin_lock(&_timer_id_lock);
    timer = _g_timerid[ktimerid];
    if (timer != NULL)
    {
        _g_timerid[ktimerid] = RT_NULL;
        resource_id_put(&id_timer, ktimerid);
    }
    rt_spin_unlock(&_timer_id_lock);

    if (timer == RT_NULL)
    {
        rt_set_errno(EINVAL);
        LOG_D("can not find timer %ld", ktimerid);
        return -1;
    }

    //如果拿出的定时器有效且处于激活状态,则置为非激活状态并停用该定时器
    if (timer->status == ACTIVE)
    {
        timer->status = NOT_ACTIVE;
        rt_ktime_hrtimer_stop(&timer->hrtimer);
    }
    // 解注册该定时器
    rt_ktime_hrtimer_detach(&timer->hrtimer);

#ifdef RT_USING_SMART // RT_SMART的实现,需使用时针对看
    if (timer->pid)
        rt_list_remove(&timer->lwp_node);
    rt_free(timer->work);
#endif
    // 释放定时器资源
    rt_free(timer);
    return 0;
}
RTM_EXPORT(timer_delete);

rt_ktime_hrtimer_stop

rt_err_t rt_ktime_hrtimer_stop(rt_ktime_hrtimer_t timer)
{
    rt_base_t level;

    RT_ASSERT(timer != RT_NULL);

    level = rt_spin_lock_irqsave(&_spinlock);
    if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
    { // 如果定时器当前未启用,则不需要停止
        rt_spin_unlock_irqrestore(&_spinlock, level);
        return -RT_ERROR;
    }
    // 移除当前定时器并将定时器标记置为停用
    _nowtimer = RT_NULL;
    rt_list_remove(&timer->row);
    timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;

    // 启动下一个定时器并退出spin lock
    _set_next_timeout_n_unlock(level);

    return RT_EOK;
}

rt_ktime_hrtimer_control

rt_err_t rt_ktime_hrtimer_control(rt_ktime_hrtimer_t timer, int cmd, void *arg)
{
    rt_base_t level;

    /* parameter check */
    RT_ASSERT(timer != RT_NULL);

    level = rt_spin_lock_irqsave(&_spinlock);
    switch (cmd)
    {
        case RT_TIMER_CTRL_GET_TIME:    // 获取定时器的初始时间
            *(unsigned long *)arg = timer->init_cnt;
            break;

        case RT_TIMER_CTRL_SET_TIME:    // 设置定时器的超时时间
            RT_ASSERT((*(unsigned long *)arg) < (_HRTIMER_MAX_CNT / 2));
            timer->init_cnt    = *(unsigned long *)arg;
            timer->timeout_cnt = *(unsigned long *)arg + rt_ktime_cputimer_getcnt();
            break;

        case RT_TIMER_CTRL_SET_ONESHOT:    // 设置为单次触发
            timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
            break;

        case RT_TIMER_CTRL_SET_PERIODIC:    // 设置为周期工作
            timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
            break;

        case RT_TIMER_CTRL_GET_STATE:    // 获取定时器的工作状态
            if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)
            {
                *(rt_uint32_t *)arg = RT_TIMER_FLAG_ACTIVATED;
            }
            else
            {
                *(rt_uint32_t *)arg = RT_TIMER_FLAG_DEACTIVATED;
            }
            break;

        case RT_TIMER_CTRL_GET_REMAIN_TIME:    // 获取定时器的剩余时间
            *(unsigned long *)arg = timer->timeout_cnt;
            break;
        case RT_TIMER_CTRL_GET_FUNC:    // 获取该定时器的超时处理函数
            arg = (void *)timer->timeout_func;
            break;

        case RT_TIMER_CTRL_SET_FUNC:    // 设置该定时器的超时处理函数
            timer->timeout_func = (void (*)(void *))arg;
            break;

        case RT_TIMER_CTRL_GET_PARM:    // 获取定时器内部参数
            *(void **)arg = timer->parameter;
            break;

        case RT_TIMER_CTRL_SET_PARM:    // 设置定时器内部参数
            timer->parameter = arg;
            break;

        default:
            break;
    }
    rt_spin_unlock_irqrestore(&_spinlock, level);

    return RT_EOK;
}

总结

    经过对这部分代码的分析,我们会得出以下结论:cputime本身的功能仅仅是提供更细颗粒度的计时信息,而他被boottime模块所使用。boottime模块,主要功能就是记录系统从cputime起来后到读取时间是系统所消耗的时间,其颗粒度与调用的接口有关。

       hrtime模块,则是直接通过系统滴答时钟的方式实现了高于ms精度的延时,解决带RTOS时,只能使用比滴答时钟想等或者更长时间延时的问题。






关键词: rtthread     内核     时钟     模块    

专家
2025-01-12 10:19:26     打赏
2楼

谢谢分享


高工
2025-01-12 21:04:42     打赏
3楼

hrtime 高分timer 这个还没有使用过呢


共3条 1/1 1 跳转至

回复

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