The basics of low-power programming on the Cortex-M0 - Embedded.com

The basics of low-power programming on the Cortex-M0

The ARM Cortex-M0 processor has been designed to provide low-power advantages over other processors. In this article I will discuss how some of these features can be used to advantage in programming for this architecture.

Cortex-M0 sleep modes
The Cortex-MO processor supports normal sleep and deep sleep modes. The sleep modes can be entered using WFE or WF1 instructions, or using Sleep-on-Exit feature (Figure 17.1 below ).

Figure 17.1: Normal sleep and deep sleep can both be entered using various methods.
The actual differences between normal sleep mode and deep sleep mode on a microcontroller depend on the system level design of the chip. For example, normal sleep might result in some of the clock signals being switched off, whereas deep sleep might also reduce voltage supplies to the memory blocks and might switch off additionl components in the system.

After entering sleep mode, the processor can be awakened using interrupt requests, debug requests, events, and reset. Figure 17.2 below summarizes the wakeup conditions for interrupt requests.

Figure 17.2: Wakeup conditions for interrupt requests.
In the System Control Block of the Cortex-MO processor, there is a programmable register called the System Control Register (SCR; Table 17.1 below ). This register contains several control bits related to sleep features.

Table 17.1: System Control Register (OxEOOOED10)
For the users of CMSIS-compliant device driver library, the System Control Register can be accessed by the register symbol “SCB->SCR.” For example, to enable deep sleep mode, you can use

SCB->SCR | = 1<<2; /* Enable deep sleep feature */

The System Control Register must be accessed using a word-size transfer.

Using WFE and WFI in Programming
In most cases, the device driver libraries from microcontroller vendors contain functions to enter low-power modes that are customized for their microcontrollers.

Using these functions will help you to achieve the best level of power optimization for your microcontrollers. However, if you are developing C code that needs to be portable between multiple Cortex-M microcontrollers, you can use the CMSIS functions shown in Table 17.2 below to access the WFE and WFI instructions directly.

Table 17.2: CMSIS Intrinsic Functions for WFE/WFI Instructions
For users who are not using CMSIS-compliant device drivers, you can use intrinsic functions provided by the C compiler or inline assembly to generate WFE and WFI instructions.

In these cases, the software code will be tool chain dependent and less portable. For example, the ARM RealView Development Suite or Keil MDK provides the following C intrinsic functions (as shown in Table 17.3 below , where unlike the CMSIS version, they are in lowercase letters).

Table 17.3: ARM RealView Compiler or Keil MDK Intrinsic Functions for WFI and WFE
Because the WFE can be awakened by various sources of events, including past events, it is usually used in an idle loop. For example,

while (proceesinq required()==0) {
   _wfe();
   }

Users of assembly programming environments can use WFE and WFI directly in their assembly codes.

Using the Send-Event-on-Feed Feature
The Send-Even t-on-Pend feature allows any interrupts (including disabled ones ) to wake up the processor if the processor entered sleep by executing the WFE instruction.

When the SEVONPEND bit in the System Control Register is set, an interrupt switching from inactive state to pending state generates an event, which wakes up the processor from WFE sleep.

If the pending status of an interrupt was already set before the processor entered the sleep state, a new request from this interrupt during WFE sleep will not wake up the processor.

For users of CMSIS-compliant device driver libraries, the Send-Event-on-Pend feature can be enabled by setting bit 4 in the System Control Register. For example, you can use

SCB->SCR |- 1<<4; /* Enable Send-Event-on-Send feature */

If you are not using a CMSIS-compliant device driver library, you can use the following C code to carry out the same operation:

