diff --git a/bench_pm/Makefile b/bench_pm/Makefile new file mode 100644 index 0000000..e1a602e --- /dev/null +++ b/bench_pm/Makefile @@ -0,0 +1,13 @@ +APPLICATION = bench_pm +BOARD ?= frdm-kw41z + +RIOTBASE ?= $(CURDIR)/../../RIOT +QUIET ?= 1 +DEVELHELP ?= 1 + +FEATURES_OPTIONAL = periph_rtt periph_gpio_irq + +# Disable auto_init to avoid starting any extra services +DISABLE_MODULE += auto_init + +include $(RIOTBASE)/Makefile.include diff --git a/bench_pm/README.md b/bench_pm/README.md new file mode 100644 index 0000000..eeb5bbf --- /dev/null +++ b/bench_pm/README.md @@ -0,0 +1,43 @@ +Purpose +======= + +This project is used to provide a baseline for the power consumption of the +platform when no software is interfering with the low power modes. The +application is designed to be used as a test subject for measuring power +consumption and timing of low power modes. + +Hardware requirements +===================== + +The data collection relies on external measurement equipment. An oscilloscope, +or logic analyzer and a multimeter is required for any meaningful measurements. + +Test outputs +============ + +The test uses the board's LED0, LED1 pins as feedback from the application to +the logic analyzer to signal when a low power mode is exited. +The wake up request is triggered by UART RX activity, or a configurable GPIO pin. + +Set up +====== + +Connect the logic analyzer to trigger on the chosen GPIO wake pin (or UART RX +pin, if not using the GPIO), connect the LED0 pin to the logic analyzer as well. + +The LED0 pin will be asserted immediately when control returns to the main thread. +The LED1 pin is asserted by the ISR. + +Tested hardware +=============== + +The application is designed to run on the FRDM-KW41Z (or a custom R41Z board), +but some care has been taken to allow building for different platforms without +any major changes. + +Future work +=========== + +The logic analyzer requirement could be eliminated by creating a measurement +application which can run on a different board for driving the test and taking +measurements. diff --git a/bench_pm/dist/analogdiscovery2/bench_pm.dwf3work b/bench_pm/dist/analogdiscovery2/bench_pm.dwf3work new file mode 100644 index 0000000..02e22c7 Binary files /dev/null and b/bench_pm/dist/analogdiscovery2/bench_pm.dwf3work differ diff --git a/bench_pm/main.c b/bench_pm/main.c new file mode 100644 index 0000000..53e7900 --- /dev/null +++ b/bench_pm/main.c @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2017-2018 SKF AB + * Copyright (C) 2014 Freie UniversitÀt Berlin + * + * This file is subject to the terms and conditions of the GNU Lesser General + * Public License v2.1. See the file LICENSE in the top level directory for more + * details. + */ + +/** + * @ingroup tests + * @{ + * + * @file + * @brief Test for low power modes and wake up timings + * + * This test will switch to different low power modes and wait for wake events. + * + * @author Joakim NohlgÄrd + * + * @} + */ + +#include +#include + +#include "cpu.h" +#include "board.h" +#include "periph_conf.h" +#include "periph/rtt.h" +#ifdef MODULE_PM_LAYERED +#include "pm_layered.h" +#endif +#ifdef MODULE_PERIPH_GPIO_IRQ +#include "periph/gpio.h" +#endif +#ifdef MODULE_PERIPH_LLWU +/* Kinetis specific low leakage mode handling */ +#include "llwu.h" +#endif + +#ifndef ENABLE_DEBUG +/* Enabling debug prints will affect timing measurements */ +#define ENABLE_DEBUG (0) +#endif +#include "debug.h" + +#if COMA_MODE +/* For testing deepest low power modes without any interference */ +#undef MODULE_PERIPH_GPIO_IRQ +#undef MODULE_PERIPH_RTT +#undef MODULE_PERIPH_LLWU +#undef LED0_ON +#undef LED1_ON +#endif + +#ifdef MODULE_PERIPH_RTT +#define PRINT_RTT() (printf("RTT: %" PRIu32 "\n", rtt_get_counter())) +#else +#define PRINT_RTT() +#endif + +#ifdef MODULE_PERIPH_GPIO_IRQ +#ifndef GPIO_WAKE_PIN +#ifdef BTN0_PIN +#define GPIO_WAKE_PIN BTN0_PIN +#else +#error Missing GPIO_WAKE_PIN configuration +#endif /* BTN0_PIN */ +#endif /* GPIO_WAKE_PIN */ +#endif /* MODULE_PERIPH_GPIO_IRQ */ + +#ifdef MODULE_PERIPH_LLWU +/* Platform specific configuration for testing Kinetis low leakage wake up module (LLWU) */ +#ifndef LLWU_WAKE_PIN +/* This macro should correspond to the pin used in the GPIO_WAKE_PIN macro */ +#if defined(BOARD_FRDM_KW41Z) +#define LLWU_WAKE_PIN LLWU_WAKEUP_PIN_PTC4 +#elif defined(BOARD_FRDM_K22F) +#define LLWU_WAKE_PIN LLWU_WAKEUP_PIN_PTC1 +#elif defined(BOARD_FRDM_K64F) +#define LLWU_WAKE_PIN LLWU_WAKEUP_PIN_PTC6 +#endif +#endif /* LLWU_WAKE_PIN */ +#endif /* MODULE_PERIPH_LLWU */ + +#ifndef TEST_PIN_ON +#ifdef LED0_ON +#define TEST_PIN_ON LED0_ON +#define TEST_PIN_OFF LED0_OFF +#else +#define TEST_PIN_ON +#define TEST_PIN_OFF +#endif /* LED0_ON */ +#endif /* TEST_PIN_ON */ + +#ifndef TEST_ISR_PIN_ON +#ifdef LED1_ON +#define TEST_ISR_PIN_ON LED1_ON +#define TEST_ISR_PIN_OFF LED1_OFF +#else +#define TEST_ISR_PIN_ON +#define TEST_ISR_PIN_OFF +#endif /* LED1_ON */ +#endif /* TEST_ISR_PIN_ON */ + +#ifdef MODULE_PERIPH_RTT +#define TICKS_TO_WAIT (10 * RTT_FREQUENCY) +#endif /* MODULE_PERIPH_RTT */ + +static volatile unsigned busy = 0; + +#ifdef MODULE_PERIPH_RTT +static void cb_rtt(void *arg) +{ + (void)arg; + TEST_ISR_PIN_ON; + DEBUG("RTT IRQ\n"); + + busy = 0; +} +#endif /* MODULE_PERIPH_RTT */ + +#ifdef MODULE_PERIPH_LLWU +static void cb_llwu(void *arg) +{ + (void)arg; + TEST_ISR_PIN_ON; + DEBUG("llwu pin\n"); + + busy = 0; +} +#endif /* MODULE_PERIPH_LLWU */ + +#ifdef MODULE_PERIPH_GPIO_IRQ +static void cb_gpio(void *arg) +{ + (void)arg; + TEST_ISR_PIN_ON; + DEBUG("gpio pin\n"); + + busy = 0; +} +#endif /* MODULE_PERIPH_GPIO_IRQ */ + +int main(void) +{ + TEST_PIN_ON; + puts("\nRIOT power consumption and wake timing test application"); + +#ifdef MODULE_PERIPH_LLWU + /* Kinetis specific */ + puts("Enable LLWU wake up from RTC"); + llwu_wakeup_module_enable(LLWU_WAKEUP_MODULE_RTC_ALARM); + puts("Enable LLWU IRQ on PTC4 (SW4) falling"); + gpio_init(GPIO_WAKE_PIN, GPIO_IN); + llwu_wakeup_pin_set(LLWU_WAKE_PIN, LLWU_WAKEUP_EDGE_FALLING, cb_llwu, NULL); +#endif /* MODULE_PERIPH_LLWU */ + +#ifdef MODULE_PERIPH_GPIO_IRQ + puts("Enable GPIO IRQ on PTC4 (SW4) falling"); + int res = gpio_init_int(GPIO_WAKE_PIN, GPIO_IN_PU, GPIO_FALLING, cb_gpio, NULL); + if (res != 0) { + printf("!! gpio_init_int: %d\n", res); + } +#endif /* MODULE_PERIPH_GPIO_IRQ */ + +#ifdef MODULE_PERIPH_RTT + puts("Initializing the RTT driver"); + rtt_init(); +#endif /* MODULE_PERIPH_RTT */ + +#if ENABLE_CLKOUT + /* Kinetis specific, clock monitor via CLKOUT on pin PTB3 */ + puts("Enable CLKOUT on PTB3"); + PORTB->PCR[3] = PORT_PCR_MUX(4); + /* Select which clock to output */ + SIM->SOPT2 = (SIM->SOPT2 & ~SIM_SOPT2_CLKOUTSEL_MASK) | SIM_SOPT2_CLKOUTSEL(2); + /* Use a logic analyzer or oscilloscope to look at the signal */ +#endif + +#if COMA_MODE + puts("Coma mode, going to pm_set(0), not coming back"); + while (1) { + pm_set(0); + puts("woke up unexpectedly, going to pm_set(0)"); + } +#endif + + while (1) { + PRINT_RTT(); + puts("Busy spin"); + { +#ifdef MODULE_PERIPH_RTT + uint32_t rtt_target = rtt_get_counter() + TICKS_TO_WAIT; + rtt_target &= RTT_MAX_VALUE; + rtt_set_alarm(rtt_target, cb_rtt, 0); +#endif /* MODULE_PERIPH_RTT */ + busy = 1; + TEST_PIN_OFF; + TEST_ISR_PIN_OFF; + while (busy) { + __asm__ volatile ("" ::: "memory"); + } + TEST_PIN_ON; + PRINT_RTT(); + } +#ifdef MODULE_PM_LAYERED + for (int k = PM_NUM_MODES; 0 <= k; --k) { +#ifdef MODULE_PERIPH_RTT + uint32_t rtt_target = rtt_get_counter() + TICKS_TO_WAIT; + rtt_target &= RTT_MAX_VALUE; + rtt_set_alarm(rtt_target, cb_rtt, 0); +#endif /* MODULE_PERIPH_RTT */ + PRINT_RTT(); + printf("pm_set(%d)\n", k); + TEST_PIN_OFF; + TEST_ISR_PIN_OFF; + pm_set((unsigned)k); + TEST_PIN_ON; + printf("wake from %d\n", k); + } +#endif + } + return 0; +}