Posts in this project
Pallet Tracker - 01 - Project description
Pallet Tracker - 02 - Development environment
Pallet Tracker - 03 - Application skeleton
Pallet Tracker - 04 - PSoC6 power modes and LPComp
Pallet Tracker - 05 - Evaluating power consumption
Pallet Tracker - 06 - Indoor localization
As first step, I will get in depth in the PSoC6 power modes and see which low power mode is most suitable for this application
PSoC6 low power modes
Let's have a quick overview of the PSoC6 internal architecture. Here is a diagram with all the integrated peripherals and buses
There are two Arm Cortex CPUs:
- The Cortex-M4 (CM4) has single-cycle multiply, a floating-point unit (FPU), and a memory protection unit (MPU). It can run at up to 150 MHz. This is the main CPU, designed for a short interrupt response time, high code density, and high throughput.
- The Cortex-M0+ (CM0+) has single-cycle multiply, and an MPU. It can run at up to 100 MHz; however, for CM4 speeds above 100 MHz, CM0+ and bus peripherals are limited to half the speed of CM4. Thus, for CM4 running at 150 MHz, CM0+ and peripherals are limited to 75 MHz. CM0+ is the secondary CPU; it is used to implement system calls and device-level security, safety, and protection features. CM0+ provides a secured, uninterruptible boot function. This guarantees that post boot, system integrity is checked and memory and peripheral access privileges are enforced.
The CPUs can be selectively placed in their Sleep and Deep Sleep power modes as defined by Arm.
The PSoC 6 MCU can operate in four system and three CPU power modes. These modes are intended to minimize the average power consumption in an application. The power modes supported by PSoC 6 MCUs, in the order of decreasing power consumption, are:
- System Low Power (LP) – All peripherals and CPU power modes are available at maximum speed and current. In this mode,
All resources are available with maximum power and speed
All CPU power modes supported
- System Ultra Low Power (ULP) – All peripherals and CPU power modes are available, but with limited speed and current. In this mode,
- All blocks are available, but the core voltage is lowered resulting in reduced clock frequencies
- All CPU power modes supported
- CPU Active – CPU is executing code in system LP or ULP mode. In this mode,
- Normal CPU code execution
- Available in system LP and ULP power modes
- CPU Sleep – CPU code execution is halted in system LP or ULP mode. In this mode,
- CPU halts code execution
- Available in system LP and ULP power modes
- CPU Deep Sleep – CPU code execution is halted and system deep sleep is requested while in system LP or ULP mode. In this mode,
- CPU halts code execution
- Requests system deep sleep entry
- Available in system LP and ULP power modes
- System Deep Sleep – Entered only after both CPUs enter CPU Deep Sleep mode. Only low-frequency peripherals are available. In this mode,
- Occurs when all CPUs are in CPU deep sleep
- CPUs, most peripherals, and high-frequency clocks are OFF
- Low-frequency clock is ON
- Low-power analog and some digital peripherals are available for operation and as wakeup sources
- SRAM is retained
- System Hibernate – Device and I/O states are frozen and the device resets on wakeup. In this mode,
- CPUs and clocks are OFF
- GPIO output states are frozen
- Low-power comparator, RTC alarm, and dedicated WAKEUP pins are available to wake up the system
- Backup domain is available
- SRAM is not retained
CPU Active, Sleep, and Deep Sleep are standard Arm-defined power modes supported by the Arm CPU instruction set architecture (ISA). System LP, ULP, Deep Sleep and Hibernate modes are additional low-power modes supported by PSoC 6. Hibernate mode is the lowest power mode in the PSoC 6 MCU and on wakeup, the CPU and all peripherals go through a reset.
According to the datasheet, CM0+ draws less current than the CM4+
Since this application is not going to implement complex algorithm, it would nice if I could use such a CPU and disable the CM4+. However, the datasheet states that CM0+ is the secondary CPU, so I suspect it's not possible to run code in CM0+ only. This is confirmed by the fact that all the examples provided use CM4+ to run application code.
The other things to note are
- I can run in ULP mode, which reduces power consumption by scaling down clock frequency
- the LPComp (Low-power comparator) is one of the few peripherals that are active in Hibernate mode, and can be used to wake up the PSoC6
The comparator supports three operation modes that affect its speed and power:
- Ultra-low-power/Slow: ICMP1 = 0.85 µA (SID259) – Slows the response time to 20 µs (SID92). Use this mode when in system deep sleep or hibernate only.
- Low-power/Low: ICMP2 = 10 µA (SID248) – Preferred mode when system deep sleep or hibernate are not required and the slower response time of 1 µs (SID258) is acceptable. This increases the input offset voltage to 25 mV (SID85A).
- Normal Power/Fast: ICMP1 = 150 µA (SID89) – Use it when the fastest response time of 100 ns (SID91) and/or a low offset voltage of 10 mV (SID84) are required.
Another option to reduce the amount of current consumed by the comparator is to disable hysteresis. Hysteresis can be disabled in the ModusToolbox software configurator, or PDL configuration structure.
Hardware connections
According to power reduction techniques, if the low-power comparator requires pin connections and system deep sleep operation, always choose the dedicated pin connections to the comparator. This allows the comparator to work in system deep sleep and avoid using the global analog muxes, which consume additional current to stay active.
Looking at the datasheet, this is the internal connections of the LPComp
On the back of the evaluation kit, there is a table with the pin assignments
According to this table, pin 5.6 and 5.7 (used by LPComp1) are connected to pin D6 and D7 of the connectors on the front of the board. So I can use these two pins and LPComp1 for my project
Because most of the time the pallet is on the floor or on a shelf (and not, as an example, lifted up by a forkilft), it's a good idea to limit the current consumption is such condition. My first design idea was to use a Force Sensing Resistor (FSR) to detect when the pallet is lifted up. However, a FSR's resistance diminishes when a force is applied, as shown in diagram below
This means that the maximum current would flow just when I want to save energy (i.e. when the pallet is resting on the floor or on a shelf). So I moved to a simpler solution: a normally-closed switch. With a switch, you are completely cutting the circuit, so no current will circulate.
When the pallet is on the floor, the switch is open and there will virtually no current flowing (the current flows through the 100k resistor in series with the very-high opamp input resistor)
When the pallet is lifted up by a forklift, then the switch closes and pin is pulled down to ground. Here we have a limited current flowing through the 100k resistor, but this condition should last significantly less the the other condition.
Sample application
With these considerations in mind, I can write a small test application to make some preliminary analysis about expected power consumption
The test application is quite simple
First, it configures the LPComp
/* Enable the whole LPComp block */ Cy_LPComp_GlobalEnable(LPCOMP); /* Configure LPComp output mode and hysteresis for channel 0 */ Cy_LPComp_Init(LPCOMP, CY_LPCOMP_CHANNEL_0, &myLPCompConfig); /* Enable the local reference voltage */ Cy_LPComp_UlpReferenceEnable(LPCOMP); /* Set the local reference voltage to the negative terminal and set a GPIO input on the positive terminal for the wake up signal */ Cy_LPComp_SetInputs(LPCOMP, CY_LPCOMP_CHANNEL_0, CY_LPCOMP_SW_GPIO, CY_LPCOMP_SW_LOCAL_VREF); /* Set channel 0 power mode - Ultra Low Power mode */ Cy_LPComp_SetPower(LPCOMP, CY_LPCOMP_CHANNEL_0, CY_LPCOMP_MODE_ULP); /* It needs 50us start-up time to settle in ULP mode after the block is enabled */ Cy_SysLib_DelayUs(MY_LPCOMP_ULP_SETTLE);
When exiting the Hibernate mode, the CPU is reset both GPIO are frozen in order to maintain their status and avoid glitches. So we need to check if GPIO are currently frozen and, if this is the case, we can unfreeze in order to be able to operate on the GPIOs
/* Check the IO status. If current status is frozen, unfreeze the system. */ if(Cy_SysPm_GetIoFreezeStatus()) { /* Unfreeze the system */ Cy_SysPm_IoUnfreeze(); }
Finally, we can execute the application loop
for(;;) { /* If the comparison result is high, toggles LED every 500ms */ if(Cy_LPComp_GetCompare(LPCOMP, CY_LPCOMP_CHANNEL_0) == MY_LPCOMP_OUTPUT_HIGH) { /* Toggle LED every 500ms */ Cy_GPIO_Inv(LED_0_PORT, LED_0_NUM); Cy_SysLib_Delay(TOGGLE_LED_PERIOD); } /* If the comparison result is low, goes to the hibernate mode */ else { /* System wakes up when LPComp channel 0 output is high */ /* Turn on LED for 2 seconds to indicate the hibernate mode. */ Cy_GPIO_Write(LED_0_PORT, LED_0_NUM, LED_ON); Cy_SysLib_Delay(LED_ON_2S_BEFORE_HIB); Cy_GPIO_Write(LED_0_PORT, LED_0_NUM, LED_OFF); /* Set the wake-up signal from Hibernate */ Cy_SysPm_SetHibWakeupSource(CY_SYSPM_LPCOMP0_HIGH); /* Jump into Hibernate */ Cy_SysPm_Hibernate(); } }
Here is a video that shows a system prototype at work. The board is doing all the basic tasks that needs to be implemented, namely
- in hibernate mode, waits for the LPComp to wake up the system (meaning that the pallet has been lifted up or put back on the floor)
- scans for wifi networks
- sends data about wifi networks and RSSI to a server
- goes back to hibernate mode
In the next post, I will make some power consumption analysis and I will try to optimize energy usage