From acba841bf15338b6ba472a0f433ac21bcc36310f Mon Sep 17 00:00:00 2001 From: Max Regan Date: Sat, 18 Apr 2020 12:18:32 -0700 Subject: [PATCH] Add Makefile support for more output binaries, add clock test --- firmware/Application/main.cpp | 208 ++++++----------------------- firmware/Bsp/Drivers/RtcDriver.cpp | 114 ++++++++-------- firmware/Bsp/Mcu/stm32l031k6.S | 2 + firmware/Bsp/Mcu/stm32l412rb.S | 2 + firmware/Makefile | 32 +++-- test/src/tr_test/test.py | 99 ++++++++++---- 6 files changed, 195 insertions(+), 262 deletions(-) diff --git a/firmware/Application/main.cpp b/firmware/Application/main.cpp index 2ca4d00..cc57fc4 100644 --- a/firmware/Application/main.cpp +++ b/firmware/Application/main.cpp @@ -38,178 +38,72 @@ #include "Bsp/macros.h" -// TODO: Don't include this here. -#include "stm32l0xx.h" +#include "Mcu.h" using BSP::Time; +// GPIOs + +static BSP::GpioDriver g_gpioa(GPIOA); + +static BSP::GpioPin g_dbg0(g_gpioa, 3); +static BSP::GpioPin g_dbg1(g_gpioa, 6); + +static BSP::GpioPin g_tx(g_gpioa, 9); +static BSP::GpioPin g_rx(g_gpioa, 10); + +static BSP::GpioPin g_btn_down(g_gpioa, 0); +static BSP::GpioPin g_btn_mid(g_gpioa, 1); +static BSP::GpioPin g_btn_up(g_gpioa, 2); + +static BSP::GpioPin g_nss(g_gpioa, 4); +static BSP::GpioPin g_sck(g_gpioa, 5); +static BSP::GpioPin g_mosi(g_gpioa, 12); +static BSP::GpioPin g_extcomm(g_gpioa, 7); + +// Scheduler and Tasks + static BSP::Schedule::LowPowerTaskScheduler<5> g_sched; -static BSP::SpiDriver g_spi(g_sched); +static BSP::SpiDriver g_spi(g_sched, g_nss); static BSP::DisplayDriver g_display(g_sched, g_spi); static BSP::LptimPwm g_lptim_pwm(LPTIM1); -static BSP::ButtonManager g_btn_manager(g_sched, 2, 1, 0, Time::millis(1)); +static BSP::ButtonManager g_btn_manager( + g_sched, g_btn_up, g_btn_mid, g_btn_down, Time::millis(200)); +// Screens- contexts for the display static ScreenManager g_screen_manager(g_sched, g_display, g_btn_manager); static SetTimeScreen g_set_time_screen(g_display, g_screen_manager); static SetTimeScreen g_set_date_screen(g_display, g_screen_manager); static StopwatchScreen g_stopwatch_screen(g_display, g_screen_manager); - -static MenuScreen g_enable_debug(g_display, - g_screen_manager, - "SW Update", - std::initializer_list({MenuScreenItem("Enable", []() { BSP::LowPower::enable_debug(); }), - MenuScreenItem("Disable", []() { BSP::LowPower::disable_debug();} - )})); -// static DebugScreen g_debug_screen(g_display, g_screen_manager); - static MenuScreen g_set_face_screen(g_display, g_screen_manager, "Face", std::initializer_list()); - static MenuScreen g_settings_menu_screen(g_display, g_screen_manager, "Settings", - std::initializer_list({MenuScreenItem("Set Time", g_set_time_screen), - MenuScreenItem("Set Date", g_set_date_screen), - MenuScreenItem("Set Face", g_set_face_screen), - MenuScreenItem("SW Update", g_enable_debug)})); - + std::initializer_list( + { + MenuScreenItem("Set Time", g_set_time_screen), + MenuScreenItem("Set Date", g_set_date_screen), + MenuScreenItem("Set Face", g_set_face_screen) + })); static MenuScreen g_apps_menu_screen(g_display, g_screen_manager, - "Apps", - std::initializer_list({MenuScreenItem("Stopwatch", g_stopwatch_screen)})); - - + "Apps", std::initializer_list({MenuScreenItem("Stopwatch", g_stopwatch_screen)})); static MenuScreen g_main_menu_screen(g_display, g_screen_manager, "Main Menu", - std::initializer_list({MenuScreenItem("Apps", g_apps_menu_screen), - MenuScreenItem("Settings", g_settings_menu_screen)})); - + std::initializer_list( + { + MenuScreenItem("Apps", g_apps_menu_screen), + MenuScreenItem("Settings", g_settings_menu_screen) + })); static AnalogTimeScreen g_analog_time_screen(g_display, g_screen_manager, g_main_menu_screen); static BigDigitalTimeScreen g_digital_time_screen(g_display, g_screen_manager, g_main_menu_screen); -extern "C" void __cxa_pure_virtual() { while(1) {} } - -void SystemInit() -{ - /** - * Use the MSI for the system clock, and disable all other clocks. - */ - - /*!< Set MSION bit. Set by hardware to force the MSI oscillator ON - * when exiting from Stop or Standby mode, or in case of a failure - * of the HSE oscillator used directly or indirectly as system - * clock. This bit cannot be cleared if the MSI is used as system - * clock. */ - SET(RCC->CR, - RCC_CR_MSION); - - SET_TO(RCC->ICSCR, - RCC_ICSCR_MSIRANGE, - RCC_ICSCR_MSIRANGE_6); - - /*!< Set internal representation of clock frequency to 4MHz */ - // system_clk_freq = 4u << 22; - - /*!< Reset - * SW[1:0] (use MSI oscillator as system clock), - * HPRE[3:0] (do not divide AHB clock in prescaler) , - * PPRE1[2:0] (do not divide APB low-speed clock) - * PPRE2[2:0] (do not divide APB high-speed clock), - * MCOSEL[2:0] (disable MCO clock), - * MCOPRE[2:0] (disable MCO prescaler) */ - CLR(RCC->CFGR, - RCC_CFGR_SW | ~RCC_CFGR_HPRE | RCC_CFGR_PPRE1 | RCC_CFGR_PPRE2 | - RCC_CFGR_MCOSEL | RCC_CFGR_MCOPRE); - - /*!< Reset - * HSION (disable HSI), - * HSIDIVEN (disable 18MHz HSI division) - * HSEON (disable HSE clock) - * CSSHSEON (disable HSE clock monitoring) - * PLLON (disable PLL) - */ - CLR(RCC->CR, - RCC_CR_HSION | RCC_CR_HSIDIVEN | RCC_CR_HSEON | - RCC_CR_CSSHSEON | RCC_CR_PLLON); - - /*!< Reset HSEBYP bit (disable HSE bypass) */ - CLR(RCC->CR, - RCC_CR_HSEBYP) - ; - - /* (1) Test if PLL is used as System clock */ - /* (2) Select HSI as system clock */ - /* (3) Wait for HSI switched */ - /* (4) Disable the PLL */ - /* (5) Wait until PLLRDY is cleared */ - /* (6) Set latency to 1 wait state */ - /* (7) Set the PLL multiplier to 24 and divider by 3 */ - /* (8) Enable the PLL */ - /* (9) Wait until PLLRDY is set */ - /* (10) Select PLL as system clock */ - /* (11) Wait until the PLL is switched on */ - - // SET(RCC->CR, RCC_CR_HSION); - // while((RCC->CR & RCC_CR_HSIRDY) != 0) {} - - // if ((RCC->CFGR & RCC_CFGR_SWS) == RCC_CFGR_SWS_PLL) /* (1) */ - // { - // RCC->CFGR = (RCC->CFGR & (uint32_t) (~RCC_CFGR_SW)) | RCC_CFGR_SW_HSI; /* (2) */ - // while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) /* (3) */ - // { /* For robust implementation, add here time-out management */ } - // } - - // RCC->CR &= (uint32_t)(~RCC_CR_PLLON);/* (4) */ - // while((RCC->CR & RCC_CR_PLLRDY) != 0) /* (5) */ - // { /* For robust implementation, add here time-out management */ } - - // FLASH->ACR |= FLASH_ACR_LATENCY; /* (6) */ - // RCC->CFGR = RCC->CFGR & ((~(RCC_CFGR_PLLMUL| RCC_CFGR_PLLDIV )) | (RCC_CFGR_PLLMUL24 | RCC_CFGR_PLLDIV2)); /* (7) */ - // RCC->CR |= RCC_CR_PLLON; /* (8) */ - - // while ((RCC->CR & RCC_CR_PLLRDY) == 0) /* (9) */ - // { /* For robust implementation, add here time-out management */ } - // RCC->CFGR |= (uint32_t) (RCC_CFGR_SW_PLL); /* (10) */ - - // while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) /* (11) */ - // { /* For robust implementation, add here time-out management */ } - - /*!< Reset - * PLLSRC (HSI16 is the PLL source), - * PLLMUL[3:0] (3x PLL multiplication) - * Don't touch PLLDIV[1:0], since 0 is undefined - */ - CLR(RCC->CFGR, - RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL | RCC_CFGR_PLLDIV); - - /*!< Disable all interrupts */ - RCC->CIER = 0x00000000; - - /* Vector Table Relocation in Internal FLASH */ - SCB->VTOR = FLASH_BASE; -} - -extern "C" { - -typedef void (*func_ptr)(void); -extern func_ptr __init_array_start[], __init_array_end[]; - -static void _init(void) -{ - - for (func_ptr* func = __init_array_start; func != __init_array_end; func++) { - (*func)(); - } -} -} - [[noreturn]] void main() { - _init(); - // Set up the system clock BSP::RtcDriver::init(); BSP::SystemTimer::set_timer(BSP::RtcDriver::get_system_timer()); @@ -238,29 +132,3 @@ static void _init(void) // And we're off! This will never return g_sched.run(); } - - -extern "C" void NMI_Handler() {while (1);} -extern "C" void HardFault_Handler() {while (1);} -extern "C" void SVC_Handler() {while (1);} -extern "C" void PendSV_Handler() {while (1);} -extern "C" void SysTick_Handler() {while (1);} - -extern "C" void WWDG_IRQHandler() {while (1);} -extern "C" void PVD_IRQHandler() {while (1);} -extern "C" void WDT_IRQHandler() {while (1);} -extern "C" void FLASH_IRQHandler() {while (1);} -extern "C" void RCC_CRS_IRQHandler() {while (1);} -extern "C" void DMA1_CHANNEL1_IRQHandler() {while (1);} -extern "C" void DMA1_CHANNEL3_2_IRQHandler() {while (1);} -extern "C" void DMA_CHANNEL_7_4_IRQHandler() {while (1);} -extern "C" void ADC_COMP_IRQHandler() {while (1);} -extern "C" void LPTIM1_IRQHandler() {while (1);} -extern "C" void USART4_USART5_IRQHandler() {while (1);} -extern "C" void TIM2_IRQHandler() {while (1);} -extern "C" void TIM3_IRQHandler() {while (1);} -extern "C" void TIM6_IRQHandler() {while (1);} -extern "C" void TIM7_IRQHandler() {while (1);} -extern "C" void TIM21_IRQHandler() {while (1);} -extern "C" void I2C3_IRQHandler() {while (1);} -extern "C" void TIM22_IRQHandler() {while (1);} diff --git a/firmware/Bsp/Drivers/RtcDriver.cpp b/firmware/Bsp/Drivers/RtcDriver.cpp index e42b027..18ffb10 100644 --- a/firmware/Bsp/Drivers/RtcDriver.cpp +++ b/firmware/Bsp/Drivers/RtcDriver.cpp @@ -58,27 +58,35 @@ void RtcDriver::enable_periodic_alarm() // Only calculate alarms when second rolls over SET_TO(RTC->ALRMASSR, RTC_ALRMASSR_MASKSS, RTC_ALRMASSR_MASKSS); + CLR(RTC->CR, RTC_CR_ALRAE | RTC_CR_ALRAIE); + #if defined(STM32L0XX) - SET(RTC->CR, RTC_CR_ALRAE | RTC_CR_ALRAIE); SET(EXTI->IMR, EXTI_IMR_IM17); - SET(EXTI->EMR, EXTI_EMR_EM17); SET(EXTI->RTSR, EXTI_RTSR_RT17); #elif defined(STM32L4XX) - SET(RTC->CR, RTC_CR_ALRAE | RTC_CR_ALRAIE); + SET(EXTI->IMR1, EXTI_IMR1_IM18); - SET(EXTI->EMR1, EXTI_EMR1_EM18); SET(EXTI->RTSR1, EXTI_RTSR1_RT18); + + NVIC_EnableIRQ(RTC_Alarm_IRQn); + NVIC_SetPriority(RTC_Alarm_IRQn, 0); + + SET(RTC->SCR, RTC_SCR_CALRAF); + #else #error "Unsupported family" #endif + SET(RTC->CR, RTC_CR_ALRAE); + SET(RTC->CR, RTC_CR_ALRAIE); } ReturnCode RtcDriver::init_hw() { - //SET(RCC->CSR, RCC_CSR_RTCRST); #if defined(STM32L0XX) uint32_t temp = RCC->CSR; + SET(RCC->CSR, RCC_CSR_RTCRST); + SET(RCC->APB1ENR, RCC_APB1ENR_PWREN); SET(PWR->CR, PWR_CR_DBP); @@ -102,14 +110,14 @@ ReturnCode RtcDriver::init_hw() #elif defined(STM32L4XX) uint32_t temp = RCC->CSR; + //SET(RCC->CSR, RCC_CSR_RTCRST); + SET(RCC->APB1ENR1, RCC_APB1ENR1_PWREN); SET(PWR->CR1, PWR_CR1_DBP); - /*BDCR & RCC_BDCR_LSERDY)) { - // TODO: Does this help? - SET(temp, RCC_BDCR_LSEON); - } + SET(temp, RCC_BDCR_LSEON); + + while (!(RCC->BDCR & RCC_BDCR_LSERDY)) {} SET_TO(temp, RCC_BDCR_RTCSEL, RCC_BDCR_RTCSEL_0); SET(temp, RCC_BDCR_RTCEN); @@ -127,8 +135,7 @@ ReturnCode RtcDriver::init_hw() #endif /*PRER, RTC_PRER_PREDIV_A, 0); + SET_TO(RTC->PRER, RTC_PRER_PREDIV_A, 0); /*PRER, RTC_PRER_PREDIV_S, (LSE_CLOCK_FREQ - 1)); @@ -151,27 +158,22 @@ ReturnCode RtcDriver::init_hw() CLR(RTC->ISR, RTC_ISR_INIT); SET(EXTI->IMR, EXTI_IMR_IM20); - SET(EXTI->EMR, EXTI_EMR_EM20); SET(EXTI->RTSR, EXTI_RTSR_RT20); // Enable Wakeup irq, we may/will use them later SET(RTC->CR, RTC_CR_WUTIE); NVIC_EnableIRQ(RTC_IRQn); NVIC_SetPriority(RTC_IRQn, 0); - #elif defined(STM32L4XX) CLR(RTC->ICSR, RTC_ICSR_INIT); SET(EXTI->IMR1, EXTI_IMR1_IM20); - SET(EXTI->EMR1, EXTI_EMR1_EM20); SET(EXTI->RTSR1, EXTI_RTSR1_RT20); // Enable Wakeup irq, we may/will use them later SET(RTC->CR, RTC_CR_WUTIE); NVIC_EnableIRQ(RTC_WKUP_IRQn); - NVIC_SetPriority(RTC_WKUP_IRQn, 0); - - + NVIC_SetPriority(RTC_WKUP_IRQn, 1); #else #error "Unsupported device type" #endif @@ -179,6 +181,8 @@ ReturnCode RtcDriver::init_hw() disable_rtc_write(); + //SET(EXTI->SWIER1, EXTI_SWIER1_SWI18); + return ReturnCode::OK; } @@ -243,11 +247,11 @@ ReturnCode RtcDriver::set_time(const BSP::WallClockTime &wall_time) #if defined(STM32L0XX) CLR(RTC->ISR, RTC_ISR_INIT); - while ((RTC->ISR & RTC_ISR_INITF)) {} + while (!(RTC->ISR & RTC_ISR_INITF)) {} while (!(RTC->ISR & RTC_ISR_RSF)) {} #elif defined(STM32L4XX) CLR(RTC->ICSR, RTC_ICSR_INIT); - while ((RTC->ICSR & RTC_ICSR_INITF)) {} + while (!(RTC->ICSR & RTC_ICSR_INITF)) {} while (!(RTC->ICSR & RTC_ICSR_RSF)) {} #else #error "Unsupported device type" @@ -319,22 +323,22 @@ ReturnCode RtcDriver::set_wakeup_in(BSP::time_t wakeup_delay) return ReturnCode::OK; } - BSP::time_t RtcDriver::RtcSystemTimer::get_time() - { - uint32_t new_secs, old_secs, ssr; - uint64_t new_timer_ticks, new_millis; - do { - __disable_irq(); - old_secs = m_seconds; - ssr = RTC->SSR & 0xFFFF; - new_secs = m_seconds; - __enable_irq(); - } while (new_secs != old_secs); +BSP::time_t RtcDriver::RtcSystemTimer::get_time() +{ + uint32_t new_secs, old_secs, ssr; + uint64_t new_timer_ticks, new_millis; + do { + __disable_irq(); + old_secs = m_seconds; + ssr = RTC->SSR & 0xFFFF; + new_secs = m_seconds; + __enable_irq(); + } while (new_secs != old_secs); - new_timer_ticks = (uint64_t) new_secs * LSE_CLOCK_FREQ; - /** SSR is a countdown register */ - new_millis = (new_timer_ticks + LSE_CLOCK_FREQ - 1 - ssr) * BSP::Time::MILLIS_PER_SEC / LSE_CLOCK_FREQ; - return BSP::Time::millis(new_millis); + new_timer_ticks = (uint64_t) new_secs * LSE_CLOCK_FREQ; + /** SSR is a countdown register */ + new_millis = (new_timer_ticks + LSE_CLOCK_FREQ - 1 - ssr) * BSP::Time::MILLIS_PER_SEC / LSE_CLOCK_FREQ; + return BSP::Time::millis(new_millis); } void RtcDriver::RtcSystemTimer::increment_seconds() @@ -351,11 +355,10 @@ void RtcDriver::increment_seconds() static uint32_t wakeup_alarms = 0; +#if defined(STM32L0XX) extern "C" void RTC_IRQHandler() { - // Clear the wakeup and alarm irq in the EXTI -#if defined(STM32L0XX) SET(EXTI->PR, EXTI_PR_PIF20 | EXTI_PR_PIF17); if (RTC->ISR & RTC_ISR_ALRAF) { @@ -371,29 +374,30 @@ extern "C" void RTC_IRQHandler() // one-shot timer CLR(RTC->CR, RTC_CR_WUTE); } +} +} #elif defined(STM32L4XX) - SET(EXTI->PR1, EXTI_PR1_PIF20 | EXTI_PR1_PIF18); +extern "C" void RTC_WKUP_IRQHandler() +{ + SET(EXTI->PR1, EXTI_PR1_PIF20); - if (RTC->SR & RTC_SR_ALRAF) { - RtcDriver::increment_seconds(); - CLR(RTC->SR, RTC_SR_ALRAF); - } + wakeup_alarms++; + // Clear the interrupt in the RTC + SET(RTC->SCR, RTC_SCR_CWUTF); + // Disable the Wakeup timer (its periodic, but we use it as a + // one-shot timer + CLR(RTC->CR, RTC_CR_WUTE); +} - if (RTC->SR & RTC_SR_WUTF) { - wakeup_alarms++; - // Clear the interrupt in the RTC - SET(RTC->SCR, RTC_SCR_CWUTF); - // Disable the Wakeup timer (its periodic, but we use it as a - // one-shot timer - CLR(RTC->CR, RTC_CR_WUTE); - } +extern "C" void RTC_ALARM_IRQHandler() +{ + SET(EXTI->PR1, EXTI_PR1_PIF18); + RtcDriver::increment_seconds(); + SET(RTC->SCR, RTC_SCR_CALRAF); +} +} #else #error "Unsupported device type" #endif - - -} - -} diff --git a/firmware/Bsp/Mcu/stm32l031k6.S b/firmware/Bsp/Mcu/stm32l031k6.S index bf21462..6c5a6d2 100644 --- a/firmware/Bsp/Mcu/stm32l031k6.S +++ b/firmware/Bsp/Mcu/stm32l031k6.S @@ -259,6 +259,8 @@ Reset_Handler: bl SystemInit #endif + bl __init_array + #ifndef __START #define __START _start #endif diff --git a/firmware/Bsp/Mcu/stm32l412rb.S b/firmware/Bsp/Mcu/stm32l412rb.S index bf21462..6c5a6d2 100644 --- a/firmware/Bsp/Mcu/stm32l412rb.S +++ b/firmware/Bsp/Mcu/stm32l412rb.S @@ -259,6 +259,8 @@ Reset_Handler: bl SystemInit #endif + bl __init_array + #ifndef __START #define __START _start #endif diff --git a/firmware/Makefile b/firmware/Makefile index 70b1da5..9ea6657 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -45,7 +45,7 @@ DEVICE_TYPE ?= stm32l031k6 DEVICE_FAMILY = stm32l031xx DEVICE_LINE = stm32l0xx -STACK_SIZE ?= 768 +STACK_SIZE ?= 512 HEAP_SIZE ?= 0 else ifeq ($(BOARD), devboard) @@ -83,11 +83,18 @@ S_SOURCES := $(call find_important, $(SOURCEDIR), '*.s') SPP_SOURCES := Bsp/Mcu/$(DEVICE_TYPE).S SOURCES = $(C_SOURCES) $(S_SOURCES) $(SPP_SOURCES) $(CPP_SOURCES) +APPS := ./Application/main ./Test/basic ./Test/clock +APP_ELFS = $(addsuffix .elf, $(APPS)) +APP_MAPS = $(addsuffix .map, $(APPS)) +APP_BINS = $(addsuffix .bin, $(APPS)) +APP_OBJS = $(addsuffix .o, $(APPS)) + C_OBJS := $(patsubst %.c,%.o,$(C_SOURCES)) CXX_OBJS := $(patsubst %.cpp,%.o,$(CXX_SOURCES)) S_OBJS := $(patsubst %.s,%.o,$(S_SOURCES)) SPP_OBJS := $(patsubst %.S,%.o,$(SPP_SOURCES)) -OBJS = $(C_OBJS) $(S_OBJS) $(SPP_OBJS) $(CXX_OBJS) +ALL_OBJS = $(C_OBJS) $(S_OBJS) $(SPP_OBJS) $(CXX_OBJS) +OBJS = $(filter-out $(APP_OBJS), $(ALL_OBJS)) LINKER_SCRIPT ?= Bsp/Mcu/$(DEVICE_TYPE).ld @@ -96,6 +103,10 @@ OUTPUT_BIN ?= $(OUTPUT_NAME).bin OUTPUT_ELF ?= $(OUTPUT_NAME).elf OUTPUT_MAP ?= $(OUTPUT_NAME).map +# $(info "ALL_OBJS=$(ALL_OBJS)") +# $(info "APP_OBJS=$(APP_OBJS)") +# $(info "OBJS=$(OBJS)") + # # Flags # @@ -118,9 +129,9 @@ CFLAGS += -ffreestanding CFLAGS += -fstack-usage -Wstack-usage=128 # Defines CFLAGS += -D$(DEVICE_FAMILY_DEFINE) -D$(DEVICE_TYPE_DEFINE) -D$(DEVICE_LINE_DEFINE) -CFLAGS += -DPRINTF_DISABLE_SUPPORT_FLOAT -DPRINTF_DISABLE_SUPPORT_EXPONENTIAL -DPRINTF_DISABLE_SUPPORT_PTRDIFF_T +# CFLAGS += -DPRINTF_DISABLE_SUPPORT_FLOAT -DPRINTF_DISABLE_SUPPORT_EXPONENTIAL -DPRINTF_DISABLE_SUPPORT_PTRDIFF_T # Consider this one if we are running short on flash, it saved about 1K -#CFLAGS += -DPRINTF_DISABLE_SUPPORT_LONG_LONG +# CFLAGS += -DPRINTF_DISABLE_SUPPORT_LONG_LONG # Includes CFLAGS += -I./Bsp/Mcu/ CFLAGS += -I./ThirdParty/stm32/$(DEVICE_LINE)/Include @@ -165,7 +176,7 @@ $(info ================================) # Default Target # .PHONY: build -build: $(OUTPUT_BIN) +build: $(APP_BINS) # # Build Logic @@ -195,13 +206,13 @@ $(FONT_GEN_DIR)/large_digits.h $(FONT_GEN_DIR)/large_digits.c: Gen/fixedfont-to- @mkdir -p $(FONT_GEN_DIR) @Gen/fixedfont-to-c.py $(patsubst .%,%,$(suffix $@)) $(LARGE_FONT) "$@" -s 70 --header-dir "Bsp/" --name font_large_digits -c "01234567890:" -$(OUTPUT_BIN): $(OUTPUT_ELF) +%.bin: %.elf @echo "OBJCOPY $@" - @$(OBJCOPY) -O binary $(OUTPUT_ELF) $(OUTPUT_BIN) + @$(OBJCOPY) -O binary $^ $@ -$(OUTPUT_MAP) $(OUTPUT_ELF): $(LINKER_SCRIPT) $(OBJS) +%.map %.elf: %.o $(LINKER_SCRIPT) $(OBJS) @echo "LD $@" - @$(LD) -T $(LINKER_SCRIPT) $(LDFLAGS) -o $(OUTPUT_ELF) $(OBJS) -Wl,-Map=$(OUTPUT_MAP) + @$(LD) -T $(LINKER_SCRIPT) $(LDFLAGS) -o $*.elf $*.o $(OBJS) -Wl,-Map=$*.map # # Utilities @@ -224,3 +235,6 @@ jlink: $(OUTPUT_BIN) .PHONY: clean clean: rm -f $(OBJS) $(OUTPUT_BIN) $(OUTPUT_ELF) $(FONT_C_FILES) $(FONT_H_FILES) $(OUTPUT_MAP) $(addsuffix .su,$(basename $(OBJS))) + +# Please do not delete my files. +.SECONDARY: $(ALL_OBJS) $(APP_ELFS) diff --git a/test/src/tr_test/test.py b/test/src/tr_test/test.py index a22b8db..063c967 100755 --- a/test/src/tr_test/test.py +++ b/test/src/tr_test/test.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + # Copyright (C) 2020 Max Regan # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -24,13 +26,18 @@ import serial.tools.list_ports import logging import pylink import time +import os +import sys -from typing import List - +PYTEST_DIR = os.path.dirname(os.path.abspath(__file__)) +DEFAULT_FW_DIR = os.path.abspath(PYTEST_DIR + "../../../../firmware/") SAMPLE_TIME_MS = 2500 SAMPLES_PER_SEC = 12000000 DRIVER = "fx2lafw" +TEST_START_TEXT = b"TEST_BEGIN\r\n" +TEST_PASS_TEXT = b"TEST_PASS\r\n" +TEST_FAIL_TEXT = b"TEST_FAIL\r\n" @pytest.fixture def logger(): @@ -40,7 +47,17 @@ def logger(): @pytest.fixture def context_factory(): - def create_context(mcu: str, addr: int, fw_path: str, leave_halted: bool=False): + def create_context(fw_rel_path: str, + mcu: str="STM32L412RB", + addr: int=0x8000000, + leave_halted: bool=False): + + proc = subprocess.run(["make", "BOARD=devboard", fw_rel_path], + cwd=DEFAULT_FW_DIR, + capture_output=True, + check=True) + logging.info("Make process stdout: {}".format(proc.stdout)) + ports = serial.tools.list_ports.comports() if len(ports) == 0: raise RuntimeError("No serial devices found") @@ -56,44 +73,70 @@ def context_factory(): jlink.set_tif(pylink.enums.JLinkInterfaces.SWD) jlink.connect(mcu) #jlink.set_reset_strategy(pylink.enums.JLinkResetStrategyCortexM3.HALT_AFTER_BTL) - jlink.flash_file(fw_path, addr) + fw = DEFAULT_FW_DIR + "/" + fw_rel_path + logging.info("Flashing {}...".format(fw)) + jlink.flash_file(fw, addr) + logging.info("Flashing done.") assert jlink.halted() jlink.reset(halt=True) - serial_dev = serial.Serial(port=ports[0].device, baudrate=115200) - - if not leave_halted: - jlink.reset(halt=False) - while True: - try: - serial_dev.read_until(b"HELLO WORLD!\r\n") - except serial.serialutil.SerialException: - continue - break + serial_dev = serial.Serial(port=ports[0].device, baudrate=115200, timeout=1) + if leave_halted: + return serial_dev, jlink + # Start test test, and check that it started correctly over serial + jlink.reset(halt=False) + while True: + try: + logging.info("Waiting for firmware to start...") + assert serial_dev.read_until(TEST_START_TEXT).endswith(TEST_START_TEXT), \ + "Timed out starting test firmware application" + logging.debug("Test execution started") + except serial.serialutil.SerialException: + continue + break return serial_dev, jlink - return create_context -def test_serial(context_factory, logger): - serial_dev, jlink = context_factory( - "STM32L412RB", - 0x8000000, - "/home/max/work/TimelyReference/firmware/watch.bin" - ) +def test_basic(context_factory, logger): + serial_dev, jlink = context_factory("Test/basic.bin") + text = serial_dev.read_until(TEST_PASS_TEXT) + print("Got serial output: {}".format(text)) + assert text.endswith(TEST_PASS_TEXT) - lines = [serial_dev.readline().decode("ascii", errors="ignore") for _ in range(3)] - logger.info("Test lines: {}".format(lines)) - assert lines[0] == "Counter: 0\r\n" - assert lines[1] == "HELLO WORLD!\r\n" - assert lines[2] == "Counter: 1\r\n" +def test_watch(context_factory, logger): + serial_dev, jlink = context_factory("Application/main.bin", leave_halted=True) + jlink.reset(halt=False) +def test_clock(context_factory, logger): + serial_dev, jlink = context_factory("Test/clock.bin") + serial_dev.timeout = 1.5 + + START_MARKER = b"GO\r\n" + END_MARKER = b"STOP\r\n" + + start_text = serial_dev.read_until(START_MARKER) + start = time.monotonic() + end_text = serial_dev.read_until(END_MARKER) + end = time.monotonic() + + delta = end - start + logger.debug("Serial text: {}".format(start_text)) + logger.debug("Serial text: {}".format(end_text)) + logger.info("Start time: {}".format(start)) + logger.info("End time: {}".format(end)) + logger.info("Delta time: {}".format(delta)) + + # TODO: Using a single pin, instead of UART, would make this more + # accurate. Add support via sigrok. + assert start_text.endswith(START_MARKER) + assert end_text.endswith(END_MARKER) + assert delta < 1.1 and delta > .9 def main(): - pytest.main() - + pytest.main(sys.argv) if __name__ == "__main__": main()