Abstract: This article leads us to analyze the hongmeng light kernel time management module source code. The time management module provides necessary clock beats for task scheduling, and provides all time-related services to applications, such as time conversion, statistics, and delay functions.
This article is shared from huawei cloud community “Hongmeng light kernel M core source code analysis series six time management”, original author: zhushy.
This article will continue to analyze Tick and time-related source code, to introduce to the reader hongmeng light kernel time management module. The source code in this article, using the OpenHarmony LitEOS-M kernel as an example, is available on the open source site gitee.com/openharmony… To obtain.
Based on the system clock, the time management module can be divided into two parts. One part is SysTick interruption, which provides the necessary clock beats for task scheduling. The other part is to provide all time-related services to the application, such as time conversion, statistics functions.
The system clock is generated by an interrupt triggered by an output pulse generated by a timer/counter and is generally defined as an integer or long integer. The period of the output pulse is called a “clock Tick”, also known as a time scale or Tick. Tick is the basic unit of time of an operating system. It is determined by the number of ticks per second configured by users. If the number of ticks per second is set to 1000, one Tick equals 1ms. The other unit of time is Cycle, which is the smallest unit of time for the system. The length of Cycle is determined by the system master clock frequency, which is the number of cycles per second. For a 216 MHz CPU, 216000 cycles are generated in one second.
Users time the system in seconds and milliseconds, while the OPERATING system time in ticks. When users need to perform operations on the system, such as task suspension or delay, you can use the time management module to convert the ticks to seconds and milliseconds.
Below, we analyze the time management module source code, if it involves the development board part, to the development board project Targets \ Cortex-m7_nucleo_F767zi_gcc \ as an example for source analysis.
1. Time management initialization and startup
Let’s take a look at the time management module configuration, and then analyze how to initialize, how to start.
1.1 Time Management Configurations
The time management module consists of three configuration items: system clock OS_SYS_CLOCK, number of ticks per second LOSCFG_BASE_CORE_TICK_PER_SECOND, and macro LOSCFG_BASE_CORE_TICK_HW_TIME. LOSCFG_BASE_CORE_TICK_HW_TIME is disabled by default. If LOSCFG_BASE_CORE_TICK_HW_TIME is enabled, the customized VOID platform_tick_handler(VOID) function is required to perform customized operations in the Tick interrupt handler function. These configuration items are defined in the target_config.h file in the template development board project directory such as targets\cortex-m7_nucleo_f767zi_gcc\target_config.h as follows:
#define OS_SYS_CLOCK 96000000
#define LOSCFG_BASE_CORE_TICK_PER_SECOND (1000UL)
#define LOSCFG_BASE_CORE_TICK_HW_TIME 0
Copy the code
1.2 Time Management Initialization and Startup
The INT32 main(VOID) function calls the kernel\ SRC \ LOs_init. c function UINT32 LOS_Start(VOID) starts the system. The function invokes the start scheduling function UINT32 HalStartSchedule(OS_TICK_HANDLER Handler). The source code is as follows:
LITE_OS_SEC_TEXT_INIT UINT32 LOS_Start(VOID)
{
return HalStartSchedule(OsTickHandler);
}
Copy the code
Function UINT32 HalTickStart(OS_TICK_HANDLER *handler) defined in kernel\arch\arm\cortex-m7\ GCC \los_context.c The function parameter is the Tick interrupt handler function OsTickHandler(), which will be analyzed later. The code at ⑴ continues to call the function HalTickStart(handler) to set the Tick interrupt to start. (2) HalStartToRun assembly function will be called to start running the system, and this assembly function will be analyzed in detail in the subsequent task scheduling series.
LITE_OS_SEC_TEXT_INIT UINT32 HalStartSchedule(OS_TICK_HANDLER handler) { UINT32 ret; (1) ret = HalTickStart (handler); if (ret ! = LOS_OK) { return ret; } [2] HalStartToRun (); return LOS_OK; /* never return */ }Copy the code
HalTickStart(handler) is defined in the kernel\arch\arm\cortex-m7\ GCC \los_timer.c file, source code as follows, we analyze the code implementation of the function. Verify the validity of the configuration item of the time management module. System-defined interrupts are used when the macro LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT is enabled. The code at (2) is executed to set the interrupt vector by calling OsSetVector(), a function defined in the file kernel\arch\arm\cortex-m7\ GCC \los_interrupt.c, which is examined in detail in the interrupt series. ⑶ Set the global variable g_sysClock as the system clock, g_cyclesPerTick as the number of cycles corresponding to each tick, and g_ullTickCount as 0 to indicate the number of tick interruption occurrences in the system. Uint32_t SysTick_Config(uint32_t) in the targets\cortex-m7_nucleo_f767zi_gcc\Drivers\CMSIS\Include\core_cm7.h file Ticks), initialize and start the system timer Systick and interrupt.
WEAK UINT32 HalTickStart(OS_TICK_HANDLER *handler) { UINT32 ret; (1) if ((OS_SYS_CLOCK = = 0) | | (LOSCFG_BASE_CORE_TICK_PER_SECOND = = 0) | | (LOSCFG_BASE_CORE_TICK_PER_SECOND > OS_SYS_CLOCK)) { return LOS_ERRNO_TICK_CFG_INVALID; } #if (LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT == 1) #if (OS_HWI_WITH_ARG == 1) OsSetVector(SysTick_IRQn, (HWI_PROC_FUNC)handler, NULL); # the else 2 OsSetVector (SysTick_IRQn, HWI_PROC_FUNC handler); G_sysClock = OS_SYS_CLOCK; g_cyclesPerTick = OS_SYS_CLOCK / LOSCFG_BASE_CORE_TICK_PER_SECOND; g_ullTickCount = 0; Ret [4] = SysTick_Config (g_cyclesPerTick); if (ret == 1) { return LOS_ERRNO_TICK_PER_SEC_TOO_SMALL; } return LOS_OK; }Copy the code
1.3 Tick Interrupt Handler OsTickHandler()
The function VOID OsTickHandler(VOID), defined in the kernel\ SRC \los_tick.c file, is the most frequently executed function in the time management module and is called whenever a Tick interrupt occurs. If LOSCFG_BASE_CORE_TICK_HW_TIME is enabled, the custom tick handler function platform_tick_handler() will be called, which is disabled by default. (2) the global variable g_ullTickCount will be updated. (3) If the macro LOSCFG_BASE_CORE_TIMESLICE is enabled, the time slice of the current running task will be checked. In the subsequent task module, the function OsTimesliceCheck() will be analyzed in detail. (4) we iterate through the sorted list of tasks and check if there are any tasks that have timed out. ⑸ if the timer feature is supported, it will check whether the timer times out.
The source code is as follows:
VOID OsTickHandler(VOID) {#if (LOSCFG_BASE_CORE_TICK_HW_TIME == 1) ⑴ platform_tick_handler(); # endif g_ullTickCount [2] + +; #if (LOSCFG_BASE_CORE_TIMESLICE == 1) ⑶ OsTimesliceCheck(); # endif OsTaskScan [4] (); // task timeout scan #if (LOSCFG_BASE_CORE_SWTMR == 1) ⑸ (VOID)OsSwtmrScan(); #endif }Copy the code
2, LiteOS kernel time management common operations
Time management provides the following functions, time conversion, time statistics, etc., these functions are defined in the file kernel\ SRC \los_tick.c, we analyze the source code implementation of these operations.
2.1 Time conversion operation
2.1.1 Ms is converted to Tick
Function UINT32 LOS_MS2Tick(UINT32 millisederec) Converts the input parameter UINT32 millisederec into the number of ticks. OS_SYS_MS_PER_SECOND specifies 1000 milliseconds. Change the millisieverts’ number of ticks by eursys_MS_per_second and ^ [zip5], ^ [zip5], ^ [zip5], ^ [zip5].
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
{
if (millisec == OS_NULL_INT) {
return OS_NULL_INT;
}
return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND;
}
Copy the code
2.1.2 The Tick is converted to ms
Function UINT32 LOS_Tick2MS(UINT32 TICK) Converts the tick number into the number of milliseconds. The time conversion is also simple: the number of ticks divided by the number of ticks per second, the Tick value LOSCFG_BASE_CORE_TICK_PER_SECOND, calculates the number of seconds, converts to milliseconds, calculates the resulting value and returns it.
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 ticks)
{
return ((UINT64)ticks * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
}
Copy the code
2.1.3 Cycle Number is converted to milliseconds
Before introducing the conversion function, the CpuTick structure has two simple members, each representing a high and low 32-bit value of a UINT64 type data.
typedef struct tagCpuTick { UINT32 cntHi; /* < the highest 32 bits of a 64-bit value */ UINT32 cntLo; /* < the lower 32 bits of a 64-bit value */} CpuTick;Copy the code
Moving on to OsCpuTick2MS(), the conversion function converts the number of cycles represented by type CpuTick to the corresponding number of milliseconds, printing the high and low 32 bits of millisecond data. Take a look at the specific code, ⑴ check whether the parameter is null pointer, ⑵ check whether the system clock is configured. (3) Convert the number of cycles represented by CpuTick into UINT64 cycle data. G_sysClock/OS_SYS_MS_PER_SECOND (DOUBLE)g_sysClock/OS_SYS_MS_PER_SECOND (DOUBLE)g_sysClock/OS_SYS_MS_PER_SECOND (DOUBLE)g_sysClock/OS_SYS_MS_PER_SECOND (⑸) convert DOUBLE to UINT64, and then execute ⑹, assigning the high and low 64-bit values to *msLo and *msHi, respectively.
LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2MS(CpuTick *cpuTick, UINT32 *msHi, UINT32 *msLo) { UINT64 tmpCpuTick; DOUBLE temp; (1) if ((cpuTick = = NULL) | | (msHi = = NULL) | | (msLo = = NULL) {return LOS_ERRNO_SYS_PTR_NULL; } ⑵ if (g_sysClock == 0) {return LOS_ERRNO_SYS_CLOCK_INVALID; } (3) tmpCpuTick = ((UINT64) cpuTick - > cntHi < < OS_SYS_MV_32_BIT) | cpuTick - > cntLo; ⑷ temp = tmpCpuTick/((DOUBLE)g_sysClock/OS_SYS_MS_PER_SECOND); tmpCpuTick = (UINT64)temp; *msLo = (UINT32)tmpCpuTick; *msHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT); return LOS_OK; }Copy the code
2.1.4 The number of cycles is converted to microseconds
The OsCpuTick2US() conversion function converts the number of cycles represented by type CpuTick to the corresponding number of milliseconds, and outputs the high and low 32-bit values of the millisecond data. This function is similar to OsCpuTick2MS() and can be read by yourself.
LITE_OS_SEC_TEXT_INIT UINT32 OsCpuTick2US(CpuTick *cpuTick, UINT32 *usHi, UINT32 *usLo)
{
UINT64 tmpCpuTick;
DOUBLE temp;
if ((cpuTick == NULL) || (usHi == NULL) || (usLo == NULL)) {
return LOS_ERRNO_SYS_PTR_NULL;
}
if (g_sysClock == 0) {
return LOS_ERRNO_SYS_CLOCK_INVALID;
}
tmpCpuTick = ((UINT64)cpuTick->cntHi << OS_SYS_MV_32_BIT) | cpuTick->cntLo;
temp = tmpCpuTick / ((DOUBLE)g_sysClock / OS_SYS_US_PER_SECOND);
tmpCpuTick = (UINT64)temp;
*usLo = (UINT32)tmpCpuTick;
*usHi = (UINT32)(tmpCpuTick >> OS_SYS_MV_32_BIT);
return LOS_OK;
}
Copy the code
2.2 Time Statistics Operations
2.2.1 Obtain the number of cycles of each Tick
Function UINT32 LOS_CyclePerTickGet(VOID) Calculates the cycle length of a tick. G_sysClock System clock indicates the cycle of 1 second. LOSCFG_BASE_CORE_TICK_PER_SECOND Indicates the tick cycle of 1 second. G_cyclesPerTick = g_sysClock /LOSCFG_BASE_CORE_TICK_PER_SECOND.
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
{
return g_cyclesPerTick;
}
Copy the code
2.2.2 Obtaining the number of Ticks since system startup
UINT64 Number of Tick interrupts counted by the LOS_TickCountGet(VOID) function since system startup. It should be noted that no counting is carried out in the case of shutdown interruption and cannot be used as an accurate time. G_ullTickCount data is updated in the function VOIDOsTickHandler(VOID) each time a Tick interrupt occurs.
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
{
return g_ullTickCount;
}
Copy the code
2.2.3 Obtaining the System Clock
The UINT32 LOS_SysClockGet(VOID) function obtains the configured system clock.
UINT32 LOS_SysClockGet(VOID)
{
return g_sysClock;
}
Copy the code
2.2.4 Obtaining the Cycle number since system startup
The function VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo) is defined in the kernel\arch\arm\cortex-m7\ GCC \los_timer.c file. This function gets the number of cycles since the system started. Result Unsigned value UINT32 *cntHi and UINT32 *cntLo are returned, respectively.
Let’s take a look at the source of this function. First turn off the interrupt, and then obtain the Tick number since the startup. (2) Obtain hwCycle by reading the current Value Register SysTickCurrent Value Register. If the TICK_CHECK bit of the State Register is 1, it indicates that the SYstick Interrupt is suspended, and the tick does not count, so it needs to be adjusted by 1. (4) According to swTick, g_cyclesPerTick and hwCycle, calculate the Cycle number since the system was started. At ⑸, unsigned values of the high and low 32 bits of Cycle number are obtained, and then interrupt and return.
LITE_OS_SEC_TEXT_MINOR VOID HalGetCpuCycle(UINT32 *cntHi, UINT32 *cntLo) { UINT64 swTick; UINT64 cycle; UINT32 hwCycle; UINTPTR intSave; intSave = LOS_IntLock(); (1) swTick = g_ullTickCount; 2 hwCycle = SysTick - > VAL. ⑶ if ((SCB->ICSR & TICK_CHECK)! = 0) { hwCycle = SysTick->VAL; swTick++; } ⑷ ⑷ cycle = ((swTick) * g_cyclesPerTick + (g_cyclespertick-hwCycle)); ⑸ cntHi = cycle >> SHIFT_32_BIT; *cntLo = cycle & CYCLE_CHECK; LOS_IntRestore(intSave); return; }Copy the code
summary
This article leads us to analyze the hongmeng light kernel time management module source code. The time management module provides necessary clock beats for task scheduling, and provides all time-related services to applications, such as time conversion, statistics, and delay functions. The follow-up will also launch more articles to share, please look forward to, but also welcome to share learning, using hongmeng light kernel experience, any questions, suggestions, you can leave a message to us: gitee.com/openharmony… . To make it easier to find the light kernel repository, visit gitee.com/openharmony… “, follow Watch, like Star, and Fork to your account, thank you.
Click to follow, the first time to learn about Huawei cloud fresh technology ~