#define SCB SCR (* ((volatile unsigned long*) (OxEOOOEDl0)))
/* Set SEVONPEND bit in System Control Register * /
SCB_SCR | = 1<<4;

Users of assembly language can enable this feature by using the following assembly code:

LDR     r0, =OxEOOOED10; System Control Register address
LDR     rl, [r0]
MOVS    r2, #0x10; Set SEVONPEND bit
ORR     r1, r2
STR     rl, [r0]

Using the Sleep-on-Exit Feature
The Sleep-on-Exit feature is ideal for interrupt-driven applications. When it is enabled, the processor can enter sleep as soon as it completes an exception handler and returns to Thread mode.

It does not cause the processor to enter sleep if the exception handler is returning to another exception handler (nested interrupt). By using Sleep-on-Exit, the microcontroller can stay in sleep mode as much as possible (Figure 17.3 below ).

Figure 17.3: Sleep-on-Exit feature.
When the Cortex-MO enters sleep using the Sleep-on-Exit feature, it is just like executing WFI immediately after the exception exit.

However, the unstacking process is not carried out because the registers will have to be pushed onto the stack at the next exception entry.

The Sleep-on-Exit feature reduces the power consumption of the system (1) by avoiding unnecessary program execution in thread in interrupt-driven applications and (2) by reducing unnecessary stack push and pop operations.

When the processor is awakened by a halt debug request, then the unstacking process will be carried out automatically. When the Sleep-on-Exit feature is used, the WIFE or WFI instruction is normally placed in an idle loop:

SCB-> SCR= SCB|0x2;// Enable S1eep-on-exit feature
while (1){
  _WFI();// Execute WFI and enter sleep
   }
;

The loop is required because if the processor is awakened by a halt debug request, the instruction after the WFI (branch back to WFI loop) would be executed when the processor is unhalted after debugging.

If you are not using a CMSIS-compliant device driver, you can use the following C code to enable the Sleep-on-Exit feature:

#define SCB_SCR (*((volatile unsigned long *)(0xE000ED10)))
/* Set SLEEPONEXIT bit in System Control Register */
SCB_SCR = SCB_SCR | 0x2;

Users of assembly language can enable this feature using the following assembly code:

LDR     r0, =0xE000ED10; System Control Register address
LDR     r1, [r0]
MOVS    r2, #0x2
ORR     r1, r2; Set SLEEPONEXIT bit
STR     r1, [r0]

In interrupt-driven applications, do not enable the Sleep-on-Exit feature too early during the initialization. Otherwise if the processor receives an interrupt request during the initialization process, it will enter sleep automatically after the interrupt handler is executed, before the rest of the initialization process completes.

Wakeup Interrupt Controller (WIC) Feature
The Wakeup Interrupt Controller (WIC) is an optional component that microcontroller vendors can use to mirror the wakeup decision functionality of the NVIC when all the processor clocks have stopped during deep sleep.

This feature also allows the processor to be put into an ultralow-power state and still be able to be awakened by an interrupt almost instantly. The WIC was first introduced in the Cortex-M3 revision two (r2p0).

The same feature was also made available in the Cortex-MO and Cortex-M4 processors. The presence of WIC does not require extra programmable registers.

However, the use of the WIC usually requires a system-level power management unit (PMU), which would have device-specific programmable registers. In general, the presence of the WIC feature is usually transparent to the software.

The WIC is used only when the processor enters deep sleep. To use the WIC feature, the following steps are required:

• Enable PMU (device specific)
• Enable deep sleep feature in the System Control Register
• Enter sleep

When WIC is enabled and the processor enters deep sleep, the sequence shown in Figure 17.4 below will occur.

Figure 17.4: WIC operation sequence
Because the task of detecting and masking interrupts for wakeup is offloaded to the WIC, the Cortex-MO processor can remain in a low-power state and does not require any clocks.

To reduce the power consumption further, microcontrollers can use a special silicon technology called state retention power gating (SRPG) to power down most part of the processor logic, leaving only a small portion of circuit within each register to hold the current status.

This allows the leakage current of the design to be further lowered. Currently the SRPG is only supported in a limited numbers of silicon technology processes (cell libraries).

The use of WIC does not require a special programming step apart from configuring the device-specific PMU and enabling deep sleep. However, it can result in the SysTick timer being disabled during deep sleep.

If your application uses an embedded OS and requires the OS task scheduler to continue to operate during sleep, you might need to do one of the following:

• Enabled a separate timer that is not affected by deep sleep to wake up the processor at a scheduled time.

