Zephyr的TimeTimersleep

Posted Arnold Lu@南京

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Zephyr的TimeTimersleep相关的知识,希望对你有一定的参考价值。

正如Linux下一样,关于时间的系统函数可以分为三类:时间值、睡眠一段时间以及延迟执行。

在Zephyr上对应是什么样子呢?带着这个疑问,去了解一下这些函数。

以及他们与suspend之间的关系?

是否计入suspend时间?(计入-在到期后立即执行;不计入-需要唤醒后继续睡眠剩下时间)。

是否具备唤醒功能?如果具备,则能将将系统从suspend唤醒。

1 Zephyr的时间服务基础

Zephyr的官方文档提供了详细的模块说明和API使用方法。

Time:Kernel Clocks是系统所有基于时间服务的基础,包括Timer和Sleep。

Zephyr提供两种时钟计数,一个是高精度的32位硬件时钟计数(hardware clock),cycle表示的长短由硬件决定;

另一个是64位的tick计数(system clock),每个tick大小是由系统配置的,1ms~100ms不等。

 

2 Zephry的Time

我们知道Zephyr有两种clock计数:hardware clock和system clock。

 

system clock是内核很多基于时间服务的基础,包括timer或者其他超时服务。

当然,system clock是建立在hardware clock基础之上的。系统决定一个tick多长时间,然后换算成多少个hardware clock cycles。

通过对hardware clock编程,hardware clock倒计数然后产生中断,一个中断表示一个tick。

系统时间服务受制于tick的精度,比如10ms的tick,如果delay是25的话,会对齐到30ms。

即使是20ms delay,很有可能时间delay达到30ms,因为当前设置的delay只有到下一次tick产生才会设置在下两个tick到期。

 

系统时间相关服务建立在tick之上,tick建立在hardware clock之上,hardware clock具有最高精度,因此如果想要高精度时间测量,可以使用hardware clock。

不同精度时间示例。

普通精度:

s64_t time_stamp;
s64_t milliseconds_spent;

/* capture initial time stamp */
time_stamp = k_uptime_get();

/* do work for some (extended) period of time */
...

/* compute how long the work took (also updates the time stamp) */
milliseconds_spent = k_uptime_delta(&time_stamp);

 

高精度:

u32_t start_time;
u32_t stop_time;
u32_t cycles_spent;
u32_t nanoseconds_spent;

/* capture initial time stamp */
start_time = k_cycle_get_32();

/* do work for some (short) period of time */
...

/* capture final time stamp */
stop_time = k_cycle_get_32();

/* compute how long the work took (assumes no counter rollover) */
cycles_spent = stop_time - start_time;
nanoseconds_spent = SYS_CLOCK_HW_CYCLES_TO_NS(cycles_spent);

 

Tick的配置通过CONFIG_SYS_CLOCK_TICKS_PER_SEC相关API位于Clocks

3 Zephyr的Sleep

Zephyr的时间一个应用是Thread Sleeping,线程可以通过k_sleep()来延迟一段时间处理。在这段时间内,当前线程进入睡眠。在sleep时间满足并且当前进程被调度到,才会继续运行。

其他进程可以通过k_wakeup()提前唤醒处于k_sleep进程;如果进程不处于k_sleep中,k_wakeup则不起作用。

问题:那么如果睡眠过程中进入suspend,k_sleep是否计入suspend时间?

void k_sleep(s32_t duration)
Put the current thread to sleep.

This routine puts the current thread to sleep for duration milliseconds.

Return
N/A
Parameters
duration: Number of milliseconds to sleep.


void k_wakeup(k_tid_t thread)
Wake up a sleeping thread.

This routine prematurely wakes up thread from sleeping.

If thread is not currently sleeping, the routine has no effect.

Return
N/A
Parameters
thread: ID of thread to wake.

 

Busy Waiting是另一种延迟操作,k_busy_wait和k_sleep有以下不同:

  • k_busy_wait基于hardware clock进行计数,更加精确;k_sleep基于system tick。
  • k_busy_wait期间不会将CPU调度权交出去;k_sleep允许CPU调度别的线程。
  • k_busy_wait只能在非常短延时的情况下使用。
void k_busy_wait(u32_t usec_to_wait)
Cause the current thread to busy wait.

This routine causes the current thread to execute a “do nothing” loop for usec_to_wait microseconds.

Return
N/A

 

 

4 Zephyr的Timer 

Zephyr时间另一应用是Timers,包括几个要素duration(第一次定时器)、period(第一次超时之后的周期性定时器)、expiry function(超时函数)、stop function(提前结束Timer)、status(Timer的状态)。

Timer使用之前必须先初始化,如果period不为0,则第一次从超时后会重新起一个period的timer。timer执行过程中可以被停止或者重新触发。Timer的状态可以随时随地读取。

Zephyr Timer还有另一种同步读取状态的功能,这个功能会将当前进程阻塞,直到timer状态非零(即timer已经发生过超时,最起码一次)或者timer被停止。如果已经非零或者被停止,则当前线程不用等待。

Timer初始化:

struct k_timer my_timer;
extern void my_expiry_function(struct k_timer *timer_id);

k_timer_init(&my_timer, my_expiry_function, NULL);

或者:

K_TIMER_DEFINE(my_timer, my_expiry_function, NULL);

 

使用Timer:

void my_work_handler(struct k_work *work)
{
    /* do the processing that needs to be done periodically */
    ...
}

K_WORK_DEFINE(my_work, my_work_handler);

void my_timer_handler(struct k_timer *dummy)
{
    k_work_submit(&my_work);
}

K_TIMER_DEFINE(my_timer, my_timer_handler, NULL);

...

/* start periodic timer that expires once every second */
k_timer_start(&my_timer, K_SECONDS(1), K_SECONDS(1));

 

 

获取Timer状态:

K_TIMER_DEFINE(my_status_timer, NULL, NULL);

...

/* start one shot timer that expires after 200 ms */
k_timer_start(&my_status_timer, K_MSEC(200), 0);

/* do work */
...

/* check timer status */
if (k_timer_status_get(&my_status_timer) > 0) {
    /* timer has expired */
} else if (k_timer_remaining_get(&my_status_timer) == 0) {
    /* timer was stopped (by someone else) before expiring */
} else {
    /* timer is still running */
}

 

 

同步获取Timer状态(还具有delay的功能):

K_TIMER_DEFINE(my_sync_timer, NULL, NULL);

...

/* do first protocol operation */
...

/* start one shot timer that expires after 500 ms */
k_timer_start(&my_sync_timer, K_MSEC(500), 0);

/* do other work */
...

/* ensure timer has expired (waiting for expiry, if necessary) */
k_timer_status_sync(&my_sync_timer);

/* do second protocol operation */
...

 

停止Timer:

k_timer_stop(&my_timer)

 

以上是关于Zephyr的TimeTimersleep的主要内容,如果未能解决你的问题,请参考以下文章

Zephyr下使用TFLite进行语音识别

Zephyr在编译时将二进制文件转化成c语言数组

Zephyr RTOS -- nRF Connect SDK (NCS) 环境搭建

Zephyr RTOS -- nRF Connect SDK (NCS) 环境搭建

Zephyr:undefined reference to `__device_dts_ord_xx‘

Zephyr:undefined reference to `__device_dts_ord_xx‘