1@page page_clock_management Clock & Timer Management
2
3The concept of time is very important. You need to set a time to go out with friends and it takes time to complete tasks. Life is inseparable from time. The same is true for operating systems, which require time to regulate the execution of their tasks. The smallest time unit in operating system is clock tick (OS Tick). This chapter focuses on introduction of clock ticks and clock-based timers. After reading this chapter, we will learn how clock ticks are generated and how to use RT-Thread timers.
4
5# Clock Tick(OS Tick)
6
7Any operating system needs to provide a clock tick for the system to handle all time-related events, such as thread latency, thread time slice rotation scheduling, timer timeout, etc. Clock tick is a specific periodic interrupt. This interrupt can be regarded as the system heartbeat. The time interval between interrupts depends on different applications, generally it is 1ms–100ms. The faster the clock tick rate, the greater the overhead of the system. The number of clock ticks counted from the start of the system is called the system time.
8
9In RT-Thread, the length of clock tick can be adjusted according to the value of RT_TICK_PER_SECOND, which is equal to 1/RT_TICK_PER_SECOND second.
10
11## Clock Tick Implementation
12
13Clock tick is generated by a hardware timer configured in interrupt trigger mode.  `void rt_tick_increase(void)` will be called when an interrupt occurs,notifying the operating system that a system clock has passed; different hardware driver have different timer interrupt implementations. Here is an example of using STM32 `SysTick_Handler` to achieve clock Tick.
14
15```c
16void SysTick_Handler(void)
17{
18    /* Entry Interrupt*/
19    rt_interrupt_enter();
20    ……
21    rt_tick_increase();
22    /* Leave Interrupt */
23    rt_interrupt_leave();
24}
25```
26
27Call `rt_tick_increase()` in interrupt function to self-add global variable rt_tick. The code is as follows:
28
29```c
30void rt_tick_increase(void)
31{
32    struct rt_thread *thread;
33
34    /* Global variable rt_tick self-add */
35    ++ rt_tick;
36
37    /* Check time slice */
38    thread = rt_thread_self();
39
40    -- thread->remaining_tick;
41    if (thread->remaining_tick == 0)
42    {
43        /* Re-assign initial value */
44        thread->remaining_tick = thread->init_tick;
45
46        /* Thread suspends */
47        rt_thread_yield();
48    }
49
50    /* Check time slice */
51    rt_timer_check();
52}
53```
54
55You can see that global variable rt_tick is incremented by one on every clock tick.  The value of rt_tick indicates the total number of clock ticks that the system has elapsed since it started, that is, system time. In addition, on every clock tick, whether the current thread's time slice is exhausted and whether there is a timer timeout will be checked.
56
57>In interrupt, rt_timer_check()  is used to check the system hardware timer linked list. If there is a timer timeout, the corresponding timeout function will be called. All timers are removed from the timer linked list if it timed out, and periodic timer is added to the timer linked list when it is started again.
58
59## Obtain Clock Tick
60
61Since global variable rt_tick is incremented by one on every clock tick, the value of the current rt_tick will be returned by calling `rt_tick_get`, which is the current clock tick value. This interface can be used to record the length of time a system is running, or to measure the time it takes for a task to run. The interface function is as follows:
62
63```c
64rt_tick_t rt_tick_get(void);
65```
66
67The following table describes the return values of `rt_tick_get()` function:
68
69|**R**eturn|Description      |
70|----------|----------------|
71| rt_tick  | Current clock tick value |
72
73# Timer Management
74
75Timer refers to triggering an event after a certain specified time from a specified moment, for example, setting a timer to wake up yourself the next morning. Timer includes hardware timer and software timer:
76
771) **Hardware timer** is the timing function provided by the chip itself. The hardware timer can be used by configuring the timer module into a timer mode and setting the time. Hardware timer is accurate to nanosecond precision, and is interrupt trigger mode.
78
792) **Software timer** is a type of system interface provided by the operating system. It is built on the basis of the hardware timer to enable the system to provide a timer service with no constraint on numbers.
80
81RT-Thread operating system provides software-implemented timers in units of clock tick (OS Tick), that is, the timing value must be an integer multiple of OS Tick. For example, an OS Tick is 10ms, then the software timer can only be timed 10ms, 20ms, 100ms, etc., but not 15ms. RT-Thread timer is also based on the clock tick, providing timing capabilities based on integral multiples of the clock tick.
82
83## RT-Thread Timer Introduction
84
85RT-Thread timer provides two types of timer mechanisms: the first type is a one-shot timer, which only triggers a timer event for onetime after startup, and then the timer stops automatically. The second type is a periodic trigger timer, which periodically triggers a timer event until the user manually stops it, otherwise it will continue to execute forever.
86
87In addition, according to the context in which the timeout function is executed, RT-Thread timer can be divided into HARD_TIMER mode and SOFT_TIMER mode, as shown in the following figure.
88
89![Timer Context](figures/05timer_env.png)
90
91### HARD_TIMER Mode
92
93The timer timeout function of HARD_TIMER mode is executed in the interrupt context and can be specified with the parameter RT_TIMER_FLAG_HARD_TIMER when initializing/creating the timer.
94
95When executed in interrupt context, the requirements for timeout function are the same as those for the interrupt service routine: execution time should be as short as possible, and the execution should not cause the current context to suspend and wait. For example, a timeout function executed in an interrupt context should not attempt to apply for dynamic memory, free dynamic memory, etc.
96
97The default mode of RT-Thread timer is HARD_TIMER mode which means after the timer timeout, the timeout function runs in the context of the system clock interrupt. The execution mode in the interrupt context determines that the timer's timeout function should not call any system function that will cause the current context to suspend; nor can it be executing for a very long time, otherwise the response time of other interrupts will be lengthened or the running time of other threads will be preempted.
98
99### SOFT_TIMER Mode
100
101The SOFT_TIMER mode is configurable and macro definition RT_USING_TIMER_SOFT is used to determine whether the mode should be enabled. When this mode is enabled, the system will create a timer thread at initialization, and then the timer timeout function of SOFT_TIMER mode will be executed in the context of the timer thread. SOFT_TIMER mode can be specified using the parameter RT_TIMER_FLAG_SOFT_TIMER when initializing/creating the timer.
102
103## Timer Working Mechanism
104
105The following is an example to illustrate the working mechanism of RT-Thread timer. Two important global variables are maintained in the RT-Thread timer module:
106
107 (1)  Elapsed tick time of the current system rt_tick (when hardware timer interrupt comes, it will add 1);
108
109 (2)  Timer linked list `rt_timer_list`. Newly created and activated timers of the system are inputted into the `rt_timer_list` linked list in a timeout-ordered manner.
110
111As shown in the figure below, the current tick value of the system is 20. In the current system, three timers have been created and started, which are Timer1 with 50 ticks set time, Timer2 with 100 ticks, and Timer3 with 500 ticks. Current time of the system rt_tick=20 is added respectively on these three timers and they are linked from small to large in the rt_timer_list linked list, forming a timer linked list structure as shown in the figure.
112
113![Timer Linked List Diagram](figures/05timer_linked_list.png)
114
115Along with the trigger of the hardware timer, `rt_tick` has been increasing (rt_tick variable is incremented by 1 every time the hardware timer is interrupted). After 50 tick, rt_tick is increased from 20 to 70, which is equal to the timeout value of Timer1. Then, timeout functions associated with the Timer1 timer will be triggered and Timer1 from the rt_timer_list linked list will be removed. Similarly, after 100 ticks and 500 ticks, timeout functions associated with Timer2 and Timer3 are triggered, and  timers of Time2 and Timer3 will be removed from the rt_timer_list linked list.
116
117If after system's 10 ticks (current rt_tick=30),  a new task has created Timer4 with 300 ticks, so the Timer4's timeout is equal to rt_tick add 300, that is 330. Timer4 will be inserted in between Timer2 and Timer3, forming a linked list structure shown below:
118
119![Timer linked List Insertion Diagram](figures/05timer_linked_list2.png)
120
121### Timer Control Block
122
123In RT-Thread operating system, timer control block is defined by structure `struct rt_timer` and forms a timer kernel object, which is then linked to the kernel object container for management. It is a data structure used by the operating system to manage timers. It stores information about timers, such as the initial number of ticks, the number of timeout ticks, the linked list structure used to connect timers, timeout callback functions, etc.
124
125```c
126struct rt_timer
127{
128    struct rt_object parent;
129    rt_list_t row[RT_TIMER_SKIP_LIST_LEVEL];  /* Timer Linked List Node */
130
131    void (*timeout_func)(void *parameter);     /* Timeout Function */
132    void      *parameter;                      /* Parameters of Timeout Function  */
133    rt_tick_t init_tick;                       /* Timer Initial Timeout Ticks */
134    rt_tick_t timeout_tick;                    /* Number of ticks when the timer actually times out */
135};
136typedef struct rt_timer *rt_timer_t;
137```
138
139Timer control block is defined by  structure `struct rt_timer` and forms a timer kernel object, which is then linked to the kernel object container for management. The `list` member is used to link an active (already started) timer to the `rt_timer_list` linked list.
140
141### Timer Skip List Algorithm
142
143In the introduction of working mechanics of the timer above, we have talked about that the newly created and activated timers are inserted into the rt_timer_list linked list in the order of the timeout, that is, rt_timer_list linked list is an ordered list. RT-Thread uses a skip list algorithm to speed up the search for linked list elements.
144
145Skip list is a data structure based on a parallel linked list, which is simple to implement, and the time complexity of insertion, deletion, and search is O(log n). Skip list is a kind of linked list, but it adds a "skip" function to the linked list. It is this function that enables the skip list to have the time complexity of O(log n) when looking for elements, for example:
146
147An ordered list, as shown in the following figure, searches for elements {13, 39} from the ordered list. The number of comparisons is {3, 5} and the total number of comparisons is 3 + 5 = 8 times.
148
149![Ordered Linked List](figures/05timer_skip_list.png)
150
151After using the skip list algorithm, a method similar to binary search tree can be used to extract some nodes as indexes, and then the structure shown in the following figure is obtained:
152
153![Ordered Linked List Index](figures/05timer_skip_list2.png)
154
155In this structure, {3, 18, 77} is extracted as first-level index, so that the number of comparisons can be reduced when searching. For example, there are only 3 times of comparisons when searching 39 (by comparing 3, 18, 39). Of course, we can also extract some elements from the first-level index, as a secondary index, which can speed up the element search.
156
157![Three Layer Skip List](figures/05timer_skip_list3.png)
158
159Therefore, the timer skip list can pass the index of the upper layer, reducing the number of comparisons during the search and improving the efficiency of the search. This is an algorithm of "space in exchange of time", macro definition RT_TIMER_SKIP_LIST_LEVEL is used to configure the number of layers in skip list. The default value is 1, which means that ordered linked list algorithm for first-order ordered list graph is used. Each additional one means that another level of index is added to the original list.
160
161## Timer Management
162
163RT-Thread timer is introduced in the previous sections and the working mechanism of the timer is conceptually explained. This section will go deep into the various interfaces of the timer to help the reader understand the RT-Thread timer at the code level.
164
165Timer management system needs to be initialized at system startup. This can be done through the following function interface:
166
167```c
168void rt_system_timer_init(void);
169```
170
171If you need to use SOFT_TIMER, the following function interface should be called when the system is initialized:
172
173```c
174void rt_system_timer_thread_init(void);
175```
176
177Timer control block contains important parameters related to the timer and acts as a link between various states of the timer. Relevant operations of the timer are as shown in the following figure. Relevant operations of the timer includes: creating/initializing the timer, starting the timer, running the timer, and deleting/detaching the timer. All the timers will be moved from the timer linked list after their timings expire. However, periodic timer is added back to the timer linked list when it is started again, which is related to timer parameter settings. Each time an operating system clock interrupt occurs, a change is made to the timer status parameter that has timed out.
178
179![Timer Related Operations](figures/05timer_ops.png)
180
181### Create and Delete Timer
182
183When dynamically creating a timer, the following function interface can be used:
184
185```c
186rt_timer_t rt_timer_create(const char* name,
187                           void (*timeout)(void* parameter),
188                           void* parameter,
189                           rt_tick_t time,
190                           rt_uint8_t flag);
191```
192
193After calling the function interface, kernel first allocates a timer control block from the dynamic memory heap and then performs basic initialization on the control block. The description of each parameter and return value is detailed in the following table:
194
195  Input parameters and return values of `rt_timer_create()`
196
197|**Parameters**                       |**Description**                                                                                                |
198|---------------------------------|--------------------------------------------------------------------------|
199| name                            | Name of the timer                                                                            |
200| void (timeout) (void parameter) | Timer timeout function pointer (this function is called when the timer expires) |
201| parameter                       | Entry parameter of the timer timeout function (when the timer expires, calling timeout callback function will pass this parameters as the entry parameter to the timeout function) |
202| time                            | Timeout of the timer, the unit is the clock tick                         |
203| flag                            | Parameters when the timer is created. The supported values include one-shot timing,  periodic timing, hardware timer, software timer, etc. (You can use multiple values with "OR") |
204|**Return**                       | ——                                                                                                       |
205| RT_NULL                         | Creation failed (usually returning RT_NULL due to insufficient system memory) |
206| Timer Handle       | Timer was created successfully.                                                        |
207
208In include/rtdef.h, some timer related macros are defined, as follows:
209
210```c
211#define RT_TIMER_FLAG_ONE_SHOT      0x0     /* One shot timing     */
212#define RT_TIMER_FLAG_PERIODIC      0x2     /* Periodic timing     */
213
214#define RT_TIMER_FLAG_HARD_TIMER    0x0     /* Hardware timer   */
215#define RT_TIMER_FLAG_SOFT_TIMER    0x4     /* Software timer  */
216```
217
218The above two sets of values can be assigned to the flag in an "or" logical manner. When the specified flag is RT_TIMER_FLAG_HARD_TIMER, if the timer expires, the timer's callback function will be called in the context of the service routine of the clock interrupt; when the specified flag is RT_TIMER_FLAG_SOFT_TIMER, if the timer expires, the timer's callback function will be called in the context of the system clock timer thread.
219
220When the system no longer uses dynamic timers, the following function interface can be used:
221
222```c
223rt_err_t rt_timer_delete(rt_timer_t timer);
224```
225
226After calling this function interface, the system will remove this timer from the rt_timer_list linked list, and then release the memory occupied by the corresponding timer control block. The parameters and return values are detailed in the following table:
227
228Input parameters and return values of rt_timer_delete()
229
230|**Parameters**|**Description**                                                               |
231|----------|-------------------------------------------------------------------------|
232| timer    | Timer handle, pointing at timer needs to be deleted |
233|**Return**| ——                                                                      |
234| RT_EOK   | Deletion is successful (if the parameter timer handle is RT_NULL, it will result in an ASSERT assertion) |
235
236### Initialize and Detach Timer
237
238When creating a timer statically , the timer can be initialized by using `rt_timer_init` interface. The function interface is as follows:
239
240```c
241void rt_timer_init(rt_timer_t timer,
242                   const char* name,
243                   void (*timeout)(void* parameter),
244                   void* parameter,
245                   rt_tick_t time, rt_uint8_t flag);
246```
247
248When using this function interface, the corresponding timer control block, the corresponding timer name, timer timeout function, etc will be initialized. The description of each parameter and return value is shown in the following table:
249
250Input parameters and return values of `rt_timer_init()`
251
252|Parameters                       |**Description**                                                                                                                  |
253|---------------------------------|-------------------------------------------------------------------------------------|
254| timer                           | Timer handle, pointing to the to-be-initialized timer control block |
255| name                            | Name of the timer                                                                                             |
256| void (timeout) (void parameter) | Timer timeout function pointer (this function is called when the timer expires) |
257| parameter                       | Entry parameter of the timer timeout function (when the timer expires, the call timeout callback function will pass this parameter as the entry parameter to the timeout function) |
258| time                            | Timeout of the timer, the unit is clock tick                                  |
259| flag                            | Parameters of when the timer is created. The supported values include one shot timing, periodic timing, hardware timer, and software timer (multiple values can be taken with OR). For details, see Creating a Timer. |
260
261When a static timer does not need to be used again, you can use the following function interface:
262
263```c
264rt_err_t rt_timer_detach(rt_timer_t timer);
265```
266
267When detaching a timer, the system will detach the timer object from the kernel object container, but the memory occupied by the timer object will not be released. The parameters and return values are detailed in the following table:
268
269Input parameters and return values for `rt_timer_detach()`
270
271|**Parameters**|Description                            |
272|----------|--------------------------------------|
273| timer    | Timer handle, pointing to the to-be-detached timer control block |
274|**Return **| ——                                   |
275| RT_EOK   | Successfully detached     |
276
277### Start and Stop Timer
278
279When the timer is created or initialized, it will not be started immediately. It will start after timer function interface is called. The timer function interface is started as follows:
280
281```c
282rt_err_t rt_timer_start(rt_timer_t timer);
283```
284
285After the timer start function interface is called, the state of the timer is changed to activated state (RT_TIMER_FLAG_ACTIVATED) and inserted into rt_timer_list queue linked list, the parameters and return values are detailed in the following table:
286
287  Input parameters and return values of rt_timer_start()
288
289|Parameters|Description                            |
290|----------|--------------------------------------|
291| timer    | Timer handle, pointing to the to-be-initialized timer control block |
292|**Return**| ——                                   |
293| RT_EOK   | Successful startup           |
294
295For an example of starting the timer, please refer to the sample code below.
296
297After starting the timer, if you want to stop it, you can use the following function interface:
298
299```c
300rt_err_t rt_timer_stop(rt_timer_t timer);
301```
302
303After the timer stop function interface is called, the timer state will change to the stop state and will be detached from the rt_timer_list linked list without participating in the timer timeout check. When a (periodic) timer expires, this function interface can also be called to stop the (periodic) timer itself. The parameters and return values are detailed in the following table:
304
305  Input parameters and return values of rt_timer_stop()
306
307|**Parameters**   |Description                            |
308|-------------|--------------------------------------|
309| timer       | Timer handle, pointing to the to-be-stopped timer control block |
310|**Return**   | ——                                   |
311| RT_EOK      | Timer successfully stopped |
312| \- RT_ERROR | timer is in stopped state |
313
314### Control Timer
315
316In addition to some of the programming interfaces provided above, RT-Thread additionally provides a timer control function interface to obtain or set more timer information. The control timer function interface is as follows:
317
318```c
319rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg);
320```
321
322The control timer function interface can view or change the setting of the timer according to the parameters of the command type. The description of each parameter and return value is as follows:
323
324Input parameters and return values of rt_timer_control()
325
326|Parameters|**Description**                                                                                                |
327|----------|----------------------------------------------------------------------------------------------------------|
328| timer    | Timer handle, pointing to the to-be-stopped timer control block      |
329| cmd      | The command for controlling the timer currently supports four command interfaces, which are setting timing, viewing the timing time, setting a one shot trigger, and setting the periodic trigger. |
330| arg      | Control command parameters corresponding to cmd. For example, when cmd is the set timeout time, the timeout time parameter can be set by arg. |
331|**Return**| ——                                                                                                       |
332| RT_EOK   | Successful                                                                                            |
333
334Commands supported by function parameters cmd:
335
336```c
337#define RT_TIMER_CTRL_SET_TIME      0x0     /* Set Timeout value      */
338#define RT_TIMER_CTRL_GET_TIME      0x1     /* Obtain Timer Timeout Time      */
339#define RT_TIMER_CTRL_SET_ONESHOT   0x2     /* Set the timer as a oneshot timer.   */
340#define RT_TIMER_CTRL_SET_PERIODIC  0x3     /* Set the timer as a periodic timer */
341```
342
343See "dynamic timer routine" for code that uses the timer control interface.
344
345# Timer Application Sample
346
347This is an example of creating a timer that creates two dynamic timers, one for one shot timing, another one for periodic timing and for the periodic timer to run for a while and then stop running, as shown below:
348
349```c
350#include <rtthread.h>
351
352/* Timer Control Block */
353static rt_timer_t timer1;
354static rt_timer_t timer2;
355static int cnt = 0;
356
357/* Timer 1 Timeout Function */
358static void timeout1(void *parameter)
359{
360    rt_kprintf("periodic timer is timeout %d\n", cnt);
361
362    /* On the 10th time, stops perodic timer */
363    if (cnt++>= 9)
364    {
365        rt_timer_stop(timer1);
366        rt_kprintf("periodic timer was stopped! \n");
367    }
368}
369
370/* Timer 2 Timeout Function */
371static void timeout2(void *parameter)
372{
373    rt_kprintf("one shot timer is timeout\n");
374}
375
376int timer_sample(void)
377{
378    /* Create Timer 1 Periodic Timer */
379    timer1 = rt_timer_create("timer1", timeout1,
380                             RT_NULL, 10,
381                             RT_TIMER_FLAG_PERIODIC);
382
383    /* Start Timer 1*/
384    if (timer1 != RT_NULL) rt_timer_start(timer1);
385
386    /* Create Timer 2 One Shot Timer */
387    timer2 = rt_timer_create("timer2", timeout2,
388                             RT_NULL,  30,
389                             RT_TIMER_FLAG_ONE_SHOT);
390
391    /* Start Timer 2 */
392    if (timer2 != RT_NULL) rt_timer_start(timer2);
393    return 0;
394}
395
396/* Export to msh command list */
397MSH_CMD_EXPORT(timer_sample, timer sample);
398```
399
400The simulation results are as follows:
401
402```
403 \ | /
404- RT -     Thread Operating System
405 / | \     3.1.0 build Aug 24 2018
406 2006 - 2018 Copyright by rt-thread team
407msh >timer_sample
408msh >periodic timer is timeout 0
409periodic timer is timeout 1
410one shot timer is timeout
411periodic timer is timeout 2
412periodic timer is timeout 3
413periodic timer is timeout 4
414periodic timer is timeout 5
415periodic timer is timeout 6
416periodic timer is timeout 7
417periodic timer is timeout 8
418periodic timer is timeout 9
419periodic timer was stopped!
420```
421
422Timeout function of periodic timer 1 runs once every 10 OS Ticks for 10 times (after 10 times, rt_timer_stop is called to stop timer 1); timeout function of one-shot timer 2 runs once on the 30th OS Tick.
423
424The example of initializing timer is similar to the example of creating a timer. This program initializes two static timers, one is one-shot timing and one is periodic timing, as shown in the following code:
425
426```c
427#include <rtthread.h>
428
429/* Timer Control Block */
430static struct rt_timer timer1;
431static struct rt_timer timer2;
432static int cnt = 0;
433
434/* Timer 1 Timeout Function */
435static void timeout1(void* parameter)
436{
437    rt_kprintf("periodic timer is timeout\n");
438    /* Run for 10 times */
439    if (cnt++>= 9)
440    {
441        rt_timer_stop(&timer1);
442    }
443}
444
445/* Timer 2 Timeout Function */
446static void timeout2(void* parameter)
447{
448    rt_kprintf("one shot timer is timeout\n");
449}
450
451int timer_static_sample(void)
452{
453    /* Initialize Timer */
454    rt_timer_init(&timer1, "timer1",  /* Timer name is timer1 */
455                    timeout1, /* Callback handler for timeout */
456                    RT_NULL, /* Entry parameter of the timeout function */
457                    10, /* Timing length in OS Tick, 10 OS Tick */
458                    RT_TIMER_FLAG_PERIODIC); /* Periodic timer */
459    rt_timer_init(&timer2, "timer2",   /* Timer name is timer2 */
460                    timeout2, /* Callback handler for timeout */
461                      RT_NULL, /* Entry parameter of the timeout function */
462                      30, /* Timing length is 30 OS Tick */
463                    RT_TIMER_FLAG_ONE_SHOT); /* One-shot timer */
464
465    /* Start Timer */
466    rt_timer_start(&timer1);
467    rt_timer_start(&timer2);
468    return 0;
469}
470/* Export to msh command list */
471MSH_CMD_EXPORT(timer_static_sample, timer_static sample);
472```
473
474The simulation results are as follows:
475
476```
477\ | /
478- RT -     Thread Operating System
479 / | \     3.1.0 build Aug 24 2018
480 2006 - 2018 Copyright by rt-thread team
481msh >timer_static_sample
482msh >periodic timer is timeout
483periodic timer is timeout
484one shot timer is timeout
485periodic timer is timeout
486periodic timer is timeout
487periodic timer is timeout
488periodic timer is timeout
489periodic timer is timeout
490periodic timer is timeout
491periodic timer is timeout
492periodic timer is timeout
493```
494
495The timeout function of periodic timer1 runs once every 10 OS Ticks for 10 times (After 10 times rt_timer_stop is called to stop timer1); the timeout function of one-shot timer2 runs once on the 30th OS Tick.
496
497# High Precision Delay
498
499The minimum precision of the RT-Thread timer is determined by the system clock tick (1 OS Tick = 1/RT_TICK_PER_SECOND second, RT_TICK_PER_SECOND value is defined in the rtconfig.h file), and the timer must be set to an integer multiple of the OS Tick. When it is necessary to implement system timing for a shorter time length. For example, the OS Tick is 10ms but the program needs to implement a timing or delay of 1ms. In this case, the operating system timer can't meet the requirements. This problem can be solved by reading the counter of a hardware timer of the system or using hardware timer directly.
500
501In Cortex-M series, SysTick has been used by RT-Thread as an OS Tick. It is configured to trigger an interrupt after 1/RT_TICK_PER_SECOND seconds. The interrupt handler uses the Cortex-M3 default name `SysTick_Handler`. In Cortex-M3 CMSIS (Cortex Microcontroller Software Interface Standard) specification, SystemCoreClock represents the dominant frequency of the chip, so based on SysTick and SystemCoreClock, we can use SysTick to obtain an accurate delay function, as shown in the following example, Cortex-M3 SysTick-based precision delay (requires the system to enable SysTick):
502
503The high-precision delay routine is as follows:
504
505```c
506#include <board.h>
507void rt_hw_us_delay(rt_uint32_t us)
508{
509    rt_uint32_t delta;
510    /* Obtain the number of ticks of the delay */
511    us = us * (SysTick->LOAD/(1000000/RT_TICK_PER_SECOND));
512    /* Obtain current time */
513    delta = SysTick->VAL;
514    /* Loop to obtain the current time until the specified time elapses and exits the loop */
515    while (delta - SysTick->VAL< us);
516}
517```
518
519The entry parameter us indicates the number of microseconds that need to be delayed. This function can only support delays shorter than 1 OS Tick, otherwise the SysTick will overflow and not be able to obtain the specified delay time.
520
521