1--- 2title: Low Power Utility 3author: sclarson 4ms.author: sclarson 5description: This article is a summary of the Low Power utility APIs available in ThreadX. 6ms.date: 03/02/2021 7ms.topic: article 8ms.service: rtos 9--- 10 11# ThreadX Low Power Utilities 12 13These low power utilities are intended to maintain ThreadX timers and the internal tick count while the processor is in a low-power/sleep state. The terms "low power" and "sleep" are used interchangeably throughout this document. 14 15The low power utilities may be used with any ThreadX port except SMP. 16 17## Installation of Low Power Utilities 18 19The ThreadX low power utilities are comprised of two files: 20 21 - [tx_low_power.c](tx_low_power.c) 22 - [tx_low_power.h](tx_low_power.h) 23 24These files can be built with the ThreadX library or built in the user application. 25 26## Detailed Description 27 28By default, ThreadX spins in an idle loop in the scheduler when there are no threads ready to run. It may be desireable to put the processor in a low power state while idle. Functions ```tx_low_power_enter``` and ```tx_low_power_exit``` are designed to enter and exit low power mode, respectively. 29 30The ```tx_low_power_enter``` and ```tx_low_power_exit``` functions manage the ThreadX timers and invoke optional macros that the user must define in order to configure the hardware for low power mode. These macros are discussed in a section below. 31 32For convenience, the Cortex-M and RX ports have calls to the low power APIs already integrated into their schedulers. If symbol **TX_LOW_POWER** is defined, functions ```tx_low_power_enter``` and ```tx_low_power_exit``` are called in the scheduler idle loop. It is assumed that the processor will exit sleep mode and resume execution in the idle loop (or in an interrupt and then return to the idle loop). For processors that exhibit different behavior (such as waking from sleep at the reset vector), these low power functions may need to be called elsewhere. 33 34### Low Power Timer and Tick-less Low Power Mode 35 36If accurate timekeeping is not desired while in low power mode, macros **TX_LOW_POWER_TIMER_SETUP** and **TX_LOW_POWER_TICKLESS** do not need to be defined. The internal ThreadX tick count will not reflect the time spent in low power mode. 37 38If **TX_LOW_POWER_TIMER_SETUP** is defined, there are two use cases for timekeeping in low power operation: 391. Keep track of elapsed time in low power mode only when ThreadX timers are active. If there are ThreadX timers active, the elapsed time while in low power mode must be measured, thus a low power hardware timer is required (this timer can be configured in **TX_LOW_POWER_TIMER_SETUP**). If there are no ThreadX timers active when entering low power mode, then no hardware timer needs to keep track of elapsed time. This is "tick-less" operation. To enable this feature, the symbol **TX_LOW_POWER_TICKLESS** must be defined. The internal ThreadX tick count will not reflect the time spent in low power mode when no ThreadX timers are active. 402. Always keep track of time in low power mode. This is necessary to keep the internal ThreadX tick count accurate. In this case, **TX_LOW_POWER_TICKLESS** must *not* be defined, as a hardware timer will always be needed in low power mode to measure elapsed time. The hardware timer is intended to be configured in **TX_LOW_POWER_TIMER_SETUP**. 41 42> Example 1: No low power timer is in use (**TX_LOW_POWER_TIMER_SETUP** is *not* defined). There is a ThreadX timer with 50 ticks remaining. The internal ThreadX tick count is 1000. The processor goes into low power mode for some length of time. After exiting low power mode, the ThreadX timer still has 50 ticks remaining. The internal ThreadX tick count is 1000. 43 44> Example 2: A low power timer is available (**TX_LOW_POWER_TIMER_SETUP** is defined). **TX_LOW_POWER_TICKLESS** is defined. There is a ThreadX timer A with 50 ticks remaining and another ThreadX timer B with 20 ticks remaining. The internal ThreadX tick count is 1000. The processor goes into low power mode for 20 ticks. Upon exiting low power mode, the ThreadX timer A will have 30 ticks remaining. The expiration function for ThreadX timer B will be executed. The internal ThreadX tick count is 1020. 45After executing for some time, the internal ThreadX tick count is 2000 and there are no ThreadX timers active. The processor goes into low power mode for some length of time. After exiting low power mode, the internal ThreadX tick count is 2000. 46 47> Example 3: A low power timer is always used (**TX_LOW_POWER_TIMER_SETUP** is defined and **TX_LOW_POWER_TICKLESS** is *not* defined). The internal ThreadX tick count is 1000 and there are no ThreadX timers active. The processor goes into low power mode for some length of time. Upon exiting low power mode, it is determined that the processor was in low power mode for 20 ticks. The internal ThreadX tick count is updated to 1020. 48 49## User-defined Macros 50 51The following macros invoke functions that the user may want to define/implement. 52 53### Summary of user-defined macros 54 55 - ```TX_LOW_POWER_TIMER_SETUP``` - *set up low power timer* 56 - ```TX_LOW_POWER_USER_ENTER``` - *configure processor to enter low power mode* 57 - ```TX_LOW_POWER_USER_EXIT``` - *configure processor to exit low power mode* 58 - ```TX_LOW_POWER_USER_TIMER_ADJUST``` - *return the number of ticks the processor was in low power mode* 59 60--- 61 62### TX_LOW_POWER_TIMER_SETUP 63```c 64VOID TX_LOW_POWER_TIMER_SETUP(ULONG tx_low_power_next_expiration); 65``` 66 67### Input parameters 68 69- *tx_low_power_next_expiration* - the number of ticks to configure the low power timer. 70 71### Return values 72 73- *none* 74 75**TX_LOW_POWER_TIMER_SETUP** is a macro invoking user-defined function that sets up a low power timer. To set up a low power timer or operate ticklessly in low power mode, this symbol must be defined. This macro is called in ```tx_low_power_enter```. If **TX_LOW_POWER_TICKLESS** is not defined and there are no timers active, the *tx_low_power_next_expiration* parameter will be set to 0xFFFFFFFF. 76 77> Note: The number of ThreadX ticks is the input to this function. The frequency of a ThreadX timer tick is defined in **TX_TIMER_TICKS_PER_SECOND** (typically defined in file tx_api.h, tx_user.h, or tx_port.h). 78 79> Note: do not put the processor to sleep in this macro. 80 81### Optional Define 82 83- **TX_LOW_POWER_TICKLESS** - an optional define to operate ticklessly in low power mode only if no ThreadX timers are active. With symbol **TX_LOW_POWER_TICKLESS** defined, if there are no ThreadX timers active, **TX_LOW_POWER_TIMER_SETUP** will not be called in ```tx_low_power_enter```. ThreadX will not maintain/update the internal tick count during or after exiting low power mode. Symbol **TX_LOW_POWER_TIMER_SETUP** must also be defined if defining **TX_LOW_POWER_TICKLESS**. 84 85### Example 86 87```c 88/* Low power timer function prototype. */ 89void low_power_timer_config(ULONG ticks); 90 91/* Define the TX_LOW_POWER_TIMER_SETUP macro. */ 92#define TX_LOW_POWER_TIMER_SETUP low_power_timer_config 93 94void low_power_timer_config(ULONG ticks) 95{ 96 /* Insert code here to configure a hardware timer 97 to wake the processor from sleep after 98 ticks/TX_TIMER_TICKS_PER_SECOND seconds. */ 99} 100``` 101 102--- 103 104### TX_LOW_POWER_USER_ENTER 105A macro invoking a user-defined function that configures the processor for entering low power mode (e.g. turn off peripherals and select a sleep mode). This macro is called in ```tx_low_power_enter```. 106 107### Input parameters 108 109- *none* 110 111### Return values 112 113- *none* 114 115### Example 116 117```c 118/* Low power enter function prototype. */ 119void low_power_enter(void); 120 121/* Define the TX_LOW_POWER_USER_ENTER macro. */ 122#define TX_LOW_POWER_USER_ENTER low_power_enter 123 124void low_power_enter(void) 125{ 126 /* Insert code here to configure the processor to enter low power mode. */ 127} 128``` 129--- 130 131### TX_LOW_POWER_USER_EXIT 132A macro invoking a user-defined function that configures the processor for exiting low power mode (e.g. turn on peripherals). This is called in ```tx_low_power_exit```. 133 134### Input parameters 135 136- *none* 137 138### Return values 139 140- *none* 141 142### Example 143 144```c 145/* Low power exit function prototype. */ 146void low_power_exit(void); 147 148/* Define the TX_LOW_POWER_USER_EXIT macro. */ 149#define TX_LOW_POWER_USER_EXIT low_power_exit 150 151void low_power_exit(void) 152{ 153 /* Insert code here to configure the processor to exit low power mode. */ 154} 155``` 156 157--- 158 159### TX_LOW_POWER_USER_TIMER_ADJUST 160 161```c 162ULONG TX_LOW_POWER_USER_TIMER_ADJUST(VOID); 163``` 164 165A macro invoking a user-defined function to determine how much time has elapsed while in low power mode (in units of ThreadX ticks). This is called in ```tx_low_power_exit``` and returns the number of ticks needed to adjust the ThreadX timers. 166 167When exiting low power mode, there are two possibilities: 168 1. The processor slept for the entire time the timer was configured to sleep. 169 2. The processor was awakened early. 170 171### Input parameters 172 173- *none* 174 175### Return values 176 177- *tx_low_power_adjust_ticks* 178 179### Example 180 181```c 182/* Low power timer adjust function prototype. */ 183ULONG low_power_timer_adjust(void); 184 185/* Define the TX_LOW_POWER_USER_TIMER_ADJUST macro. */ 186#define TX_LOW_POWER_USER_TIMER_ADJUST low_power_timer_adjust 187 188ULONG low_power_timer_adjust(void) 189{ 190 ULONG actual_ticks_slept; 191 ULONG elapsed_time_in_ms; 192 193 /* Insert code here to read timer registers to determine 194 how long the processor actually slept. */ 195 elapsed_time_in_ms = read_timer_register(); 196 197 /* Convert elapsed time to ThreadX ticks. */ 198 actual_ticks_slept = elapsed_time_in_ms / (1000/TX_TIMER_TICKS_PER_SECOND); 199 200 return(actual_ticks_slept); 201} 202``` 203 204--- 205 206## Summary of Low Power APIs 207 208- ```tx_low_power_enter``` - *Enter low power mode* 209- ```tx_low_power_exit``` - *Exit low power mode* 210- ```tx_time_increment``` - *Increment ThreadX timers by specific amount* 211- ```tx_timer_get_next``` - *Get next ThreadX timer expiration* 212 213--- 214 215## tx_low_power_enter 216 217Enter low power mode. 218 219### Prototype 220 221```c 222VOID tx_low_power_enter(VOID); 223``` 224 225### Description 226 227This service enters low power mode. The macros **TX_LOW_POWER_TIMER_SETUP** and **TX_LOW_POWER_USER_ENTER** are called in this function to allow the user to configure a low power timer and configure the hardware for low power mode. 228 229For keeping track of time while in low power mode, there are two possibilities: 230 2311. A ThreadX timer is active. Function ```tx_timer_get_next``` returns **TX_TRUE**. Note that in this situation, a low power clock must be used in order to wake up the CPU for the next ThreadX timer expiration. Therefore a low power timer/clock must be programmed. Program the hardware timer source such that the next timer interrupt is equal to: *tx_low_power_next_expiration \* tick_frequency*. The *tick_frequency* is application-specific and typically set up in ```tx_low_level_initialize```. 232 2332. There are no ThreadX timers active. Function ```tx_timer_get_next``` returns *TX_FALSE*. 234 1. The application may choose **not** to keep the ThreadX internal 235 tick count updated (define **TX_LOW_POWER_TICKLESS**), therefore there is no need to set up a low power clock. 236 2. The application still needs to keep the ThreadX tick up-to-date. In this case a low power clock needs to be configured. 237 238### Input parameters 239 240- *none* 241 242### Return values 243 244- *none* 245 246### Allowed from 247 248Internal ThreadX code, application 249 250### Example 251 252ARM Cortex-M assembly 253```c 254#ifdef TX_LOW_POWER 255 PUSH {r0-r3} 256 BL tx_low_power_enter // Enter low power mode 257 POP {r0-r3} 258#endif 259 260#ifdef TX_ENABLE_WFI 261 DSB // Ensure no outstanding memory transactions 262 WFI // Wait for interrupt 263 ISB // Ensure pipeline is flushed 264#endif 265 266#ifdef TX_LOW_POWER 267 PUSH {r0-r3} 268 BL tx_low_power_exit // Exit low power mode 269 POP {r0-r3} 270#endif 271``` 272### See also 273 274- tx_low_power_exit 275 276--- 277 278## tx_low_power_exit 279 280Exit low power mode. 281 282### Prototype 283 284```c 285VOID tx_low_power_exit(VOID); 286 287``` 288 289### Description 290 291This service exits low power mode. Macro **TX_LOW_POWER_USER_EXIT** is called in this function to allow the user to configure the hardware to exit low power mode. Macro **TX_LOW_POWER_USER_TIMER_ADJUST** is called in this function to determine how long the processor actually slept. 292 293### Input parameters 294 295- *none* 296 297### Return values 298 299- *none* 300 301### Allowed from 302 303Internal ThreadX code, application 304 305### Example 306 307```c 308#ifdef TX_LOW_POWER 309 PUSH {r0-r3} 310 BL tx_low_power_enter // Enter low power mode 311 POP {r0-r3} 312#endif 313 314#ifdef TX_ENABLE_WFI 315 DSB // Ensure no outstanding memory transactions 316 WFI // Wait for interrupt 317 ISB // Ensure pipeline is flushed 318#endif 319 320#ifdef TX_LOW_POWER 321 PUSH {r0-r3} 322 BL tx_low_power_exit // Exit low power mode 323 POP {r0-r3} 324#endif 325``` 326 327### See also 328 329- tx_low_power_enter 330 331--- 332 333## tx_time_increment 334 335This function increments the current time by a specified value. The value was derived by the application by calling the ```tx_timer_get_next``` function prior to this call, which was right before the processor was put in low power mode. 336 337### Prototype 338 339```c 340VOID tx_time_increment(ULONG time_increment); 341``` 342 343### Description 344 345This function increments the current time by a specified value. The value was derived by the application by calling the ```tx_timer_get_next``` function prior to this call, which was right before the processor was put in low power mode. 346 347### Input parameters 348 349- *time_increment* - Number of ThreadX ticks to increment time and timers. 350 351### Return values 352 353- *none* 354 355### Allowed from 356 357Internal ThreadX code, application 358 359### Example 360 361From ```tx_low_power_exit```: 362 363```c 364 /* Call the low-power timer driver code to obtain the amount of time (in ticks) 365 the system has been in low power mode. */ 366#ifdef TX_LOW_POWER_TIMER_ADJUST 367 tx_low_power_adjust_ticks = TX_LOW_POWER_USER_TIMER_ADJUST; 368#else 369 tx_low_power_adjust_ticks = (ULONG) 0; 370#endif 371 372 /* Determine if the ThreadX timer needs incrementing. */ 373 if (tx_low_power_adjust_ticks) 374 { 375 /* Yes, the ThreadX time must be incremented. */ 376 tx_time_increment(tx_low_power_adjust_ticks); 377 } 378``` 379 380### See also 381 382- tx_timer_get_next 383 384--- 385 386## tx_timer_get_next 387 388Get next ThreadX timer expiration 389 390### Prototype 391 392```c 393ULONG tx_timer_get_next(ULONG *next_timer_tick_ptr); 394``` 395 396### Description 397 398This service gets the next ThreadX timer expiration, in ticks. 399 400### Input parameters 401 402- *next_timer_tick_ptr* - pointer to hold number of ticks 403 404### Return values 405 406- *TX_TRUE* (1) At least one timer is active. 407- *TX_FALSE* (0) No timers are currently active. 408 409### Allowed from 410 411Internal ThreadX code, application 412 413### Example 414 415From ```tx_low_power_enter```: 416 417```c 418ULONG tx_low_power_next_expiration; /* The next timer expiration (units of ThreadX timer ticks). */ 419ULONG timers_active; 420 421 /* At this point, we want to enter low power mode, since nothing 422 meaningful is going on in the system. However, in order to keep 423 the ThreadX timer services accurate, we must first determine the 424 next ThreadX timer expiration in terms of ticks. This is 425 accomplished via the tx_timer_get_next API. */ 426 timers_active = tx_timer_get_next(&tx_low_power_next_expiration); 427``` 428 429### See also 430 431- tx_time_increment 432