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