stm32f0: intiial attempt at canboot support

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Arksine 2021-02-07 12:46:15 -05:00
parent 292ef90dde
commit 4cd17a6f5e
5 changed files with 180 additions and 69 deletions

View File

@ -3,12 +3,16 @@
#include <stdarg.h> // va_list
#include <stdint.h> // 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);

View File

@ -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

View File

@ -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

View File

@ -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();
}

115
src/stm32/stm32f0_timer.c Normal file
View File

@ -0,0 +1,115 @@
// STM32F0 timer support
//
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
//
// 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))
;
}