1. The relationship between the system clock and the kernel WinCE 5.0 uses a time-slice-based preemptive multi-tasking real-time kernel, and each thread can set its own thread time slice size (refer to the Cesetthreadquantum function), the default is 100ms, This default value, Dwdefaultthreadquantum, can also be set at Oeminit (). In the kernel source file, the variable name associated with the word quantum is generally referred to as a time slice, and the wince kernel defines several clock-related global variables, which are also part of the kernel and OAL interface: 1) dwreschedtime, which is updated in the kernel scheduler, Kcnextthread () is part of the kernel scheduler, which determines the next running thread based on the priority and state of the thread, and sets the dwreschedtime based on the thread's time slice. As the name implies, this variable refers to the next time the scheduler is run. Now that we're talking about the kernel of WinCE 5.0, we have to insert it. The scheduler has a new feature called a variable system tick, which is designed to allow the hardware timer (CPU clock) to interrupt only when the scheduler needs it. This will not only improve the efficiency of the scheduler, but also help the CPU energy saving (discussed later). This feature is optional and depends on the implementation of the OAL. Without this feature, typically each system has a clock beat of 1ms, i.e. a clock interrupt per millisecond. Of course, just like the default thread time slice, this value can be set at Oeminit (). 2) Curmsec,dword type variable, updated each time the clock is interrupted, the cumulative number of system clock beats (too much around the mouth, or the number of ticks) that the system has experienced since the system started. If the user program calls the GetTickCount () function, it actually returns the value of the variable directly. As noted above, when the system tick is 1ms, the curmsec is a millisecond counter, and GetTickCount () will not exceed 1ms in accuracy. In the clock interrupt handler function (TIMERISR), in addition to updating the CURMSEC, it is also determined by Dwreschedtime whether the scheduler is running: if ((int) (curmsec-dwreschedtime) >= 0) SysIntr = sysintr_resched; 3) Curridlehigh, CurridlElow, Idleconv These variables implement a 64-bit counter that reflects the time the system is in idle mode. Typically updated within the Oemidle () function. The user program can get this value by calling the Getidletime () function. Here again to insert some knowledge about Oemidle: Scheduling algorithm and power management is closely related, that is, with the central government to promote the energy saving and emission reduction has a certain link because most mobile devices are looking to save energy, so when all the threads are in a blocking state, the kernel will call Oemidle ( ) puts the CPU in idle mode (Low power state). This state is not available until an interrupt occurs or when a thread can run. In fact, many devices spend a lot of time waiting for the user's input, so if the CPU supports low-power mode, it should be implemented in the Oemidle function. If you do not take the new scheduler feature mentioned earlier (Variable Tick Scheduler), you also need to determine the exact time period of idle in the Oemidle function, while the variable system time beats can be set up with the correct clock interrupt in advance, This allows the Oemidle function to put the CPU into a low-power state faster, which is why it saves energy. Sometimes you need to calculate the CPU usage of a program run, you can use the following code: Dwstarttick = GetTickCount (); Dwidlest = Getidletime (); Sleep (); Code Snippet Dwstoptick = GetTickCount (); Dwidleed = Getidletime (); Percentidle = ((100* (Dwidleed-dwidlest))/(Dwstoptick-dwstarttick)); This code is shown in the Getidletime section of MSDN, where 1-percentidle is CPU usage. 2. System clock Module structure This article introduces the implementation of the system clock module with the Pqoal (production-quality OAL) structure, Pqoal is WinCE 5.0, it can simplify the implementation of OAL code, and facilitate the migration of OAL code. Simple analysis of the directory structure:%_winceroot%/platform/common for hardware-independent and CPU-related pQoal code,%_winceroot%/platform/common/src/common is hardware-independent code, the following is a yellow background to enumerate such functions;%_winceroot%/platform/common/src/$ Cpu$ is the CPU-related code, the following is a green background to enumerate such functions. If your platform uses a CPU that already exists in this directory, such as pxa270 related code is in the%_winceroot%/platform/common/src/arm/intel/pxa27x directory, generally do not need to make any changes, This code can do most of the OAL functionality. As far as the PXA270 system clock module is concerned, it is not necessary to write any code yourself, but this part of the code does not implement the new feature of WinCE 5.0 (Variable Tick Scheduler). In particular, the default implementation of Oalcpuidle () is simply a loop, and it is best to implement this function on its own, putting the CPU into a low-power state. In OAL, the data structures associated with 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 interacting with the kernel 2.1.1 UINT32 oaltimerintrhandler (); This is the previously mentioned TIMERISR, the clock interrupt handler function, which returns a SYSINTR_ value. 2.1.2 Curmsec, previously mentioned, is defined in the kernel source file. 2.1.3 Oemidle (), as mentioned earlier, already has a pqoal implementation, which internally calls Oalcpuidle () to place the CPU in idle mode (Low power state). 2.1.4 Sc_gettickcount () This is the millisecond timer required by the kernel to return the number of milliseconds from the start of the system startup. If the system clock beat is 1ms, then return directly to Curmsec, otherwise if the system clock beats more than 1ms, you need a high precision counter to adjust the time interval to one millisecond. The function has been implemented by Pqoal, but it calls the hardware-related function Oaltimercountssincesystick (). 2.1.5 Pqueryperformancefrequency, Pqueryperformancecounter a function pointer defined in the kernel to achieve a high-precision timer with these two functions. The prototypes of these two functions have also been implemented by Pqoal, namely Oaltimerqueryperformancefrequency and Oaltimerqueryperformancecounter, The hardware-related functions Oaltimercountssincesystick () and OAL layer variable G_oaltimer are also called. 2.1.6 the function pointers defined in the Poemupdaterescheduletime kernel, it is necessary to implement this function if the variable tick scheduler is to be used, mainly to reset the clock timing period based on the changed system beats (Tick). To avoid unnecessary clock interruptions. Pqoal provides an example of the Oaltimerupdaterescheduletime function that can be referenced by the implementation, which invokes 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, which is usually called in the Oeminit function. This includes initializing the OAL layer variable G_oaltimer, initializing the kernel variable curridlehigh, curridlelow, Idleconv, initializing the kernel function pointer (2.1.5,2.1.6), and initializing the hardware clock timer. 2.2.2 The variables of the g_oaltimer,oal_timer_state structure, including 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 Msecpersystick; msec per SystEM tick UINT32 Countspersystick; Counts per system tick UINT32 Actualmsecpersystick; Actual msec per system tick UINT32 Actualcountspersystick; 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 elapsed time from the last tick of the system, generally requiring a precision higher than 1ms, in other words, the crystal frequency of the hardware clock is higher than 1MHz. 2.2.4 Oaltimerupdaterescheduletime (), see 2.1.6 2.2.5 Oaltimerrecharge (), Oaltimerupdate (), Oalstall () 2.2.6 Oalgetti Ckcount () 3. Implement high-precision timers Sometimes the user program wants to call QueryPerformanceCounter () and QueryPerformanceFrequency () to achieve a more accurate timing than 1ms. According to 2.1.5, Pqoal has basically implemented this part of the code, we only need to implement Oaltimercountssincesystick (2.2.3) based on the CPU used. The PXA270 processor has two sets of clock channels that allow the software to set the clock interrupt, which is known as the operating system clock (Operating system Timer), please refer to "Intel pxa27x Processor Family Developer" for details. Manual ". Here only a set of PXA255-compatible clock channels, which use 3.25M crystal oscillator, which can be counted 3,250 times per millisecond, with it can be achieved more than 1ms precision timer. INT32 OaltimercoUntssincesystick () {UINT32 Lasttimermatch = (G_xllposthandle.postregs->osmr0-g_oaltimer.countspersystick); How many ticks since the last timer interrupt? return (G_xllposthandle.postregs->oscr0-lasttimermatch);}
"Turn" OAL system clock