From d69d1307f20c0114dae7e96494ed9f5e7249d68a Mon Sep 17 00:00:00 2001 From: Max Regan <mgregan2@gmail.com> Date: Sat, 13 Jun 2020 15:30:58 -0700 Subject: [PATCH 1/2] Add a basic sleep time test This ensures that when there is minimal user code, that the device can spend the vast majority of its time sleeping. --- firmware/Test/Board/devboard.cpp | 1 + firmware/Test/Board/watch.cpp | 2 + firmware/Test/Common/TestBoard.h | 1 + test/src/tr_test/test.py | 153 ++++++++++++++++++------------- 4 files changed, 91 insertions(+), 66 deletions(-) diff --git a/firmware/Test/Board/devboard.cpp b/firmware/Test/Board/devboard.cpp index f280006..87f1460 100644 --- a/firmware/Test/Board/devboard.cpp +++ b/firmware/Test/Board/devboard.cpp @@ -32,6 +32,7 @@ using namespace BSP::Schedule; LowPowerTaskScheduler<10> g_sched; GpioDriver g_gpioa(GPIOA); UsartDriver g_test_uart(USART1, g_sched); +GpioPin g_debug0_pin(g_gpioa, 4); void board_init() { g_gpioa.enable(); diff --git a/firmware/Test/Board/watch.cpp b/firmware/Test/Board/watch.cpp index 5106148..17fc3fc 100644 --- a/firmware/Test/Board/watch.cpp +++ b/firmware/Test/Board/watch.cpp @@ -31,11 +31,13 @@ using namespace BSP::Schedule; LowPowerTaskScheduler<10> g_sched; GpioDriver g_gpioa(GPIOA); UsartDriver g_test_uart(USART2, g_sched); +GpioPin g_debug0_pin(g_gpioa, 3); static GpioPin g_tx_pin(g_gpioa, 9); void board_init() { g_gpioa.enable(); g_tx_pin.configure_alternate_function(4); + g_debug0_pin.configure_input(GpioDriver::input_pull_t::PULL_UP); g_test_uart.init(); RtcDriver::init(); diff --git a/firmware/Test/Common/TestBoard.h b/firmware/Test/Common/TestBoard.h index 17c254d..b31b6d4 100644 --- a/firmware/Test/Common/TestBoard.h +++ b/firmware/Test/Common/TestBoard.h @@ -30,3 +30,4 @@ void board_init(); extern BSP::Schedule::LowPowerTaskScheduler<10> g_sched; extern BSP::GpioDriver g_gpioa; extern BSP::UsartDriver g_test_uart; +extern BSP::GpioPin g_debug0_pin; diff --git a/test/src/tr_test/test.py b/test/src/tr_test/test.py index bc76c53..5ac65aa 100755 --- a/test/src/tr_test/test.py +++ b/test/src/tr_test/test.py @@ -102,6 +102,54 @@ def context_factory(): return create_context +def measure_frequency( + period: float, + pin_name: str, + executable: str = "sigrok-cli", + driver_name: str = "fx2lafw", +): + + cmd = [ + executable, + "-C", + pin_name, + "-d", + driver_name, + "-c", + "samplerate=1M", + "--time", + "{}ms".format(int(period * 1000)), + "-P", + "timing:data={}".format(pin_name), + "-A", + "timing=time", + ] + + print("sigrok-cli cmd {}".format(cmd)) + proc = subprocess.run(cmd, capture_output=True, check=True) + lines = proc.stdout.decode("utf-8").split("\n") + reg = re.compile(".*:\\W(\\d+.\\d+)\\W(\\w+)") + periods = [] + for line in lines: + m = reg.match(line) + if not m: + break + num = float(m.groups(1)[0]) + units = m.groups(1)[1] + if units == "s": + periods.append(num) + elif units == "ms": + periods.append(num / 1000) + elif units == "μs": + periods.append(num / 1000000) + else: + assert False, "Couldnt find units in line '{}', units were '{}'".format( + line, units + ) + + return periods[::2], periods[1:][::2] + + def test_meta_pass(context_factory, logger): serial_dev, jlink = context_factory("Test/Apps/pass.bin") text = serial_dev.read_until(TEST_PASS_TEXT) @@ -252,6 +300,45 @@ def test_wakeup_irq(context_factory, logger): assert abs(delta) < 1000 +def test_lptim(context_factory, logger): + serial_dev, jlink = context_factory("Test/Apps/lptim.bin") + state0_periods, state1_periods = measure_frequency(1, "D0") + num_periods = min(len(state0_periods), len(state1_periods)) + periods = [state0_periods[i] + state1_periods[i] for i in range(num_periods)] + freqs = list(map(lambda x: 1 / x, periods)) + assert ( + periods + ), "No LPTIM state changes detected, is the right analyzer being used? Is the device connected?" + + min_f = min(freqs) + max_f = max(freqs) + avg_f = sum(freqs) / len(freqs) + print("min:{}, max:{}, avg:{}".format(min_f, max_f, avg_f)) + assert abs(avg_f - 50) < 0.25 + assert min_f > 49 + assert max_f < 51 + + +def test_sleep(context_factory, logger): + serial_dev, jlink = context_factory("Test/Apps/sleep.bin") + state0_periods, state1_periods = measure_frequency(10, "D1") + num_periods = min(len(state0_periods), len(state1_periods)) + periods = [state0_periods[i] + state1_periods[i] for i in range(num_periods)] + freqs = list(map(lambda x: 1 / x, periods)) + assert ( + periods + ), "No debug pin state changes detected, is the right analyzer being used? Is the device connected?" + + min_f = min(freqs) + max_f = max(freqs) + pct_sleep = sum(state1_periods) * 100 / sum(state0_periods + state1_periods) + print("period_min:{}, period_max:{}, pct_sleep:{}".format(min_f, max_f, pct_sleep)) + assert abs(1 - min_f) < 0.001, "Expected wakeups at 1Hz to update sytem timer" + assert abs(1 - max_f) < 0.001, "Expected wakeups at 1Hz to update sytem timer" + assert len(periods) >= 5 and len(periods) < 10 + assert pct_sleep > 99.95, "Spent too much time awake" + + def test_stop(context_factory, logger): serial_dev, jlink = context_factory("Test/Apps/stop.bin") serial_dev.timeout = 70 @@ -277,72 +364,6 @@ def test_stop(context_factory, logger): assert abs(delta) < 1000 -"sigrok-cli -C D3 -d fx2lafw -c samplerate=1M --time 1s -P timing:data=D3" - - -def measure_frequency( - period: float, - pin_name: str, - executable: str = "sigrok-cli", - driver_name: str = "fx2lafw", -): - - cmd = [ - executable, - "-C", - pin_name, - "-d", - driver_name, - "-c", - "samplerate=1M", - "--time", - "{}ms".format(int(period * 1000)), - "-P", - "timing:data={}".format(pin_name), - "-A", - "timing=time", - ] - - print("sigrok-cli cmd {}".format(cmd)) - proc = subprocess.run(cmd, capture_output=True, check=True) - lines = proc.stdout.decode("utf-8").split("\n") - reg = re.compile(".*:\\W(\\d+.\\d+)\\W(\\w+)") - periods = [] - for line in lines: - m = reg.match(line) - if not m: - break - num = float(m.groups(1)[0]) - units = m.groups(1)[1] - if units == "ms": - periods.append(num / 1000) - elif units == "μs": - periods.append(num / 1000000) - else: - assert False - - return periods[::2], periods[1:][::2] - - -def test_lptim(context_factory, logger): - serial_dev, jlink = context_factory("Test/Apps/lptim.bin") - state0_periods, state1_periods = measure_frequency(1, "D0") - num_periods = min(len(state0_periods), len(state1_periods)) - periods = [state0_periods[i] + state1_periods[i] for i in range(num_periods)] - freqs = list(map(lambda x: 1 / x, periods)) - assert ( - periods - ), "No LPTIM changes detected, is the right analyzer being used? Is the device connected?" - - min_f = min(freqs) - max_f = max(freqs) - avg_f = sum(freqs) / len(freqs) - print("min:{}, max:{}, avg:{}".format(min_f, max_f, avg_f)) - assert abs(avg_f - 50) < 0.25 - assert min_f > 49 - assert max_f < 51 - - def main(): pytest.main(sys.argv) -- GitLab From cbb953ab27efbb6e8311e0252b79c236f36cc017 Mon Sep 17 00:00:00 2001 From: Max Regan <mgregan2@gmail.com> Date: Sun, 14 Jun 2020 10:57:13 -0700 Subject: [PATCH 2/2] Add watch application lowpower test --- .../Screens/BigDigitalTimeScreen.cpp | 2 +- firmware/Application/main.cpp | 10 +++++++-- firmware/Bsp/Drivers/LowPower.cpp | 20 ++++++++++++++++-- firmware/Bsp/Drivers/LowPower.h | 5 +++++ test/src/tr_test/test.py | 21 ++++++++++++------- 5 files changed, 46 insertions(+), 12 deletions(-) diff --git a/firmware/Application/Screens/BigDigitalTimeScreen.cpp b/firmware/Application/Screens/BigDigitalTimeScreen.cpp index 335c2ea..bbfc793 100644 --- a/firmware/Application/Screens/BigDigitalTimeScreen.cpp +++ b/firmware/Application/Screens/BigDigitalTimeScreen.cpp @@ -37,7 +37,7 @@ BigDigitalTimeScreen::BigDigitalTimeScreen(BSP::DisplayDriver &driver, , m_last_time() , m_manager(manager) , m_menu_screen(menu_screen) - , m_display_seconds(true) + , m_display_seconds(false) {} static char get_char_for_digit(uint8_t bcd_digit) diff --git a/firmware/Application/main.cpp b/firmware/Application/main.cpp index 38cba53..25e600e 100644 --- a/firmware/Application/main.cpp +++ b/firmware/Application/main.cpp @@ -104,10 +104,16 @@ static BigDigitalTimeScreen g_digital_time_screen(g_display, g_screen_mgr, g_mai [[noreturn]] void main() { + g_gpioa.init(); + g_gpioa.enable(); + + g_dbg0.configure_output(GpioDriver::output_mode_t::PUSH_PULL, + GpioDriver::output_speed_t::LOW); + // Set up the system clock RtcDriver::init(); SystemTimer::set_timer(RtcDriver::get_system_timer()); - LowPower::init(); + LowPower::init(g_dbg0); // Initialize the tasks g_lptim_pwm.init(); @@ -115,7 +121,7 @@ static BigDigitalTimeScreen g_digital_time_screen(g_display, g_screen_mgr, g_mai g_btn_mgr.init(); g_display.init(); g_screen_mgr.init(); - g_screen_mgr.set_root_screen(g_analog_time_screen); + g_screen_mgr.set_root_screen(g_digital_time_screen); g_set_face_screen.add_item(MenuScreenItem("Analog", []() { g_screen_mgr.set_root_screen(g_analog_time_screen); })); diff --git a/firmware/Bsp/Drivers/LowPower.cpp b/firmware/Bsp/Drivers/LowPower.cpp index 8a2e5d0..45622c1 100644 --- a/firmware/Bsp/Drivers/LowPower.cpp +++ b/firmware/Bsp/Drivers/LowPower.cpp @@ -31,9 +31,19 @@ namespace BSP { using BSP::ReturnCode; +GpioPin *LowPower::m_timing_pin = nullptr; + ReturnCode LowPower::init() { - enable_debug(); + m_timing_pin = nullptr; + return ReturnCode::OK; +} + +ReturnCode LowPower::init(GpioPin &timing_pin) +{ + m_timing_pin = &timing_pin; + m_timing_pin->write(0); + return ReturnCode::OK; } @@ -93,7 +103,13 @@ ReturnCode LowPower::stop() CLR(RCC->CFGR, RCC_CFGR_STOPWUCK); // MSI oscillator is wake-up from stop clock SET(SCB->SCR, SCB_SCR_SLEEPDEEP_Msk); // low-power mode = stop mode - __WFI(); // enter low-power mode (Wake from interrupt) + if (m_timing_pin != nullptr) { + m_timing_pin->write(1); + __WFI(); // enter low-power mode (Wake from interrupt) + m_timing_pin->write(0); + } else{ + __WFI(); + } wakeups++; diff --git a/firmware/Bsp/Drivers/LowPower.h b/firmware/Bsp/Drivers/LowPower.h index 9a396e3..d3870b0 100644 --- a/firmware/Bsp/Drivers/LowPower.h +++ b/firmware/Bsp/Drivers/LowPower.h @@ -22,6 +22,7 @@ #pragma once #include "Bsp/ReturnCode.h" +#include "Bsp/Drivers/GpioDriver.h" extern uint32_t wakeups; @@ -32,10 +33,14 @@ public: LowPower() = delete; static BSP::ReturnCode init(); + static BSP::ReturnCode init(GpioPin &timing_pin); + static BSP::ReturnCode sleep(); static BSP::ReturnCode stop(); static BSP::ReturnCode enable_debug(); static BSP::ReturnCode disable_debug(); + + static GpioPin *m_timing_pin; }; } diff --git a/test/src/tr_test/test.py b/test/src/tr_test/test.py index 5ac65aa..26108c7 100755 --- a/test/src/tr_test/test.py +++ b/test/src/tr_test/test.py @@ -107,6 +107,7 @@ def measure_frequency( pin_name: str, executable: str = "sigrok-cli", driver_name: str = "fx2lafw", + trigger: str = "r", ): cmd = [ @@ -119,6 +120,8 @@ def measure_frequency( "samplerate=1M", "--time", "{}ms".format(int(period * 1000)), + "-t", + "{}={}".format(pin_name, trigger), "-P", "timing:data={}".format(pin_name), "-A", @@ -313,14 +316,15 @@ def test_lptim(context_factory, logger): min_f = min(freqs) max_f = max(freqs) avg_f = sum(freqs) / len(freqs) - print("min:{}, max:{}, avg:{}".format(min_f, max_f, avg_f)) + print("min_f:{}, max_f:{}, avg_f:{}".format(min_f, max_f, avg_f)) assert abs(avg_f - 50) < 0.25 assert min_f > 49 assert max_f < 51 -def test_sleep(context_factory, logger): - serial_dev, jlink = context_factory("Test/Apps/sleep.bin") +def test_app_lowpower(context_factory, logger): + serial_dev, jlink = context_factory("Application/main.bin", leave_halted=True) + jlink.reset(halt=False) state0_periods, state1_periods = measure_frequency(10, "D1") num_periods = min(len(state0_periods), len(state1_periods)) periods = [state0_periods[i] + state1_periods[i] for i in range(num_periods)] @@ -331,11 +335,14 @@ def test_sleep(context_factory, logger): min_f = min(freqs) max_f = max(freqs) + avg_f = sum(freqs) / len(freqs) pct_sleep = sum(state1_periods) * 100 / sum(state0_periods + state1_periods) - print("period_min:{}, period_max:{}, pct_sleep:{}".format(min_f, max_f, pct_sleep)) - assert abs(1 - min_f) < 0.001, "Expected wakeups at 1Hz to update sytem timer" - assert abs(1 - max_f) < 0.001, "Expected wakeups at 1Hz to update sytem timer" - assert len(periods) >= 5 and len(periods) < 10 + print( + "min_f:{}, max_f:{}, avg_f:{}, pct_sleep:{}".format( + min_f, max_f, avg_f, pct_sleep + ) + ) + assert len(periods) >= 5 assert pct_sleep > 99.95, "Spent too much time awake" -- GitLab