mirror of
https://github.com/andreili/katapult.git
synced 2025-08-23 19:34:06 +02:00
stm32f0: intiial attempt at canboot support
Signed-off-by: Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
parent
292ef90dde
commit
4cd17a6f5e
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
115
src/stm32/stm32f0_timer.c
Normal 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))
|
||||
;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user