老板说我技术需要有长进,不能只做一个crud boy。 于是我选来选去,终于选定了,来学习操作系统。因为操作系统一直被看做是计算机软件的基石。
本系列是我学习操作系统的笔记,操作系统是以AliOS Things为例子。其他的操作系统也是差不多。
本文主要是讲操作系统的定时器管理,后面会有更多的操作系统内容介绍。
国庆假期学门新技术,拒绝只做crud boy, 就从操作系统开始 - 中断管理
1、背景
定时器,顾名思义,是指从指定的时刻开始,经过一个指定的时间,然后触发一个超时事件,用户可以自定义定时器的周期与频率。跟生活中的闹钟类似,我们可以设置闹钟每天什么时候响,还可以设置响的次数,是响一次还是每天都响。
在嵌入式系统中,我们往往需要跟时间相关的操作。比如任务的延时调度、任务的周期性运行等。基于对时钟精确的要求,每个运行的芯片平台都会提供相应的硬件定时机制。
操作系统中最小的时间单位是系统时钟节拍(OS Tick)。本章主要介绍基于硬件定时机制的系统时钟节拍,和基于时钟节拍的软件定时器。软件定时器是AliOS Things中的一个重要模块,使用软件定时器可以方便的实现一些与超时或周期性相关的功能。
本章也将从AliOS Things软件定时器的API入手,来分析AliOS Things软件定时器的运行机理。读完本章,我们将了解系统时钟节拍是如何产生的,并学会如何使用AliOS Things软件定时器。
定时器有硬件定时器和软件定时器之分,首先介绍硬件定时器。
2、AliOS Things 定时器管理
2.1、硬件定时器介绍
硬件定时器是芯片平台本身提供的定时功能。一般是由外部晶振作为输入时钟提供给芯片,芯片向软件模块提供可配置能力,接受控制输入,在到达设定的时间后芯片产生时钟中断,用户在中断服务函数中处理信息。芯片的外部晶振一般选用MHZ级别,所以硬件定时器的精度很高,可以达到纳秒级别。
目前芯片平台一般会提供两种定时模式,原理如下:
- 倒计数模式:硬件定时器提供一个count寄存器配置,设定其初始值后,其随着定时时钟的频率计数递减,递减频率即为定时器频率。当计数值为0时,定时结束,触发对应的定时处理。如果是周期模式,可以设置其每次计数为0后自动复位的count起始计数值(一般也通过寄存器设置),以此来设置触发周期。
- 正计数模式:硬件定时器提供两个基本的寄存器配置——count寄存器和compare寄存器配置。count寄存器的值会随着时钟频率计数递增,当其达到compare设定的值后,即触发对应的定时处理。如果是周期模式,则需要按照时钟频率和延时周期来设置后续的compare值,即在上一次的定时处理内,设置下一次的compare寄存器。
上述两种方式具体参考所使用的芯片平台手册。
2.2、系统时钟节拍工作机制
在嵌入式系统中,通常软件定时器以系统节拍为计时单位。时钟节拍是嵌入式操作操作系统OS运行的“心跳”,任何操作系统都需要提供一个时钟节拍,用于处理所有与时间相关的事件,如任务的延时、任务的时间片轮转调度、软件定时器的超时事件等。
时钟节拍是特定的周期性中断,其本质就是基于芯片的硬件定时机制所设置的一个基础硬件定时器,定时周期一般是1~100ms。在AliOS Things中,系统节拍的长度可以根据
RHINO_CONFIG_TICKS_PER_SECOND
这个宏的定义来调整(该宏在k_config.h中有定义)。
系统时钟节拍的值等于1/RHINO_CONFIG_TICKS_PER_SECOND秒。比如:HaaS100和HaaS EDU平台上,RHINO_CONFIG_TICKS_PER_SECOND的值定义为1000,那么时钟节拍就是1/1000秒,即1ms,也就是每1ms系统会“心跳”一次,产生一个tick中断。
由于系统时钟节拍定义了系统中定时器的精度,系统可以根据实际系统CPU的处理能力和实时性需求设置合适的数值,系统节拍周期的值越小,精度越高,但是系统开销也将越大,因为在1秒中系统进入时钟中断的次数也就越多。
2.2.1、时钟节拍的实现方式
时钟节拍由芯片的硬件定时器产生,硬件定时器配置为中断触发模式。如果操作系统希望1ms能产生一次定时触发,则必须将1ms转换为定时器的cycle计数值,并将此cycle值按照实际倒计数或者正计数的模式来配置定时器的相关寄存器。
配置定时器的cycle间隔功能一般由相关芯片平台的驱动提供,不同芯片平台的配置方式略有差别,读者可参考平台适配的代码。
时钟节拍tick的处理指的是每次tick周期触发时,操作系统需要进行的处理。AliOS Things提供了统一的tick函数入口krhino_tick_proc,将此函数加入tick定时器中断处理函数,以此来达到屏蔽硬件差异的目的。
以HaaS100开发板为例,在SysTick_Handler中断处理函数中调用AliOS Things的tick调度函数krhino_tick_proc:
void SysTick_Handler(void)
{
/* 进入中断 */
krhino_intrpt_enter();
/* tick isr */
krhino_tick_proc();
/* 退出中断 */
krhino_intrpt_exit();
}
void krhino_tick_proc(void)
{
#if (RHINO_CONFIG_USER_HOOK > 0)
krhino_tick_hook();
#endif
tick_list_update(1);
#if (RHINO_CONFIG_SCHED_RR > 0)
time_slice_update();
#endif
}
可以看到每经过一个时钟节拍,由操作系统维护的tick值(即系统时间)就会加1,同时会检查当前任务的时间片是否用完,以及是否有定时器超时。具体代码请参考k_time.c文件。
2.2.2、时钟节拍常用接口
时钟节拍(tick模块)提供了几个维测接口用来获取基本的tick信息。