Jason's scribble
OAL system clock
1. Relationship between system clock and Kernel
Wince 5.0 uses the Real-Time Kernel of preemptible multitasking Based on Time slices, and each thread can set the size of the thread time slice as needed (refer to the cesetthreadquantum function). The default value is 100 ms, the default value dwdefathreadthreadquantum can also be set at oeminit. In the kernel source file, variable names related to the word quantum generally refer to time slices. The wince kernel defines several global variables related to the clock. They are also part of the kernel and OAL interfaces:
1) dwreschedtime: this variable is updated in the kernel scheduler. kcnextthread () is part of the kernel scheduler. It determines the next running thread based on the priority and status of the thread, set dwreschedtime based on the time slice of the thread. As the name implies, this variable refers to the next time the scheduler is run.
Since we are talking about the kernel of Wince 5.0, We have to insert a new feature in its scheduling program called the variable system clock cycle (system tick ), the purpose is to interrupt the hardware timer (CPU clock) only when the scheduler needs it. This not only improves the efficiency of the scheduling program, but also helps the CPU to save energy (This will be discussed later ). This feature is optional and depends on the implementation of OAL. This feature is not used. Generally, the clock cycle of each system is 1 ms, that is, a clock interruption occurs every millisecond.
2) curmsec, DWORD type variable, updated every time the clock is interrupted, the total number of system clock beats from the system startup to the current time (too bypassing, or system tick (tick) ).
If the user program calls the gettickcount () function, the value of this variable is actually directly returned. As mentioned above, when the system clock cycle (system tick) is 1 ms, curmsec is a millisecond-level counter, and the accuracy of gettickcount () will not exceed 1 ms.
In addition to updating curmsec in the clock interrupt processing function (timerisr), we also need to judge whether the time of running the scheduler is based on dwreschedtime:
If (INT) (curmsec-dwreschedtime)> = 0) sysintr = sysintr_resched;
3) curridlehigh, curridlelow, idleconv
These variables implement a 64-bit counter, reflecting the time when the system is in idle mode. It is generally updated in the oemidle () function. The user program can obtain this value by calling the getidletime () function.
Here we will insert some knowledge points related to oemidle:
Scheduling Algorithms are closely related to power management, that is, they are related to the energy conservation and Emission Reduction promoted by the central Government at this stage, because most mobile devices want to save energy, therefore, when all threads are in the blocking state, the kernel places the CPU in idle mode (Low Power Consumption) by calling oemidle ). This State ends when an interruption occurs or when a thread can run. In fact, many devices spend a lot of time waiting for user input. Therefore, if the CPU supports low-power mode, it should be implemented in the oemidle function.
If you do not use the new scheduling program feature (variable tick schedick) mentioned above, you need to determine the exact time period of the idle in the oemidle function, the variable system time cycle can be configured with the correct clock interrupt in advance, so that the oemidle function can put the CPU in a low power consumption faster, which is the reason for its energy saving.
You can use the following code to calculate the CPU usage of a program running:
Dwstarttick = gettickcount ();
Dwidlest = getidletime ();
Sleep (); // tested code segment
Dwstoptick = gettickcount ();
Dwidleed = getidletime ();
Percentidle = (100 * (dwidleed-dwidlest)/(dwstoptick-dwstarttick ));
For this code, see getidletime in msdn. 1-percentidle indicates the CPU usage.
2. system clock module structure
This article introduces the implementation of the system clock Module Based on the pqoal (production-quality oal) structure. pqoal is only available from wince 5.0 and can simplify the implementation of oal code, it is also helpful for porting oal code. A Brief Analysis of the directory structure:
% _ Winceroot %/platform/common is hardware-independent and CPU-related pqoal code;
% _ Winceroot %/platform/common/src/common is hardware-independent code. The following lists these functions in a yellow background;
% _ Winceroot %/platform/common/src/$ CPU $ is CPU-related code. The following describes such functions in green background.
If the CPU used by your platform already exists in this directory, for example, the PXA270 code is in the % _ winceroot %/platform/common/src/ARM/Intel/PXA27X directory, in general, this code can complete most oal functions without any modifications. For a single PXA270 system clock module, you can use it without writing any Code. However, this part of the Code does not actually implement the new feature (variable tick Scheduler) that is available only from wince 5.0 ). In particular, the default Implementation of oalcpuidle () is only a simple loop. It is best to implement this function on your own so that the CPU is placed in a low-power state.
In oal, the data structure related to the system clock, variables and function interfaces have their definitions or annotations in the oal_timer.h header file.
(% _ Winceroot %/platform/common/src/INC/oal_timer.h)
2.1 variables and functions for interaction with the kernel
2.1.1 uint32 oaltimerintrhandler ();
This is the timerisr mentioned above, that is, the clock interrupt processing function, which returns a value of sysintr.
2.1.2 curmsec, as mentioned earlier, is defined in the kernel source file.
2.1.3 oemidle (). As mentioned above, the pqoal implementation will call oalcpuidle () internally to place the CPU in idle mode (low power consumption ).
2.1.4 SC _gettickcount ()
This is the millisecond-level timer required by the kernel, and returns the number of milliseconds from the start of the system. If the system clock cycle is 1 ms, you can directly return curmsec; otherwise, if the system clock cycle exceeds 1 ms, you need a high-precision counter to adjust to a millisecond interval.
This function has been implemented by pqoal, but it will call the hardware-related function oaltimercountssincesystick ().
2.1.5 pqueryperformancefrequency, pqueryperformancecounter
The function pointer defined in the kernel implements a high-precision timer through these two functions.
The prototypes of these two functions have also been implemented by pqoal, namely oaltimerqueryperformancefrequency and oaltimerqueryperformancecounter. They also call the hardware-related functions oaltimercountssincesystick () and OAL layer variables g_oaltimer.
2.1.6 poemupdaterescheduletime
The function pointer defined in the kernel. If variable tick scheduler is used, it is necessary to implement this function. It is mainly to reset the timer cycle of the clock according to the changed system cycle (tick, this avoids unnecessary clock interruptions.
Pqoal provides an example of the oaltimerupdaterescheduletime function for reference. It calls the hardware-related function oaltimerupdate ().
2.2 variables and functions that interact with other oal modules
2.2.1 oaltimerinit ()
This function is used to initialize the system clock, usually called in the oeminit function. The initialization includes oal layer variable g_oaltimer, kernel variable curridlehigh, curridlelow, idleconv, kernel function pointer (2.1.5, 2.1.6), and hardware clock timer.
2.2.2 g_oaltimer, a variable in the oal_timer_state structure, contains various system clock-related variables.
Typedef struct {
Uint32 countspermsec; // counts per 1 msec
Uint32 countsmargin; // counts margin
Uint32 maxperiodmsec; // maximal timer period in msec
Uint32 msecpersponick; // msec per system tick
Uint32 countspersponick; // counts per system tick
Uint32 actualmsecpersponick; // actual msec per system tick
Uint32 actualcountspersponick; // actual counts per system tick
Volatile uint64 curcounts; // counts at last system tick
} Oal_timer_state, * poal_timer_state;
2.2.3 oaltimercountssincesystick ()
This function uses a high-precision counter to return the time elapsed after the last system tick. Generally, the accuracy is higher than 1 ms. In other words, the crystal oscillator frequency of the hardware clock is higher than 1 MHz.
2.2.4 oaltimerupdaterescheduletime (), see 2.1.6
2.2.5 oaltimerrecharge (), oaltimerupdate (), oalstall ()
2.2.6 oalgettickcount ()
3. Implement High-precision timer
Sometimes the user program wants to call queryperformancecounter () and queryperformancefrequency () for timing with a precision higher than 1 ms. As described in 2.1.5, pqoal has basically implemented this part of code. We only need to implement oaltimercountssincesystick (2.2.3) based on the CPU used ).
The PXA270 processor has two groups of clock channels that allow clock interruption through software. They are called the operating system clock (operating system timer ), for details, see intel PXA27X Processor family developer's manual.
Here we only introduce a group of compatible clock channels with PXA255. It uses a 3250 m crystal oscillator, that is, it can count times per millisecond. With it, You can implement a timer with a precision higher than 1 ms.
Int32 oaltimercountssincesystick ()
{
Uint32 lasttimermatch = (g_xllposthandle.postregs-> osmr0-g_oaltimer.countspersponick );
// How many ticks since the last timer interrupt?
Return (g_xllposthandle.postregs-> oscr0-lasttimermatch );
}
Http://www.cnblogs.com/jasonye/archive/2007/06/27/796756.html