• Disable the WIC feature.

• Avoid using deep sleep and use normal sleep instead.

Event Communication Interface
One of the wakeup sources for the WFE sleep operation is the external event signal (here the word "external" refers to the processor boundary; the source generating the event can be on chip or off chip).

The event signal could be generated by on-chip peripherals or by another processor on the same chip. The event communication and WFE can be used together to reduce power in polling loops.

The Cortex-MO processor uses two signals for event communication:

Transmit Event (TXEV). A pulse is generated when the SEV instruction is executed.

Receive Event (RXEV) .When a pulse is received on this signal, the event latch inside the processor will be set and can cause the processor to wake up from WFE sleep operation.

First, we look at a simple use of the event connection in a single processor system: the event can be generated by a number of peripherals. A DMA controller is used in the example shown in Figure 17.5 below.


Figure 17.5: Use of the event interface: example 1-DMA controller.
In a microcontroller system, a memory block copying process can be accelerated using a DMA controller. If a polling loop is used to determine the DMA status, this will waste energy, consume memory bandwidth, and might end up slowing down the DMA operation.

To save energy, we put the processor into the WFE sleep state. When the DMA operation completes, we can then use a "Done" status signal to wake up the processor and continue program execution.

In the application code, instead of using a simple polling loop that continuously monitors the status of the DMA controller, the polling loop can include a WFE instruction as follows:

Enable_DMA_event_mask(); // Write to programmable enable mask register
                         // to enable DMA event
Start_DMA(); // Start DMA operation
do {
  __WFE(); // WFE Sleep operation, wake up when an event is received
} while (check_DMA_completed()==0);
Disable_DMA_event_mask(); // Write to programmable enable mask register
                         // to disable DMA event

Because the processor could be awakened by other events, the polling loop must still check the DMA controller status.

For applications using an embedded OS, an OS-specific delay function should be used instead of the WFE to allow the processor to switch to another task.

In multiprocessor systems, interprocessor communication such as spin lock often involves polling software flags in shared memory. Similar to the DMA controller example, the WFE sleep operation can be used to reduce power consumption during these activities.

In a dual processor system, the event communication interface can be connected in a crossover configuration as shown in Figure 17.6 below.


Figure 17.6: Use of the event interface: example 2-dual processor event crossover.
In this arrangement, the polling loop for a shared software flag could be written as

