Replacing busy loops with sleep mode

The reason busy loops are very popular among hobbyists is that they are so easy to implement. Suppose that the system needs to wait for a digital input to switch to a low-logic state, and this input is mapped to a certain GPIO. This can be easily done with the following one-liner:

while((GPIOX_IDR & (1 << INPUT_PINX)) != 0)
;

While this is perfectly working as expected, it will force the CPU in a loop of fetch-decode-execute, and jumping around the same few instructions until the condition becomes false. As we have seen, the power used by the microcontroller depends mostly on how fast the CPU is running. A lower frequency corresponds to a smaller amount of power used per instruction. Executing instructions in an infinite loop without switching to low-power mode sets the power demand from the CPU at its highest value for a measurable amount of time, in this case, all the time needed for the logic input to change state.

Actively polling a value is the only way to go if interrupts are not enabled. The examples contained in this book tend to guide towards a proper interrupt-handling approach. The proper way to handle the wait for the logic switch foresees instead the activation of an interrupt line related to the next operation. In the case of a GPIO line, we can use external interrupt triggers to wake up the main loop when the condition is met, and switch to a low-power mode, instead of looping, while waiting for the event.

In many other cases, the temptation of implementing loops like the previous one could be avoided by investigating another way to access the peripheral that is currently holding the system from the next execution step. Modern serial and network controllers are equipped with interrupt signals, and when those are not available for the hardware we are accessing, there is always another way to sense an event through an external interrupt line. When a device can really exclusively function in polling mode, as a last resort, the polling frequency can be reduced by associating the action to a timer interrupt, which would allow polling a few times per second, or even once in a while, using intervals that are more in line with the actual peripheral speed. Executing timed operations allows the CPU to sleep in between, and to switch to a low-power mode, reducing the average energy that the CPU would have used while busy-looping.

The exception to this rule, seen many times in this chapter, is waiting for a ready flag after activating a system component. The following code activates the internal low-speed oscillator, and it is used in the standby mode example before entering the low-speed mode. The CSR register is polled until the low-speed oscillator is actually running:

RCC_CSR |= RCC_CSR_LSION;
while (!(RCC_CSR & RCC_CSR_LSIRDY))
;

Operations like this, performed on the integrated peripherals in the microcontroller silicon, have a well-known latency of a few CPU clocks, and thus do not impact the real-time constraints, as the maximum latency for similar internal actions is often mentioned in the microcontroller documentation. The situation changes whenever the polling occurs on a less predictable register, whose state and reaction times may depend on external factors, and long busy loops may occur in the system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.26.176