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 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 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 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 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 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 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 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