在鸿蒙轻内核源码分析上一篇文章中,我们剖析了中断的源码,简单提到了Tick
中断。本文会继续分析Tick
和时间相关的源码,给读者介绍鸿蒙轻内核的时间管理模块。本文中所涉及的源码,以OpenHarmony LiteOS-M
内核为例,均可以在开源站点https://gitee.com/openharmony/kernel_liteos_m 获取。
时间管理模块以系统时钟为基础,可以分为2部分,一部分是SysTick
中断,为任务调度提供必要的时钟节拍;另外一部分是,给应用程序提供所有和时间有关的服务,如时间转换、统计功能。
系统时钟是由定时器/计数器产生的输出脉冲触发中断产生的,一般定义为整数或长整数。输出脉冲的周期叫做一个“时钟滴答”,也称为时标或者Tick
。Tick
是操作系统的基本时间单位,由用户配置的每秒Tick
数决定。如果用户配置每秒的Tick数目为1000,则1个Tick
等于1ms的时长。另外一个计时单位是Cycle
,这是系统最小的计时单位。Cycle
的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle
数,对于216 MHz
的CPU
,1秒产生216000000个cycles
。
用户以秒、毫秒为单位计时,而操作系统以Tick
为单位计时,当用户需要对系统进行操作时,例如任务挂起、延时等,此时可以使用时间管理模块对Tick
和秒/毫秒进行转换。
下面,我们剖析下时间管理模块的源代码,若涉及开发板部分,以开发板工程targets\cortex-m7_nucleo_f767zi_gcc\
为例进行源码分析。
1、时间管理初始化和启动
我们先看下时间管理模块的相关配置,然后再剖析如何初始化,如何启动。
1.1 时间管理相关的配置
时间管理模块涉及3个配置项,系统时钟OS_SYS_CLOCK
、每秒Tick
数目LOSCFG_BASE_CORE_TICK_PER_SECOND
两个配置选项,还有宏LOSCFG_BASE_CORE_TICK_HW_TIME
。LOSCFG_BASE_CORE_TICK_HW_TIME
默认关闭,开启时,需要提供定制函数VOID platform_tick_handler(VOID)
,在Tick中断处理函数中执行定制操作。这些配置项在模板开发板工程目录的文件target_config.h
中定义,如文件targets\cortex-m7_nucleo_f767zi_gcc\target_config.h
中定义如下:
#define OS_SYS_CLOCK 96000000
#define LOSCFG_BASE_CORE_TICK_PER_SECOND (1000UL)
#define LOSCFG_BASE_CORE_TICK_HW_TIME 0
1.2 时间管理初始化和启动
函数INT32 main(VOID)
会调用kernel\src\los_init.c
中的函数UINT32 LOS_Start(VOID)
启动系统,该函数会调用启动调度函数UINT32 HalStartSchedule(OS_TICK_HANDLER handler)
。源码如下:
LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID)
{
return HalStartSchedule(OsTickHandler);
}
函数UINT32 HalTickStart(OS_TICK_HANDLER *handler)
定义在kernel\arch\arm\cortex-m7\gcc\los_context.c
,源码如下。其中函数参数为Tick
中断处理函数OsTickHandler()
,后文会分析该tick
中断处理函数。⑴处代码继续调用函数进一步调用函数HalTickStart(handler)
来设置Tick
中断启动。⑵处会调用汇编函数HalStartToRun
开始运行系统,后续任务调度系列再详细分析该汇编函数。
LITE_OS_SEC_TEXT_INIT UINT32 HalStartSchedule(OS_TICK_HANDLER handler)
{
UINT32 ret;
⑴ ret = HalTickStart(handler);
if (ret != LOS_OK) {
return ret;
}
⑵ HalStartToRun();
return LOS_OK; /* never return */
}
函数HalTickStart(handl