This document describes the creation of the Low power demo application (Low power demo application on FRDM-KL03Z board ) in KDS 2.0.0 with latest version of KSDK 1.1.0. It is an update of the previous document because the KSDK 1.1.0 implementation brings new features that makes design of a low power demo application more complicated. This document describes the creation of the following low power demo application: When the application starts the green LED blink one time, The RTC device alarm is set to 15 second (external oscillator 32768Hz is used) to wakeup CPU and the CPU enters the VLLS1 mode (VLLS0 mode cannot be used with external oscillator). The CPU wake up is possible by the following ways: - When you push the SW2 button the processor is woken and the green LED start blinking (5 times). - When you short the pin PTB6 to ground 5 times (the pin is available on the 8 pin header connector – pin number 4; you can for example connect a button to the pin number 4 and ground) the processor is woken and the green LED start blinking (5 times). - When selected RTC timeout expired (15 seconds) the processor is woken by the alarm interrupt and the green LED start blinking (5 times). The application is initialized again and recovery from the VLLS1 mode is executed. The alarm is set again to 15 second and the CPU enters the VLLS1 mode again. Preparation First of all the KDS 2.0.0 and KSDK 1.1.0 must be installed. You can find instructions in the document How to install Kinetis SDK 1.1.0 support in KDS 2.0.0. New project When you properly install and update all the software you are prepared to create the Low power demo application. Create a new Kinetis design Studio project: Select the FRDM-KL03Z board Select the Kinetis SDK path to the KSDK 1.1.0 and select Processor Expert The application is created and there are not any warnings reported in the Problems window. But there is another issue. The fsl_os_abstraction component in the OSs group is added into application (it was not in the KSDK 1.0.0) and it allocated LPTMR device in the inherited fsl_lptmr_hal component: The only solution of this conflict is removal of this component (the low power demo needn’t any OS; it is a simple application only). But this component is used by fsl_clock_manager and the fsl_clock_manager is used by PinSettings componnet. So you must remove all these component ( fsl_os_abstraction, fsl_clock_manager, PinSettings). When the PinSettings is removed from the project all signal names are also removed and you must select pins in the Cpu component again: The PinSettings component must be replaced by Init_GPIO component that allows settings of GPIO pins including routing and electrical properties. Add the Init_GPIO component into the project and set following properties (switch to Advance view): Select Device - GPIOB Set Settings/Clock Gate to Enabled. Set Settings/Pin 0 group to Initialize and select following properties of this pin (LLWU_P4): Pin Direction – Input Pull resistor – Enabled Pull selection - Pull Up Set Settings/Pin 6 group to Initialize and select following properties of this pin (LPTMR_ALT3): Pin Direction – Input Pull resistor – Enabled Pull selection - Pull Up Set Settings/Pin 11 group to Initialize and select following properties of this pin (PTB11 – GREEN LED): Pin Direction – Output Output value – 1 Set Pin selection/routing/Pin 11 to Enabled. The Pin 11 group is open and the PTB11 is selected as the Pin (GPIO functionality). These settings provide initialization code for routing of selected pins and also GPIO functionality for PTB11 that used for driving of the green LED of the RGB LED on the freedom board. There is also necessary to change the linker settings when you have installed the new version of GCC tools (according to the document How to install Kinetis SDK 1.1.0 support in KDS 2.0.0 - Additional Steps for Kinetis L family chapter) Open the context menu of the project, select Properties item and change the Other linker flags settings to “-specs=nano.specs -specs=nosys.specs”, in C/C++ Build / Settings, Tools Settigns tab, Cross ARM C++ Linker/Miscellaneous: Tip: If you want to know details of compiled code and the code size, you can use the following options to create extended list file and print code size info on the following Toolchains tab: You can generate Processor Expert code and process Build of the application without any error and warning. When the Build is finished the following information is provided in the Console window: 'Invoking: Cross ARM GNU Create Listing' arm-none-eabi-objdump --source --all-headers --demangle --line-numbers --wide "Low power demo KL03.elf" > "Low power demo KL03.lst" 'Finished building: Low power demo KL03.lst' ' ' 'Invoking: Cross ARM GNU Print Size' arm-none-eabi-size --format=berkeley "Low power demo KL03.elf" text data bss dec hex filename 1480 108 876 2464 9a0 Low power demo KL03.elf 'Finished building: Low power demo KL03.siz' ' ' Note: You can see that the memory footprint is quite small because all SDK component are removed. Routing of pins Routing of pins is provided by Init_GPIO and other components in the project. There will be used following pins: SW2 - ADC0_SE9/PTB0/IRQ_5/LLWU_P4/EXTRG_IN/SPI0_SCK/I2C0_SCL – input pin for the SW2 button on the board as LLWU wakeup pin GPIO pin – PTB6/IRQ_2/LPTMR0_ALT3/TPM1_CH1/TPM1_CLKIN1 – input pin of LPTMR device LED_GREEN - PTB11/TPM0_CH0/SPI0_MISO - output pin that driver the green LED of the RGB LED on the board Adding Processor Expert components Now you can add all components for the low power demo application. fsl_gpio_hal to control GPIO pins Init_LLWU and fsl_llwu_hal components to control LLWU device Init_SRTC and fsl_rtc_hal to control RTC device Init_LPTMR and fsl_lptmr_hal to control LPTMR device fsl_smc_hal to control SMC (System Mode Controller) device CPU device We are going to use external oscillator 32768Hz and we need to configure device to allow Very Low Leakage Stop modes. There we set following properties in the Component Inspector of the CPU (switch to Advance view): Check that the Clock settings/Clock Sources/System oscillator 0 is Enabled and set Enable in stop to Enabled. The Clock source, clock pins and clock frequency are preset for the FRDM-KL03Z board Go to the Clock configuration/Clock Configuration 0 and set: Internal reference clock/Slow IRC frequency to 2MHz (it is enough for our demo application and it also decrease power consumption). MCG lite settings/MCG mode set to LIRC_2M Very low power mode to Enabled (leave setting of VLP mode entry to User because the VLLS1 mode is entered after blinking; we will write the code to enter VLLS1 mode) System clocks/Core clock set to 0.5Mhz System clocks/Bus clock set to 0.5Mhz (it allow us to enter very low leakage stop modes) Set Low Power mode setings/Acknowledge isolation to Not allowed value (we will do it in the user code) GPIO pins Open the Component Inspector of fsl_gpio_hal componet, switch to Advance view and set following properties: Select Device - GPIOB LLWU (Low-Leakage Wakeup unit) device Open the Component Inspector of Init_LLWU, switch to Advance view and set following properties: Set Settings/External Source/Pin 4 to Any edge value (we will use this pin that is connected to SW2 button) Set Pins/Pin 4 to Enabled and select the Pin ADC0_SE9/PTB0/IRQ_5/LLWU_P4/EXTRG_IN/SPI0_SCK/I2C0_SCL in the item below Set Initialization/Utilize after reset values to no We will use the LLWU to wake-up the CPU and we need not any interrupt. RTC (Real Time Clock) device Open the Component Inspector of Init_SRTC, switch to Advance view and set following properties: Set Settings/Clock gate to Enabled Set Settings/Oscillator settings/Oscillator state to Enabled (it enable external oscillator also in stop modes) Set Settings/Time settings/Alarm time [s] to 15 (15 seconds timeout to wake-up from VLLS1 mode) Set Interrupts/ RTC interrupt/Interrupt request to Enabled Set Interrupts/ RTC interrupt/Time overflow interrupt to Disabled Set Interrupts/ RTC interrupt/Time invalid interrupt to Disabled Set Initialization/Time counter to Enabled Set Initialization/Utilize after reset values to no LPTMR (Low-Power Timer) device Open the Component Inspector of Init_LPTMR, switch to Advance view and set following properties: Set Settings/Clock gate to Enabled Set Settings/Clock settings/Clock select to Internal 1kHz LPO (this clock source is enabled in the VLLS1 mode) Set Settings/Clock settings/Prescale value/Glitch filter to Prescaler/64; Glitch Filter 32 (it will eliminates glitches on connected button that will be used for generating pulses) Set Settings/Compare value to 4 (the LPTMR interrupt is invoked when the compare value is equal to counter and the counter value is increased, i.e. 5 pulses on the input pins invoke the LPTMR interrupt) Set Settings/Timer mode to Pulse Counter (we will use the timer to count external pulses on the input pin 3) Set Settings/Pin select to Input 3 Set Settings/Pin polarity to Active Low Set Pins/Input pin 3 to Enabled and select PTB6/IRQ_2/LPTMR0_ALT3/TPM1_CH1, TPM_CLKIN1 in Pin 3 item. Set Interrupts/Interrupt request to Enabled Set Interrupts/Timer interrupt to Enabled (we will use the timer interrupt to wakeup CPU from VLLS1 mode after 5 pulses on the input 3 pin) Set Initialization/Timer enable to yes Set Initialization/Utilize after reset values to no We have finished design time settings of Processor Expert components and we are ready to write the application code. When you generate code and Build the application there will not be any error or warning. The Processor Expert project looks as follow: Application code During the component settings we have enabled two interrupt – RTC interrupt and LPTMR interrupt. Therefore we need to write theses interrupt service routines. If you look for example into RTC.h file, you can find the declaration of the RTC_IRQHandler interrupt routine. So we can use the declaration to write the definition of the routine in the main.c program module: #define RTC_ALARM_TIMEOUT_SEC 15 /* RTC interrupt service routine */ PE_ISR(RTC_IRQHandler) { if (RTC_HAL_HasAlarmOccured(RTC_BASE)) { // set the next alarm in RTC_ALARM_TIMEOUT_SEC seconds (clear also the TAF flag) RTC_HAL_SetAlarmReg(RTC_BASE,RTC_HAL_GetAlarmReg(RTC_BASE) + RTC_ALARM_TIMEOUT_SEC); } if (RTC_HAL_IsTimeInvalid(RTC_BASE)) { /* clear TIF (Time Invalid Flag) by stop of the counter and setting TSR reg */ RTC_HAL_EnableCounter(RTC_BASE, false); RTC_HAL_SetSecsReg(RTC_BASE, 0); /* enable counter */ RTC_HAL_EnableCounter(RTC_BASE, true); } } This interrupt routine services the Alarm interrupt in case that it is invoked during blinking of the green LED in the run mode (clear the flag and set the new Alarm time) and also it services the Invalid Time interrupt that can occur during recovering from the VLLS1 mode. Please note, that RTC module is little bit special , it runs in all run, wait and stop modes and the reset enables the Time Invalid interrupt bit (TIIE bit in RTC_IER) and invoke the Time Invalid interrupt on reset (POR or software reset). Therefore we need to clear the Invalid Time flag otherwise the application remain invoking RTC interrupt in an infinite cycle and the application does not work at all (it is also one of the issue that has not a straight forward solution). The RTC interrupt routine (defined above) shall properly serve all case we need in our application. Please note, that RTC interrupt always cause the wake-up from low-leakage stops modes (it is not configurable by LLWU on KL03 derivatives – see the chip-specific LLWU information). In addition, the after reset value of RTC_SR register is 0x01 (TIF flag is set). Therefore when the RTC is not initialized and a low-leakage stop mode is entered the CPU is immediately woken-up due to the RTC module interrupt flag (TIF flag is set). I.e. you must always properly initialize RTC module and clear all flags before you enter a low-leakage stop mode. We need also a service routine for the LPTMR device that is used for waking up from VLSS1 mode. This is a simple interrupt service routine that just clear the LPTMR interrupt flag: /* LPTMR interrupt service routine */ PE_ISR(LPTMR0_IRQHandler) { /* clear LPTMR interrupt flag */ LPTMR_HAL_ClearIntFlag(LPTMR0_BASE); } Now we can write the main function. We will need a temporary count variables for blinking: /* Write your local variable definition here */ volatile uint32_t i; // for waiting uint8_t blink_count; We need also a definition of the pin PTB11 that drivers the GREEN LED /* PTB11 - LED GREEN pin */ #define LED_GREEN_PIN 11 And the number of LED blinking: #define LED_BLINK 5 After devices initialization in PE_low_level_init() we need to check the reason of reset (POR reset or VLLS1 recovery). Thus we can write following code: /* Write your code here */ if (RCM_SRS0 == 0x01) { /* test the reason of reset - wakeup on VLLS */ if(PMC->REGSC & PMC_REGSC_ACKISO_MASK) { PMC->REGSC |= PMC_REGSC_ACKISO_MASK; /* VLLSx recovery */ } for (blink_count = 0; blink_count < LED_BLINK; blink_count++) { // green LED blinking GPIO_HAL_ClearPinOutput(GPIOB_BASE,LED_GREEN_PIN); for (i = 0; i<40000; i++); GPIO_HAL_SetPinOutput(GPIOB_BASE,LED_GREEN_PIN); for (i = 0; i<40000; i++); } // set the next alarm in "RTC_ALARM_TIMEOUT_SEC" seconds (clear also the TAF flag) RTC_HAL_SetAlarmReg(RTC_BASE,RTC_HAL_GetAlarmReg(RTC_BASE)+RTC_ALARM_TIMEOUT_SEC); } else { /* power-on reset */ /* switch the green LED on */ GPIO_HAL_ClearPinOutput(GPIOB_BASE,LED_GREEN_PIN); /* wait a while */ for (i = 0; i<40000; i++); /* switch the green LED off */ GPIO_HAL_SetPinOutput(GPIOB_BASE,LED_GREEN_PIN); } In case of VLLS1 recovery we acknowledge the pin isolation ACKISO bit in the PMC_REGSC register. This bit must be cleared to allow normal run mode of all pins. Then five blinking of the green LED follows (it is just a simple code for demo purposes only; you can write your own more sophisticated code for blinking by TPMx device with Init_TPM component if you want). In case of POR reset one blink of the green LED is processed. When the reset/wakup state is served by the our application code the VLLS1 mode can be entered. As the first step, we need to be sure that there are not any interrupt flags set to wake-up the CPU from VLLS1 mode so we clear LLWU and SW2 pin (PTB0) interrupt flags and then we enter VLLS1 mode by using enter_vllsx function: /* clear LLWU flag for the selected pin 4 - PTB0 */ LLWU_F1 |= LLWU_F1_WUF4_MASK; /* clear interrupt flag of the SW2 pin - PTB0 */ PORTB_PCR0 |= PORT_PCR_ISF_MASK; // enter the VLLS3 //enter_vllsx((smc_por_option_t)NULL,kSmcStopSub3); // enter the VLLS0 - RTC and LPTMR do not work becuase of external crystal clock source does not work in the VLLS0 mode //enter_vllsx(kSmcPorEnabled, kSmcStopSub0); // enter the VLLS1 enter_vllsx((smc_por_option_t)NULL,kSmcStopSub1); // switch the green LED on - error state when the VLLSx mode is not entered GPIO_HAL_ClearPinOutput(GPIOB_BASE,LED_GREEN_PIN); There is also code for switching on the green LED in case the VLLS1 mode is not entered (indication of the error state). The enter_vllsx function is defined by the following way (it is used existing function from a demo KSDK demo example): /* * VLLSx mode entry routinue */ static void enter_vllsx(smc_por_option_t PORPOValue, smc_stop_submode_t VLLSValue) { smc_power_mode_config_t smcConfig; /* set power mode to specific VLLSx mode */ smcConfig.porOption = true; smcConfig.porOptionValue = (smc_por_option_t) PORPOValue; smcConfig.powerModeName = kPowerModeVlls; smcConfig.stopSubMode = (smc_stop_submode_t) VLLSValue; SMC_HAL_SetMode(SMC_BASE, &smcConfig); } It is all code we need for our low power demo application. The application can be built and run now. 'Invoking: Cross ARM GNU Create Listing' arm-none-eabi-objdump --source --all-headers --demangle --line-numbers --wide "Low power demo KL03.elf" > "Low power demo KL03.lst" 'Finished building: Low power demo KL03.lst' ' ' 'Invoking: Cross ARM GNU Print Size' arm-none-eabi-size --format=berkeley "Low power demo KL03.elf" text data bss dec hex filename 7828 112 896 8836 2284 Low power demo KL03.elf 'Finished building: Low power demo KL03.siz' ' ' Note: You can see that the code size has increased because SDK functions have been used in the application. This is partly due to usage assert function that allows reporting of error by using standard libraries. If you needn’t this functionality and you need just a compact code (to decrease the power consumption) you can do it by the following way: Open Properties of the Low power demo KL03 application, select C/C++Build/Settings, on the Tool Settings tab, select Cross ARM C Compiler/Preprocessor and add NDEBUG symbol in the Defined symbols list: When you Clean and Build the application again the code size is reduced: 'Invoking: Cross ARM GNU Print Size' arm-none-eabi-size --format=berkeley "Low power demo KL03.elf" text data bss dec hex filename 3192 108 876 4176 1050 Low power demo KL03.elf 'Finished building: Low power demo KL03.siz' ' ' 08:20:28 Build Finished (took 15s.886ms) There is also additional step that allows you to reduce the code size of the application. You can set Optimization Level of GNU C tools. Open Properties of the Low power demo KL03 application, select C/C++Build/Settings, on the Tool Settings tab, select Optimization and set the Optimization Level to requested value (please note that some of the level are not suitable for debugging): Debugging The application contain predefined debug connect by default. . When you open the context menu of the project in the Project Explorer window and select Debug As/Debug Configurations.... The Debug Configurations window is opened and you can select and configure all predefined debug configurations (OpenOCD, PE Micro, Segger J-link). The default configuration can be easily used with the Freedom board (OpenSDA interface – j-link or PE Micro). You can just select the right debug connection and click on the Debug for debugging of your application. In the Debug Configuration window open the GDB SEGGER J-Link Debugger group and select the Low power demo KL03 Debug configuration. See the Debugger tab, there is already filled MKL03Z32xxx4 Device name. Uncheck Allocate console for semihosting and SWO (SWO is not support by OpenSDA SEGGER J-link). Go to on Startup tab and uncheck the Enable SWO option (SWO is not supported by OpenSDA SEGGER J-link). Click on the Apply and Debug button and the debugger starts (you must have the FRDM-KL03Z board connect to the workstation). You can now start the application (click on the Resume button) and check the functionality. The debugger is disconnected due to VLLS1 mode entry. But the application run and can be used. If you want to connect a button for the LPTMR pulses generating you can connect one pin of the button to the PTB6 on pin #4 of 8-pins connector J1 and the second pin of the button to the GND to the pin #7 of the 10-pins connector J2, see below: You can use this demo application as a start point of your real low power application. I hope it will help you and save your time of your first low power application implementation in the Processor Expert. There is also possible to measure power consumption of the CPU in VLLS1 mode. It is described in the FRDM-KL03 User Guide. Just unsolder R27 and R28 and solder a header pins to J10 position of the board. You must use jumper for J10 now to connect power supply for the CPU and when the jumper is removed you can use these two pins to measure the energy consumption of the CPU (e.g. by a multimeter)
View full article