do {
  __WFE(); // WFE Sleep operation, wake up when an event is received} while (sw_flag_x¼¼0); // poll software flag
task_X(); // execute task X when software flag for task X is received

For the other process that changes "sw flag x," it needs to generate an event after the shared variable is updated. This can be done by executing the SEV (Send event) instruction:

sw_flag_x = 1; // Set software flag in shared memory
__DSB(); // Data synchronization barrier to ensure the write is completed
        // not essential for Cortex-M0 but is added for software porting
__SEV(); // execute SEV instruction

Using this arrangement, the processor running the polling loop can stay in sleep mode until it receives an event. Because the SEV execution sets the internal event latch, this method works even if the polling process and the process that sets the software variable are running at different times on the same processor, as in a single processor multitasking system.

For applications that use an embedded OS, an OS-specific event passing mechanism should be used instead of directly using WFE and SEV.

Some tips on developing low power apps
Most Cortex-M microcontrollers come with various low-power modes to help you reduce the power consumption as low as possible. Although these features are often linked to the lowpower features of the processor, each microcontroller product provides different low-power control methods and low-power characteristics.

Therefore, it is not possible to cover every method for all the different product types. Here we will only cover some general information about how to reduce power on typical embedded systems.

In general, as shown below, various measures can be taken to reduce power consumption.

Reduction of active power 

1. Choose the right microcontroller device. Once the basic system and memory size requirements of the project are clear, you can select a microcontroller with enough memory and peripherals but not too much more.

2. Run the processor at suitable clock frequency. Many applications do not require a high clock frequency. When a processor is running at high clock speed, it might require wait states because of flash memory access time and hence reduce the energy efficiency.

3. Choose the right clock source. Many low-power microcontrollers provide multiple clock sources including internal ones. Depending on the requirements of your applications, some clock sources might work better than others. There is no general rule of "best choice" for which clock source to use. It entirely depends on the application and the microcontroller you are using.

4. Do not enable a peripheral unless it is needed. Some low-power microcontrotlers allow you to turn off clock signals to each peripheral. In some cases, you can even turn off the power supply to a certain peripheral to reduce power.

5. Check out other clock .system features. Some microcontrollers provide various clock dividers for different parts of the system. You can use these dividers to reduce the power-for example, reduce the processor speed when the processing requirement is low.

6.Select a good power supply design. A good choice of power supply design can provide optimum voltage for the application.

Reduction of active cycles

1. When the processor is idle, the sleep mode can be used to reduce power consumption, even it is going to enter sleep for a short period of time.

2. Application code can be optimized for speed to reduce active cycles. In some cases (e.g., the C compiler option has been set to speed optimization), it might increase code size, but when there is spare space in the flash memory, then the optimization is worth trying.

3. Features like Sleep-on-Exit can be used to reduce active cycles in interrupt-driven applications.

Reduction of power during sleep

1. Select the right low-power features. A low-power microcontroller might support various low-power sleep modes. Using the right sleep modes might help you to reduce the power consumption significantly.

2. Turn off unneeded peripherals and clock signals during sleep. This can reduce the power consumption, but it might also increase the time required to restore the system to an operational state after exiting sleep mode.

3.Consider turning off some of the power. Some microcontrollers can even turn off the power supply to some parts inside the microcontroller like flash memory and oscillators. But doing this usually means it will take longer to wake up the system.

Most microcontroller vendors would provide code library and example code to demonstrate the low-power features of their microcontrollers. Those examples can make the application development much easier.

The first step to take when developing a low-power application into become familiar with the microcontroller device you are using. There are a few areas to investigate when developing sleep mode support code:

1) Determine which sleep mode should be used.
2) Determine which clock signals need to remain on.
3) Determine if some clock support circuits like crystal oscillators can be switched off.
4) Determine if clock source switching is needed.

A cautionary note
Be careful when developing applications with deep sleep mode or deep power down mode. In these two modes you could lose connectivity between the in-circuit debugger and the microcontroller.

If you power down the microcontroller soon after it starts running, you could end up being unable to connect the debugger to the microcontroller to carry out debug operations. This also affects flash programming. There are various solutions to this problem:

1 .During software development you could add conditional executed code at the initialization stage so that you can switch a pin at reset to disable the deep sleep or power-down operation. This conditional executed code could be removed from the project later on once you are sure that the power management code is working correctly.

2. Depending on the microcontroller product, there can be a special boot mode to disable the execution of the application programmed in the flash memory.

For example, in the NXP LPC111x, port 0 bit 1 can be used in such situation. The NXP111x has an in-system programming (ISP) feature to allow the flash to be programmed using the boot loader and the serial port.

By pulling bit 1 of port 0 to low at power up reset, the ISP program in the boot loader will be executed. You can use the ISP feature to update the flash or to connect the in-circuit debugger to the microcontroller and update the flash.

Finally, when a debugger is connected to a system, in some microcontrollers the system design might automatically disable some of the low-power optimizations to allow the debug operation to be performed correctly.

Therefore, when trying to measure the power consumption of the system, you might need to disconnect the microcontroller system from the debugger.

In some cases, the debugger needs to be disconnected from the system before powering up the microcontroller to minimize the power consumption, because the effect of a debug connection to the power management circuit might retain until the power supply has been disconnected.

Joseph Yiu, author of “The definitive guide to the ARM Cortex-M0,” is a staffengineer at ARM Ltd., Cambridge,UK.

Used with permission from Newnes, a division of Elsevier.Copyright 2011, from “The definitive guide to the ARM Cortex-M0,"by Joseph Yiu. For more information about this title and other similar books,please visit www.elsevierdirect.com.

1 thought on “The basics of low-power programming on the Cortex-M0

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.