diff --git a/src/generic/misc.h b/src/generic/misc.h index 7262078..71ebe06 100644 --- a/src/generic/misc.h +++ b/src/generic/misc.h @@ -3,12 +3,16 @@ #include // va_list #include // uint8_t +#include "autoconf.h" // CONFIG_MACH_STM32F0 uint16_t read_magic_key(void); void set_magic_key(void); void jump_to_application(void); // Timer Functions +#if CONFIG_MACH_STM32F0 +void timer_init(void); +#endif uint32_t timer_from_us(uint32_t us); uint8_t timer_is_before(uint32_t time1, uint32_t time2); uint32_t timer_read_time(void); diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index cd09231..2d28890 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -157,8 +157,10 @@ endchoice config FLASH_PAGE_SIZE hex - default 0x400 if STM32F1_PAGE_SIZE_400 - default 0x800 if STM32F1_PAGE_SIZE_800 + default 0x400 if MACH_STM32F042 + default 0x800 if MACH_STM32F070 + default 0x400 if MACH_STM32F103 && STM32F1_PAGE_SIZE_400 + default 0x800 if MACH_STM32F103 && STM32F1_PAGE_SIZE_800 default 0x400 config MAGIC_KEY diff --git a/src/stm32/Makefile b/src/stm32/Makefile index 87a84ee..24a4aa8 100644 --- a/src/stm32/Makefile +++ b/src/stm32/Makefile @@ -24,19 +24,19 @@ CFLAGS_canboot.elf += -T $(OUT)src/generic/armcm_link.ld $(OUT)canboot.elf: $(OUT)src/generic/armcm_link.ld # Add source files -src-y += stm32/gpio.c generic/armcm_timer.c +src-y += stm32/gpio.c stm32/flash.c src-y += generic/armcm_boot.c generic/armcm_irq.c src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c -src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c +src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c stm32/stm32f0_timer.c src-$(CONFIG_MACH_STM32F1) += ../lib/stm32f1/system_stm32f1xx.c -src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c stm32/flash.c +src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32F2) += ../lib/stm32f2/system_stm32f2xx.c -src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c +src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32F4) += ../lib/stm32f4/system_stm32f4xx.c -src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c +src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c generic/armcm_timer.c can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/canbus.c diff --git a/src/stm32/stm32f0.c b/src/stm32/stm32f0.c index bb3669d..c963679 100644 --- a/src/stm32/stm32f0.c +++ b/src/stm32/stm32f0.c @@ -7,6 +7,7 @@ #include "autoconf.h" // CONFIG_CLOCK_REF_FREQ #include "board/armcm_boot.h" // armcm_main #include "board/irq.h" // irq_disable +#include "board/misc.h" // read magic key #include "internal.h" // enable_pclock #include "canboot_main.h" // sched_main @@ -98,22 +99,6 @@ usb_request_bootloader(void) NVIC_SystemReset(); } -// Copy vector table and remap ram so new vector table is used -static void -enable_ram_vectortable(void) -{ - // Symbols created by armcm_link.lds.S linker script - extern uint32_t _ram_vectortable_start, _ram_vectortable_end; - extern uint32_t _text_vectortable_start; - - uint32_t count = (&_ram_vectortable_end - &_ram_vectortable_start) * 4; - __builtin_memcpy(&_ram_vectortable_start, &_text_vectortable_start, count); - barrier(); - - enable_pclock(SYSCFG_BASE); - SYSCFG->CFGR1 |= 3 << SYSCFG_CFGR1_MEM_MODE_Pos; -} - // Configure and enable the PLL as clock source static void pll_setup(void) @@ -144,38 +129,10 @@ pll_setup(void) // Setup CFGR3 register uint32_t cfgr3 = RCC_CFGR3_I2C1SW; - if (CONFIG_USBSERIAL) - // Select PLL as source for USB clock - cfgr3 |= RCC_CFGR3_USBSW; + RCC->CFGR3 = cfgr3; } -// Configure and enable internal 48Mhz clock on the stm32f042 -static void -hsi48_setup(void) -{ -#if CONFIG_MACH_STM32F042 - // Enable HSI48 - RCC->CR2 |= RCC_CR2_HSI48ON; - while (!(RCC->CR2 & RCC_CR2_HSI48RDY)) - ; - - // Switch system clock to HSI48 - RCC->CFGR = RCC_CFGR_SW_HSI48; - while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSI48) - ; - - // Enable USB clock recovery - if (CONFIG_USBSERIAL) { - enable_pclock(CRS_BASE); - CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN; - } - - // Setup I2C1 clock - RCC->CFGR3 = RCC_CFGR3_I2C1SW; -#endif -} - // Enable high speed internal 14Mhz clock for ADC static void hsi14_setup(void) @@ -190,28 +147,13 @@ hsi14_setup(void) void armcm_main(void) { - if (CONFIG_USBSERIAL && CONFIG_MACH_STM32F042 - && *(uint64_t*)USB_BOOT_FLAG_ADDR == USB_BOOT_FLAG) { - *(uint64_t*)USB_BOOT_FLAG_ADDR = 0; - uint32_t *sysbase = (uint32_t*)0x1fffc400; - asm volatile("mov sp, %0\n bx %1" - : : "r"(sysbase[0]), "r"(sysbase[1])); - } - SystemInit(); - if (CONFIG_ARMCM_RAM_VECTORTABLE) - enable_ram_vectortable(); - // Set flash latency FLASH->ACR = (1 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE; // Configure main clock - if (CONFIG_MACH_STM32F042 && CONFIG_STM32_CLOCK_REF_INTERNAL - && CONFIG_USBSERIAL) - hsi48_setup(); - else - pll_setup(); + pll_setup(); // Turn on hsi14 oscillator for ADC hsi14_setup(); @@ -224,5 +166,53 @@ armcm_main(void) } #endif - sched_main(); + timer_init(); + canboot_main(); +} + +uint16_t +read_magic_key(void) +{ + irq_disable(); + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + RCC->APB1ENR; + uint16_t val = RTC->BKP4R; + if (val) { + // clear the key + PWR->CR |= PWR_CR_DBP; + RTC->BKP4R = 0; + PWR->CR &=~ PWR_CR_DBP; + } + RCC->APB1ENR &= ~RCC_APB1ENR_PWREN; + irq_enable(); + return val; +} + +void +set_magic_key(void) +{ + irq_disable(); + RCC->APB1ENR |= RCC_APB1ENR_PWREN; + RCC->APB1ENR; + PWR->CR |= PWR_CR_DBP; + RTC->BKP4R = CONFIG_MAGIC_KEY; + PWR->CR &=~ PWR_CR_DBP; + RCC->APB1ENR &= ~RCC_APB1ENR_PWREN; + irq_enable(); +} + +typedef void (*func_ptr)(void); + +void +jump_to_application(void) +{ + func_ptr application = (func_ptr) *(volatile uint32_t*) + (CONFIG_APPLICATION_START + 0x04); + + // Set the main stack pointer + asm volatile ("MSR msp, %0" : : "r" (*(volatile uint32_t*) + CONFIG_APPLICATION_START) : ); + + // Jump to application + application(); } diff --git a/src/stm32/stm32f0_timer.c b/src/stm32/stm32f0_timer.c new file mode 100644 index 0000000..833fbc1 --- /dev/null +++ b/src/stm32/stm32f0_timer.c @@ -0,0 +1,115 @@ +// STM32F0 timer support +// +// Copyright (C) 2019 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "board/armcm_boot.h" // armcm_enable_irq +#include "board/internal.h" // TIM3 +#include "board/io.h" // readl +#include "board/irq.h" // irq_disable +#include "board/misc.h" // timer_read_time + + +/**************************************************************** + * Low level timer code + ****************************************************************/ + +// Use 32bit TIM2 timer if available (otherwise use 16bit TIM3 timer) +#ifdef TIM2 +#define TIMx TIM2 +#define TIMx_IRQn TIM2_IRQn +#define HAVE_TIMER_32BIT 1 +#else +#define TIMx TIM3 +#define TIMx_IRQn TIM3_IRQn +#define HAVE_TIMER_32BIT 0 +#endif + +static inline uint32_t +timer_get(void) +{ + return TIMx->CNT; +} + +static inline void +timer_set(uint32_t next) +{ + TIMx->CCR1 = next; + TIMx->SR = 0; +} + +/**************************************************************** + * 16bit hardware timer to 32bit conversion + ****************************************************************/ + +// High bits of timer (top 17 bits) +static uint32_t timer_high = 0; + +// Return the current time (in absolute clock ticks). +uint32_t __always_inline +timer_read_time(void) +{ + if (HAVE_TIMER_32BIT) + return timer_get(); + uint32_t th = readl(&timer_high); + uint32_t cur = timer_get(); + // Combine timer_high (high 17 bits) and current time (low 16 + // bits) using method that handles rollovers correctly. + return (th ^ cur) + (th & 0xffff); +} + +/**************************************************************** + * Setup and irqs + ****************************************************************/ + +// Hardware timer IRQ handler - dispatch software timers +void __aligned(16) +TIMx_IRQHandler(void) +{ + irq_disable(); + timer_high += 0x8000; + timer_set(timer_high + 0x8000); + irq_enable(); +} + +void +timer_init(void) +{ + irqstatus_t flag = irq_save(); + enable_pclock((uint32_t)TIMx); + TIMx->CNT = 0; +#if !HAVE_TIMER_32BIT + TIMx->DIER = TIM_DIER_CC1IE; + TIMx->CCER = TIM_CCER_CC1E; + armcm_enable_irq(TIMx_IRQHandler, TIMx_IRQn, 2); + timer_set(0x8000); +#endif + TIMx->CR1 = TIM_CR1_CEN; + irq_restore(flag); +} + +// Return the number of clock ticks for a given number of microseconds +uint32_t +timer_from_us(uint32_t us) +{ + return us * (CONFIG_CLOCK_FREQ / 1000000); +} + +// Return true if time1 is before time2. Always use this function to +// compare times as regular C comparisons can fail if the counter +// rolls over. +uint8_t +timer_is_before(uint32_t time1, uint32_t time2) +{ + return (int32_t)(time1 - time2) < 0; +} + +// Implement simple early-boot delay mechanism +void +udelay(uint32_t usecs) +{ + uint32_t end = timer_read_time() + timer_from_us(usecs); + while (timer_is_before(timer_read_time(), end)) + ; +} \ No newline at end of file