Verify the main app mostly sleeps
This validates that the main watch app spends at least 99.5% of it's time sleeping in the first 10 seconds.
This commit is contained in:
@@ -37,7 +37,7 @@ BigDigitalTimeScreen::BigDigitalTimeScreen(BSP::DisplayDriver &driver,
|
|||||||
, m_last_time()
|
, m_last_time()
|
||||||
, m_manager(manager)
|
, m_manager(manager)
|
||||||
, m_menu_screen(menu_screen)
|
, m_menu_screen(menu_screen)
|
||||||
, m_display_seconds(true)
|
, m_display_seconds(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
static char get_char_for_digit(uint8_t bcd_digit)
|
static char get_char_for_digit(uint8_t bcd_digit)
|
||||||
|
|||||||
@@ -104,10 +104,16 @@ static BigDigitalTimeScreen g_digital_time_screen(g_display, g_screen_mgr, g_mai
|
|||||||
|
|
||||||
[[noreturn]] void main() {
|
[[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
|
// Set up the system clock
|
||||||
RtcDriver::init();
|
RtcDriver::init();
|
||||||
SystemTimer::set_timer(RtcDriver::get_system_timer());
|
SystemTimer::set_timer(RtcDriver::get_system_timer());
|
||||||
LowPower::init();
|
LowPower::init(g_dbg0);
|
||||||
|
|
||||||
// Initialize the tasks
|
// Initialize the tasks
|
||||||
g_lptim_pwm.init();
|
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_btn_mgr.init();
|
||||||
g_display.init();
|
g_display.init();
|
||||||
g_screen_mgr.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_set_face_screen.add_item(MenuScreenItem("Analog",
|
||||||
[]() { g_screen_mgr.set_root_screen(g_analog_time_screen); }));
|
[]() { g_screen_mgr.set_root_screen(g_analog_time_screen); }));
|
||||||
|
|||||||
@@ -31,9 +31,19 @@ namespace BSP {
|
|||||||
|
|
||||||
using BSP::ReturnCode;
|
using BSP::ReturnCode;
|
||||||
|
|
||||||
|
GpioPin *LowPower::m_timing_pin = nullptr;
|
||||||
|
|
||||||
ReturnCode LowPower::init()
|
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;
|
return ReturnCode::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +103,13 @@ ReturnCode LowPower::stop()
|
|||||||
CLR(RCC->CFGR, RCC_CFGR_STOPWUCK); // MSI oscillator is wake-up from stop clock
|
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
|
SET(SCB->SCR, SCB_SCR_SLEEPDEEP_Msk); // low-power mode = stop mode
|
||||||
|
|
||||||
|
if (m_timing_pin != nullptr) {
|
||||||
|
m_timing_pin->write(1);
|
||||||
__WFI(); // enter low-power mode (Wake from interrupt)
|
__WFI(); // enter low-power mode (Wake from interrupt)
|
||||||
|
m_timing_pin->write(0);
|
||||||
|
} else{
|
||||||
|
__WFI();
|
||||||
|
}
|
||||||
|
|
||||||
wakeups++;
|
wakeups++;
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Bsp/ReturnCode.h"
|
#include "Bsp/ReturnCode.h"
|
||||||
|
#include "Bsp/Drivers/GpioDriver.h"
|
||||||
|
|
||||||
extern uint32_t wakeups;
|
extern uint32_t wakeups;
|
||||||
|
|
||||||
@@ -32,10 +33,14 @@ public:
|
|||||||
LowPower() = delete;
|
LowPower() = delete;
|
||||||
|
|
||||||
static BSP::ReturnCode init();
|
static BSP::ReturnCode init();
|
||||||
|
static BSP::ReturnCode init(GpioPin &timing_pin);
|
||||||
|
|
||||||
static BSP::ReturnCode sleep();
|
static BSP::ReturnCode sleep();
|
||||||
static BSP::ReturnCode stop();
|
static BSP::ReturnCode stop();
|
||||||
static BSP::ReturnCode enable_debug();
|
static BSP::ReturnCode enable_debug();
|
||||||
static BSP::ReturnCode disable_debug();
|
static BSP::ReturnCode disable_debug();
|
||||||
|
|
||||||
|
static GpioPin *m_timing_pin;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ using namespace BSP::Schedule;
|
|||||||
LowPowerTaskScheduler<10> g_sched;
|
LowPowerTaskScheduler<10> g_sched;
|
||||||
GpioDriver g_gpioa(GPIOA);
|
GpioDriver g_gpioa(GPIOA);
|
||||||
UsartDriver g_test_uart(USART1, g_sched);
|
UsartDriver g_test_uart(USART1, g_sched);
|
||||||
|
GpioPin g_debug0_pin(g_gpioa, 4);
|
||||||
|
|
||||||
void board_init() {
|
void board_init() {
|
||||||
g_gpioa.enable();
|
g_gpioa.enable();
|
||||||
|
|||||||
@@ -31,11 +31,13 @@ using namespace BSP::Schedule;
|
|||||||
LowPowerTaskScheduler<10> g_sched;
|
LowPowerTaskScheduler<10> g_sched;
|
||||||
GpioDriver g_gpioa(GPIOA);
|
GpioDriver g_gpioa(GPIOA);
|
||||||
UsartDriver g_test_uart(USART2, g_sched);
|
UsartDriver g_test_uart(USART2, g_sched);
|
||||||
|
GpioPin g_debug0_pin(g_gpioa, 3);
|
||||||
static GpioPin g_tx_pin(g_gpioa, 9);
|
static GpioPin g_tx_pin(g_gpioa, 9);
|
||||||
|
|
||||||
void board_init() {
|
void board_init() {
|
||||||
g_gpioa.enable();
|
g_gpioa.enable();
|
||||||
g_tx_pin.configure_alternate_function(4);
|
g_tx_pin.configure_alternate_function(4);
|
||||||
|
g_debug0_pin.configure_input(GpioDriver::input_pull_t::PULL_UP);
|
||||||
g_test_uart.init();
|
g_test_uart.init();
|
||||||
|
|
||||||
RtcDriver::init();
|
RtcDriver::init();
|
||||||
|
|||||||
@@ -30,3 +30,4 @@ void board_init();
|
|||||||
extern BSP::Schedule::LowPowerTaskScheduler<10> g_sched;
|
extern BSP::Schedule::LowPowerTaskScheduler<10> g_sched;
|
||||||
extern BSP::GpioDriver g_gpioa;
|
extern BSP::GpioDriver g_gpioa;
|
||||||
extern BSP::UsartDriver g_test_uart;
|
extern BSP::UsartDriver g_test_uart;
|
||||||
|
extern BSP::GpioPin g_debug0_pin;
|
||||||
|
|||||||
@@ -102,6 +102,57 @@ def context_factory():
|
|||||||
return create_context
|
return create_context
|
||||||
|
|
||||||
|
|
||||||
|
def measure_frequency(
|
||||||
|
period: float,
|
||||||
|
pin_name: str,
|
||||||
|
executable: str = "sigrok-cli",
|
||||||
|
driver_name: str = "fx2lafw",
|
||||||
|
trigger: str = "r",
|
||||||
|
):
|
||||||
|
|
||||||
|
cmd = [
|
||||||
|
executable,
|
||||||
|
"-C",
|
||||||
|
pin_name,
|
||||||
|
"-d",
|
||||||
|
driver_name,
|
||||||
|
"-c",
|
||||||
|
"samplerate=1M",
|
||||||
|
"--time",
|
||||||
|
"{}ms".format(int(period * 1000)),
|
||||||
|
"-t",
|
||||||
|
"{}={}".format(pin_name, trigger),
|
||||||
|
"-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):
|
def test_meta_pass(context_factory, logger):
|
||||||
serial_dev, jlink = context_factory("Test/Apps/pass.bin")
|
serial_dev, jlink = context_factory("Test/Apps/pass.bin")
|
||||||
text = serial_dev.read_until(TEST_PASS_TEXT)
|
text = serial_dev.read_until(TEST_PASS_TEXT)
|
||||||
@@ -252,6 +303,49 @@ def test_wakeup_irq(context_factory, logger):
|
|||||||
assert abs(delta) < 1000
|
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_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_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)]
|
||||||
|
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)
|
||||||
|
avg_f = sum(freqs) / len(freqs)
|
||||||
|
pct_sleep = sum(state1_periods) * 100 / sum(state0_periods + state1_periods)
|
||||||
|
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"
|
||||||
|
|
||||||
|
|
||||||
def test_stop(context_factory, logger):
|
def test_stop(context_factory, logger):
|
||||||
serial_dev, jlink = context_factory("Test/Apps/stop.bin")
|
serial_dev, jlink = context_factory("Test/Apps/stop.bin")
|
||||||
serial_dev.timeout = 70
|
serial_dev.timeout = 70
|
||||||
@@ -277,72 +371,6 @@ def test_stop(context_factory, logger):
|
|||||||
assert abs(delta) < 1000
|
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():
|
def main():
|
||||||
pytest.main(sys.argv)
|
pytest.main(sys.argv)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user