src: update stm32 source

Bring in the latest changes from Klipper.  The STM32F4 variants are
still unsupported at this time.

Signed-off-by:  Eric Callahan <arksine.code@gmail.com>
This commit is contained in:
Eric Callahan 2022-04-11 19:59:56 -04:00
parent 73d7ddd5aa
commit 26b12a658b
No known key found for this signature in database
GPG Key ID: 7027245FBBDDF59A
10 changed files with 397 additions and 339 deletions

View File

@ -12,7 +12,7 @@ config CANSERIAL
bool bool
default y default y
config CANBUS_BAUD config CONFIG_CANBUS_FREQUENCY
int "CAN bus speed" int "CAN bus speed"
default 500000 default 500000

View File

@ -17,18 +17,27 @@ choice
config MACH_STM32F405 config MACH_STM32F405
bool "STM32F405" bool "STM32F405"
select MACH_STM32F4 select MACH_STM32F4
select MACH_STM32F4x5
config MACH_STM32F407 config MACH_STM32F407
bool "STM32F407" bool "STM32F407"
select MACH_STM32F4 select MACH_STM32F4
select MACH_STM32F4x5
config MACH_STM32F429
bool "STM32F429"
select MACH_STM32F4
select MACH_STM32F4x5
config MACH_STM32F446 config MACH_STM32F446
bool "STM32F446" bool "STM32F446"
select MACH_STM32F4 select MACH_STM32F4
config MACH_STM32F042 config MACH_STM32F042
bool "STM32F042" bool "STM32F042"
select MACH_STM32F0 select MACH_STM32F0
config MACH_STM32F070 select MACH_STM32F0x2
bool "STM32F070" config MACH_STM32F072
bool "STM32F072"
select MACH_STM32F0 select MACH_STM32F0
select MACH_STM32F0x2
endchoice endchoice
config MACH_STM32F0 config MACH_STM32F0
@ -43,11 +52,12 @@ config MACH_STM32F4
config MCU config MCU
string string
default "stm32f042x6" if MACH_STM32F042 default "stm32f042x6" if MACH_STM32F042
default "stm32f070xb" if MACH_STM32F070 default "stm32f072xb" if MACH_STM32F072
default "stm32f103xe" if MACH_STM32F103 default "stm32f103xe" if MACH_STM32F103
default "stm32f207xx" if MACH_STM32F207 default "stm32f207xx" if MACH_STM32F207
default "stm32f405xx" if MACH_STM32F405 default "stm32f405xx" if MACH_STM32F405
default "stm32f407xx" if MACH_STM32F407 default "stm32f407xx" if MACH_STM32F407
default "stm32f429xx" if MACH_STM32F429
default "stm32f446xx" if MACH_STM32F446 default "stm32f446xx" if MACH_STM32F446
config CLOCK_FREQ config CLOCK_FREQ
@ -56,13 +66,13 @@ config CLOCK_FREQ
default 64000000 if MACH_STM32F103 && STM32_CLOCK_REF_INTERNAL default 64000000 if MACH_STM32F103 && STM32_CLOCK_REF_INTERNAL
default 72000000 if MACH_STM32F103 default 72000000 if MACH_STM32F103
default 120000000 if MACH_STM32F207 default 120000000 if MACH_STM32F207
default 168000000 if MACH_STM32F405 || MACH_STM32F407 default 168000000 if MACH_STM32F4x5
default 180000000 if MACH_STM32F446 default 180000000 if MACH_STM32F446
config FLASH_SIZE config FLASH_SIZE
hex hex
default 0x8000 if MACH_STM32F042 default 0x8000 if MACH_STM32F042
default 0x20000 if MACH_STM32F070 default 0x20000 if MACH_STM32F072
default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB) default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB)
default 0x40000 if MACH_STM32F2 default 0x40000 if MACH_STM32F2
default 0x80000 if MACH_STM32F4 default 0x80000 if MACH_STM32F4
@ -74,7 +84,7 @@ config RAM_START
config RAM_SIZE config RAM_SIZE
hex hex
default 0x1800 if MACH_STM32F042 default 0x1800 if MACH_STM32F042
default 0x4000 if MACH_STM32F070 default 0x4000 if MACH_STM32F072
default 0x5000 if MACH_STM32F103 # Ram size of stm32f103x8 (20KiB) default 0x5000 if MACH_STM32F103 # Ram size of stm32f103x8 (20KiB)
default 0x20000 if MACH_STM32F207 default 0x20000 if MACH_STM32F207
default 0x20000 if MACH_STM32F4 default 0x20000 if MACH_STM32F4
@ -97,6 +107,16 @@ config ARMCM_RAM_VECTORTABLE
default y if MACH_STM32F0 && FLASH_START != 0x8000000 default y if MACH_STM32F0 && FLASH_START != 0x8000000
default n default n
config STM32F103GD_DISABLE_SWD
bool "Disable SWD at startup (for GigaDevice stm32f103 clones)"
depends on MACH_STM32F103
default n
help
The GigaDevice clone of the STM32F103 may not be able to
reliably disable SWD at run-time. This can prevent the PA13
and PA14 pins from being available. Selecting this option
disables SWD at startup and thus makes these pins available.
choice choice
prompt "Clock Reference" prompt "Clock Reference"
config STM32_CLOCK_REF_8M config STM32_CLOCK_REF_8M
@ -105,11 +125,14 @@ choice
bool "12 MHz crystal" bool "12 MHz crystal"
config STM32_CLOCK_REF_16M config STM32_CLOCK_REF_16M
bool "16 MHz crystal" bool "16 MHz crystal"
config STM32_CLOCK_REF_25M
bool "25 MHz crystal"
config STM32_CLOCK_REF_INTERNAL config STM32_CLOCK_REF_INTERNAL
bool "Internal clock" bool "Internal clock"
endchoice endchoice
config CLOCK_REF_FREQ config CLOCK_REF_FREQ
int int
default 25000000 if STM32_CLOCK_REF_25M
default 16000000 if STM32_CLOCK_REF_16M default 16000000 if STM32_CLOCK_REF_16M
default 12000000 if STM32_CLOCK_REF_12M default 12000000 if STM32_CLOCK_REF_12M
default 1 if STM32_CLOCK_REF_INTERNAL default 1 if STM32_CLOCK_REF_INTERNAL
@ -117,16 +140,20 @@ config CLOCK_REF_FREQ
choice choice
prompt "CAN pins" prompt "CAN pins"
config CAN_PINS_PA11_PA12 config STM32_CANBUS_PA11_PA12
bool "Pins PA11(rx) and PA12(tx)" bool "Pins PA11(rx) and PA12(tx)"
config CAN_PINS_PB8_PB9 config STM32_CANBUS_PA11_PA12_REMAP
bool "Pins on PA9(rx) and PA10(tx)" if MACH_STM32F042
config STM32_CANBUS_PB8_PB9
bool "Pins PB8(rx) and PB9(tx)" bool "Pins PB8(rx) and PB9(tx)"
config CAN_PINS_PI8_PH13 config STM32_CANBUS_PI9_PH13
bool "Pins PI8(rx) and PH13(tx)" if MACH_STM32F4 bool "Pins PI9(rx) and PH13(tx)" if MACH_STM32F4
config CAN_PINS_PB5_PB6 config STM32_CANBUS_PB5_PB6
bool "Pins PB5(rx) and PB6(tx)" if MACH_STM32F4 bool "Pins PB5(rx) and PB6(tx)" if MACH_STM32F4
config CAN_PINS_PB12_PB13 config STM32_CANBUS_PB12_PB13
bool "Pins PB12(rx) and PB13(tx)" if MACH_STM32F4 bool "Pins PB12(rx) and PB13(tx)" if MACH_STM32F4
config STM32_CANBUS_PD0_PD1
bool "Pins PD0(rx) and PD1(tx)"
endchoice endchoice
config STM32F0_TRIM config STM32F0_TRIM
@ -138,14 +165,6 @@ config STM32F0_TRIM
Default is 16 (use factory default). Each increment increases Default is 16 (use factory default). Each increment increases
the clock rate by ~240KHz. the clock rate by ~240KHz.
config STM32F042_PIN_SWAP
bool "Use PA9/PA10 for USB or CAN" if MACH_STM32F042
depends on MACH_STM32F042
default y if MACH_STM32F042
default n
help
Remaps logical pins PA11/PA12 to physical PA9/PA10 on low pincount F042 devices.
choice choice
depends on MACH_STM32F103 depends on MACH_STM32F103
prompt "Flash Page Size" prompt "Flash Page Size"

View File

@ -24,19 +24,22 @@ CFLAGS_canboot.elf += -T $(OUT)src/generic/armcm_link.ld
$(OUT)canboot.elf: $(OUT)src/generic/armcm_link.ld $(OUT)canboot.elf: $(OUT)src/generic/armcm_link.ld
# Add source files # Add source files
src-y += stm32/gpio.c stm32/flash.c src-y += stm32/gpio.c stm32/flash.c stm32/clockline.c
src-y += generic/armcm_boot.c generic/armcm_irq.c src-y += generic/armcm_boot.c generic/armcm_irq.c
src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c src-$(CONFIG_MACH_STM32F0) += ../lib/stm32f0/system_stm32f0xx.c
src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c stm32/stm32f0_timer.c src-$(CONFIG_MACH_STM32F0) += stm32/stm32f0.c stm32/stm32f0_timer.c
src-$(CONFIG_MACH_STM32F0) += stm32/gpioperiph.c
src-$(CONFIG_MACH_STM32F1) += ../lib/stm32f1/system_stm32f1xx.c src-$(CONFIG_MACH_STM32F1) += ../lib/stm32f1/system_stm32f1xx.c
src-$(CONFIG_MACH_STM32F1) += stm32/stm32f1.c generic/armcm_timer.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) += ../lib/stm32f2/system_stm32f2xx.c
src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32F2) += stm32/stm32f4.c generic/armcm_timer.c
src-$(CONFIG_MACH_STM32F2) += stm32/gpioperiph.c
src-$(CONFIG_MACH_STM32F4) += ../lib/stm32f4/system_stm32f4xx.c src-$(CONFIG_MACH_STM32F4) += ../lib/stm32f4/system_stm32f4xx.c
src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c generic/armcm_timer.c
src-$(CONFIG_MACH_STM32F4) += stm32/gpioperiph.c
can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c
src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/canbus.c src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/canbus.c

View File

@ -15,31 +15,36 @@
#include "internal.h" // enable_pclock #include "internal.h" // enable_pclock
#include "ctr.h" // DECL_CONSTANT_STR #include "ctr.h" // DECL_CONSTANT_STR
#if CONFIG_CAN_PINS_PA11_PA12 #if CONFIG_STM32_CANBUS_PA11_PA12 || CONFIG_STM32_CANBUS_PA11_PA12_REMAP
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PA11,PA12"); DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PA11,PA12");
#define GPIO_Rx GPIO('A', 11) #define GPIO_Rx GPIO('A', 11)
#define GPIO_Tx GPIO('A', 12) #define GPIO_Tx GPIO('A', 12)
#endif #endif
#if CONFIG_CAN_PINS_PB8_PB9 #if CONFIG_STM32_CANBUS_PB8_PB9
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB8,PB9"); DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB8,PB9");
#define GPIO_Rx GPIO('B', 8) #define GPIO_Rx GPIO('B', 8)
#define GPIO_Tx GPIO('B', 9) #define GPIO_Tx GPIO('B', 9)
#endif #endif
#if CONFIG_CAN_PINS_PI8_PH13 #if CONFIG_STM32_CANBUS_PI9_PH13
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PI8,PH13"); DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PI9,PH13");
#define GPIO_Rx GPIO('I', 8) #define GPIO_Rx GPIO('I', 9)
#define GPIO_Tx GPIO('H', 13) #define GPIO_Tx GPIO('H', 13)
#endif #endif
#if CONFIG_CAN_PINS_PB5_PB6 #if CONFIG_STM32_CANBUS_PB5_PB6
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB5,PB6"); DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB5,PB6");
#define GPIO_Rx GPIO('B', 5) #define GPIO_Rx GPIO('B', 5)
#define GPIO_Tx GPIO('B', 6) #define GPIO_Tx GPIO('B', 6)
#endif #endif
#if CONFIG_CAN_PINS_PB12_PB13 #if CONFIG_STM32_CANBUS_PB12_PB13
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB12,PB13"); DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PB12,PB13");
#define GPIO_Rx GPIO('B', 12) #define GPIO_Rx GPIO('B', 12)
#define GPIO_Tx GPIO('B', 13) #define GPIO_Tx GPIO('B', 13)
#endif #endif
#if CONFIG_STM32_CANBUS_PD0_PD1
DECL_CONSTANT_STR("RESERVE_PINS_CAN", "PD0,PD1");
#define GPIO_Rx GPIO('D', 0)
#define GPIO_Tx GPIO('D', 1)
#endif
#if CONFIG_MACH_STM32F0 #if CONFIG_MACH_STM32F0
#define SOC_CAN CAN #define SOC_CAN CAN
@ -61,14 +66,14 @@
#if CONFIG_MACH_STM32F4 #if CONFIG_MACH_STM32F4
#warning CAN on STM32F4 is untested #warning CAN on STM32F4 is untested
#if (CONFIG_CAN_PINS_PA11_PA12 || CONFIG_CAN_PINS_PB8_PB9 \ #if (CONFIG_STM32_CANBUS_PA11_PA12 || CONFIG_STM32_CANBUS_PB8_PB9 \
|| CONFIG_CAN_PINS_PI8_PH13) || CONFIG_STM32_CANBUS_PD0_PD1 || CONFIG_STM32_CANBUS_PI9_PH13)
#define SOC_CAN CAN1 #define SOC_CAN CAN1
#define CAN_RX0_IRQn CAN1_RX0_IRQn #define CAN_RX0_IRQn CAN1_RX0_IRQn
#define CAN_RX1_IRQn CAN1_RX1_IRQn #define CAN_RX1_IRQn CAN1_RX1_IRQn
#define CAN_TX_IRQn CAN1_TX_IRQn #define CAN_TX_IRQn CAN1_TX_IRQn
#define CAN_SCE_IRQn CAN1_SCE_IRQn #define CAN_SCE_IRQn CAN1_SCE_IRQn
#elif CONFIG_CAN_PINS_PB5_PB6 || CONFIG_CAN_PINS_PB12_PB13 #elif CONFIG_STM32_CANBUS_PB5_PB6 || CONFIG_STM32_CANBUS_PB12_PB13
#define SOC_CAN CAN2 #define SOC_CAN CAN2
#define CAN_RX0_IRQn CAN2_RX0_IRQn #define CAN_RX0_IRQn CAN2_RX0_IRQn
#define CAN_RX1_IRQn CAN2_RX1_IRQn #define CAN_RX1_IRQn CAN2_RX1_IRQn
@ -152,62 +157,64 @@ canbus_send(uint32_t id, uint32_t len, uint8_t *data)
return len; return len;
} }
#define CAN_FILTER_NUMBER 0
// Setup the receive packet filter // Setup the receive packet filter
static void void
can_set_filter(uint32_t id1, uint32_t id2) canbus_set_filter(uint32_t id)
{ {
uint32_t filternbrbitpos = 1 << CAN_FILTER_NUMBER;
/* Select the start slave bank */ /* Select the start slave bank */
SOC_CAN->FMR |= CAN_FMR_FINIT; SOC_CAN->FMR |= CAN_FMR_FINIT;
/* Initialisation mode for the filter */ /* Initialisation mode for the filter */
SOC_CAN->FA1R = 0; SOC_CAN->FA1R = 0;
SOC_CAN->sFilterRegister[CAN_FILTER_NUMBER].FR1 = id1 << (5 + 16); uint32_t mask = CAN_RI0R_STID | CAN_TI0R_IDE | CAN_TI0R_RTR;
SOC_CAN->sFilterRegister[CAN_FILTER_NUMBER].FR2 = id2 << (5 + 16); SOC_CAN->sFilterRegister[0].FR1 = CANBUS_ID_ADMIN << CAN_RI0R_STID_Pos;
SOC_CAN->sFilterRegister[0].FR2 = mask;
SOC_CAN->sFilterRegister[1].FR1 = (id + 1) << CAN_RI0R_STID_Pos;
SOC_CAN->sFilterRegister[1].FR2 = mask;
SOC_CAN->sFilterRegister[2].FR1 = id << CAN_RI0R_STID_Pos;
SOC_CAN->sFilterRegister[2].FR2 = mask;
/* Identifier list mode for the filter */
SOC_CAN->FM1R = filternbrbitpos;
/* 32-bit scale for the filter */ /* 32-bit scale for the filter */
SOC_CAN->FS1R = filternbrbitpos; SOC_CAN->FS1R = (1<<0) | (1<<1) | (1<<2);
/* FIFO 0 assigned for the filter */ /* FIFO 1 assigned to 'id' */
SOC_CAN->FFA1R = 0; SOC_CAN->FFA1R = (1<<2);
/* Filter activation */ /* Filter activation */
SOC_CAN->FA1R = filternbrbitpos; SOC_CAN->FA1R = (1<<0) | (id ? (1<<1) | (1<<2) : 0);
/* Leave the initialisation mode for the filter */ /* Leave the initialisation mode for the filter */
SOC_CAN->FMR &= ~CAN_FMR_FINIT; SOC_CAN->FMR &= ~CAN_FMR_FINIT;
} }
void
canbus_set_dataport(uint32_t id)
{
can_set_filter(CANBUS_ID_UUID, id);
}
void
canbus_reboot(void)
{
NVIC_SystemReset();
}
// This function handles CAN global interrupts // This function handles CAN global interrupts
void void
CAN_IRQHandler(void) CAN_IRQHandler(void)
{ {
if (SOC_CAN->RF0R & CAN_RF0R_FMP0) { if (SOC_CAN->RF1R & CAN_RF1R_FMP1) {
// Rx // Read and ack data packet
SOC_CAN->IER &= ~CAN_IER_FMPIE0; CAN_FIFOMailBox_TypeDef *mb = &SOC_CAN->sFIFOMailBox[1];
canbus_notify_rx(); uint32_t rir_id = (mb->RIR >> CAN_RI0R_STID_Pos) & 0x7FF;
uint32_t dlc = mb->RDTR & CAN_RDT0R_DLC;
uint32_t rdlr = mb->RDLR, rdhr = mb->RDHR;
SOC_CAN->RF1R = CAN_RF1R_RFOM1;
// Process packet
union {
struct { uint32_t rdlr, rdhr; };
uint8_t data[8];
} rdata = { .rdlr = rdlr, .rdhr = rdhr };
canbus_process_data(rir_id, dlc, rdata.data);
} }
uint32_t ier = SOC_CAN->IER; uint32_t ier = SOC_CAN->IER;
if (ier & CAN_IER_FMPIE0 && SOC_CAN->RF0R & CAN_RF0R_FMP0) {
// Admin Rx
SOC_CAN->IER = ier = ier & ~CAN_IER_FMPIE0;
canbus_notify_rx();
}
if (ier & CAN_IER_TMEIE if (ier & CAN_IER_TMEIE
&& SOC_CAN->TSR & (CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2)) { && SOC_CAN->TSR & (CAN_TSR_RQCP0|CAN_TSR_RQCP1|CAN_TSR_RQCP2)) {
// Tx // Tx
SOC_CAN->IER &= ~CAN_IER_TMEIE; SOC_CAN->IER = ier & ~CAN_IER_TMEIE;
canbus_notify_tx(); canbus_notify_tx();
} }
} }
@ -260,6 +267,12 @@ compute_btr(uint32_t pclock, uint32_t bitrate)
return make_btr(sjw, time_seg1, time_seg2, brp); return make_btr(sjw, time_seg1, time_seg2, brp);
} }
void
canbus_reboot(void)
{
NVIC_SystemReset();
}
void void
can_init(void) can_init(void)
{ {
@ -270,7 +283,7 @@ can_init(void)
uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN); uint32_t pclock = get_pclock_frequency((uint32_t)SOC_CAN);
uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_BAUD); uint32_t btr = compute_btr(pclock, CONFIG_CANBUS_FREQUENCY);
/*##-1- Configure the CAN #######################################*/ /*##-1- Configure the CAN #######################################*/
@ -290,17 +303,15 @@ can_init(void)
; ;
/*##-2- Configure the CAN Filter #######################################*/ /*##-2- Configure the CAN Filter #######################################*/
can_set_filter(CANBUS_ID_UUID, CANBUS_ID_SET); canbus_set_filter(0);
/*##-3- Configure Interrupts #################################*/ /*##-3- Configure Interrupts #################################*/
SOC_CAN->IER = CAN_IER_FMPIE0; // RX mailbox IRQ
armcm_enable_irq(CAN_IRQHandler, CAN_RX0_IRQn, 0); armcm_enable_irq(CAN_IRQHandler, CAN_RX0_IRQn, 0);
if (CAN_RX0_IRQn != CAN_RX1_IRQn) if (CAN_RX0_IRQn != CAN_RX1_IRQn)
armcm_enable_irq(CAN_IRQHandler, CAN_RX1_IRQn, 0); armcm_enable_irq(CAN_IRQHandler, CAN_RX1_IRQn, 0);
if (CAN_RX0_IRQn != CAN_TX_IRQn) if (CAN_RX0_IRQn != CAN_TX_IRQn)
armcm_enable_irq(CAN_IRQHandler, CAN_TX_IRQn, 0); armcm_enable_irq(CAN_IRQHandler, CAN_TX_IRQn, 0);
SOC_CAN->IER = CAN_IER_FMPIE1;
// Convert unique 96-bit chip id into 48 bit representation // Convert unique 96-bit chip id into 48 bit representation
uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7); uint64_t hash = fasthash64((uint8_t*)UID_BASE, 12, 0xA16231A7);

32
src/stm32/clockline.c Normal file
View File

@ -0,0 +1,32 @@
// Code to enable clock lines on stm32
//
// Copyright (C) 2021 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "board/irq.h" // irq_save
#include "internal.h" // struct cline
// Enable a peripheral clock
void
enable_pclock(uint32_t periph_base)
{
struct cline cl = lookup_clock_line(periph_base);
irqstatus_t flag = irq_save();
*cl.en |= cl.bit;
*cl.en; // Pause 2 cycles to ensure peripheral is enabled
if (cl.rst) {
// Reset peripheral
*cl.rst = cl.bit;
*cl.rst = 0;
}
irq_restore(flag);
}
// Check if a peripheral clock has been enabled
int
is_enabled_pclock(uint32_t periph_base)
{
struct cline cl = lookup_clock_line(periph_base);
return *cl.en & cl.bit;
}

38
src/stm32/gpioperiph.c Normal file
View File

@ -0,0 +1,38 @@
// Code to setup gpio on stm32 chip (except for stm32f1)
//
// Copyright (C) 2019-2021 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
#include "internal.h" // gpio_peripheral
// Set the mode and extended function of a pin
void
gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
{
GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)];
// Enable GPIO clock
gpio_clock_enable(regs);
// Configure GPIO
uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8;
uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0;
uint32_t pos = gpio % 16, af_reg = pos / 8;
uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift;
uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift;
regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift);
regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift);
regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift);
regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos);
// Setup OSPEEDR:
// stm32f0 is ~10Mhz at 50pF
// stm32f2 is ~25Mhz at 40pF
// stm32f4 is ~50Mhz at 40pF
// stm32g0 is ~30Mhz at 50pF
// stm32h7 is ~85Mhz at 50pF
uint32_t ospeed = CONFIG_MACH_STM32F0 ? 0x01 : 0x02;
regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (ospeed << m_shift);
}

View File

@ -12,24 +12,34 @@
#include "stm32f2xx.h" #include "stm32f2xx.h"
#elif CONFIG_MACH_STM32F4 #elif CONFIG_MACH_STM32F4
#include "stm32f4xx.h" #include "stm32f4xx.h"
#elif CONFIG_MACH_STM32G0
#include "stm32g0xx.h"
#elif CONFIG_MACH_STM32H7
#include "stm32h7xx.h"
#endif #endif
// gpio.c
extern GPIO_TypeDef * const digital_regs[]; extern GPIO_TypeDef * const digital_regs[];
#define GPIO(PORT, NUM) (((PORT)-'A') * 16 + (NUM)) #define GPIO(PORT, NUM) (((PORT)-'A') * 16 + (NUM))
#define GPIO2PORT(PIN) ((PIN) / 16) #define GPIO2PORT(PIN) ((PIN) / 16)
#define GPIO2BIT(PIN) (1<<((PIN) % 16)) #define GPIO2BIT(PIN) (1<<((PIN) % 16))
// gpioperiph.c
#define GPIO_INPUT 0 #define GPIO_INPUT 0
#define GPIO_OUTPUT 1 #define GPIO_OUTPUT 1
#define GPIO_OPEN_DRAIN 0x100 #define GPIO_OPEN_DRAIN 0x100
#define GPIO_FUNCTION(fn) (2 | ((fn) << 4)) #define GPIO_FUNCTION(fn) (2 | ((fn) << 4))
#define GPIO_ANALOG 3 #define GPIO_ANALOG 3
void enable_pclock(uint32_t periph_base);
int is_enabled_pclock(uint32_t periph_base);
uint32_t get_pclock_frequency(uint32_t periph_base);
void gpio_clock_enable(GPIO_TypeDef *regs);
void gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup); void gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup);
// clockline.c
void enable_pclock(uint32_t periph_base);
int is_enabled_pclock(uint32_t periph_base);
// stm32??.c
struct cline { volatile uint32_t *en, *rst; uint32_t bit; };
struct cline lookup_clock_line(uint32_t periph_base);
uint32_t get_pclock_frequency(uint32_t periph_base);
void gpio_clock_enable(GPIO_TypeDef *regs);
#endif // internal.h #endif // internal.h

View File

@ -1,6 +1,6 @@
// Code to setup clocks and gpio on stm32f0 // Code to setup clocks on stm32f0
// //
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net> // Copyright (C) 2019-2021 Kevin O'Connor <kevin@koconnor.net>
// //
// This file may be distributed under the terms of the GNU GPLv3 license. // This file may be distributed under the terms of the GNU GPLv3 license.
@ -13,38 +13,19 @@
#define FREQ_PERIPH 48000000 #define FREQ_PERIPH 48000000
// Enable a peripheral clock // Map a peripheral address to its enable bits
void struct cline
enable_pclock(uint32_t periph_base) lookup_clock_line(uint32_t periph_base)
{ {
if (periph_base < SYSCFG_BASE) { if (periph_base >= AHB2PERIPH_BASE) {
uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400; uint32_t bit = 1 << ((periph_base - AHB2PERIPH_BASE) / 0x400 + 17);
RCC->APB1ENR |= 1 << pos; return (struct cline){.en=&RCC->AHBENR, .rst=&RCC->AHBRSTR, .bit=bit};
RCC->APB1ENR; } else if (periph_base >= SYSCFG_BASE) {
} else if (periph_base < AHBPERIPH_BASE) { uint32_t bit = 1 << ((periph_base - SYSCFG_BASE) / 0x400);
uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400; return (struct cline){.en=&RCC->APB2ENR, .rst=&RCC->APB2RSTR, .bit=bit};
RCC->APB2ENR |= 1 << pos;
RCC->APB2ENR;
} else { } else {
uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400; uint32_t bit = 1 << ((periph_base - APBPERIPH_BASE) / 0x400);
RCC->AHBENR |= 1 << (pos + 17); return (struct cline){.en=&RCC->APB1ENR, .rst=&RCC->APB1RSTR, .bit=bit};
RCC->AHBENR;
}
}
// Check if a peripheral clock has been enabled
int
is_enabled_pclock(uint32_t periph_base)
{
if (periph_base < SYSCFG_BASE) {
uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400;
return RCC->APB1ENR & (1 << pos);
} else if (periph_base < AHBPERIPH_BASE) {
uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400;
return RCC->APB2ENR & (1 << pos);
} else {
uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400;
return RCC->AHBENR & (1 << (pos + 17));
} }
} }
@ -64,41 +45,6 @@ gpio_clock_enable(GPIO_TypeDef *regs)
RCC->AHBENR; RCC->AHBENR;
} }
// Set the mode and extended function of a pin
void
gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
{
GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)];
// Enable GPIO clock
gpio_clock_enable(regs);
// Configure GPIO
uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8;
uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0;
uint32_t pos = gpio % 16, af_reg = pos / 8;
uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift;
uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift;
regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift);
regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift);
regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift);
regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos);
regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (0x02 << m_shift);
}
#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 1024)
#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT"
// Handle USB reboot requests
void
usb_request_bootloader(void)
{
irq_disable();
*(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG;
NVIC_SystemReset();
}
// Configure and enable the PLL as clock source // Configure and enable the PLL as clock source
static void static void
pll_setup(void) pll_setup(void)
@ -160,7 +106,7 @@ armcm_main(void)
// Support pin remapping USB/CAN pins on low pinout stm32f042 // Support pin remapping USB/CAN pins on low pinout stm32f042
#ifdef SYSCFG_CFGR1_PA11_PA12_RMP #ifdef SYSCFG_CFGR1_PA11_PA12_RMP
if (CONFIG_STM32F042_PIN_SWAP) { if (CONFIG_STM32_CANBUS_PA11_PA12_REMAP) {
enable_pclock(SYSCFG_BASE); enable_pclock(SYSCFG_BASE);
SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP; SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
} }

View File

@ -1,6 +1,6 @@
// Code to setup clocks and gpio on stm32f1 // Code to setup clocks and gpio on stm32f1
// //
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net> // Copyright (C) 2019-2021 Kevin O'Connor <kevin@koconnor.net>
// //
// This file may be distributed under the terms of the GNU GPLv3 license. // This file may be distributed under the terms of the GNU GPLv3 license.
@ -13,38 +13,19 @@
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2) #define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2)
// Enable a peripheral clock // Map a peripheral address to its enable bits
void struct cline
enable_pclock(uint32_t periph_base) lookup_clock_line(uint32_t periph_base)
{ {
if (periph_base < APB2PERIPH_BASE) { if (periph_base >= AHBPERIPH_BASE) {
uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; uint32_t bit = 1 << ((periph_base - AHBPERIPH_BASE) / 0x400);
RCC->APB1ENR |= (1<<pos); return (struct cline){.en=&RCC->AHBENR, .bit=bit};
RCC->APB1ENR; } else if (periph_base >= APB2PERIPH_BASE) {
} else if (periph_base < AHBPERIPH_BASE) { uint32_t bit = 1 << ((periph_base - APB2PERIPH_BASE) / 0x400);
uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400; return (struct cline){.en=&RCC->APB2ENR, .rst=&RCC->APB2RSTR, .bit=bit};
RCC->APB2ENR |= (1<<pos);
RCC->APB2ENR;
} else { } else {
uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400; uint32_t bit = 1 << ((periph_base - APB1PERIPH_BASE) / 0x400);
RCC->AHBENR |= (1<<pos); return (struct cline){.en=&RCC->APB1ENR, .rst=&RCC->APB1RSTR, .bit=bit};
RCC->AHBENR;
}
}
// Check if a peripheral clock has been enabled
int
is_enabled_pclock(uint32_t periph_base)
{
if (periph_base < APB2PERIPH_BASE) {
uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400;
return RCC->APB1ENR & (1<<pos);
} else if (periph_base < AHBPERIPH_BASE) {
uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400;
return RCC->APB2ENR & (1<<pos);
} else {
uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400;
return RCC->AHBENR & (1<<pos);
} }
} }
@ -64,74 +45,6 @@ gpio_clock_enable(GPIO_TypeDef *regs)
RCC->APB2ENR; RCC->APB2ENR;
} }
static void stm32f1_alternative_remap(uint32_t mapr_mask, uint32_t mapr_value)
{
// The MAPR register is a mix of write only and r/w bits
// We have to save the written values in a global variable
static uint32_t mapr = 0;
mapr &= ~mapr_mask;
mapr |= mapr_value;
AFIO->MAPR = mapr;
}
// Set the mode and extended function of a pin
void
gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
{
GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)];
// Enable GPIO clock
gpio_clock_enable(regs);
// Configure GPIO
uint32_t pos = gpio % 16, shift = (pos % 8) * 4, msk = 0xf << shift, cfg;
if (mode == GPIO_INPUT) {
cfg = pullup ? 0x8 : 0x4;
} else if (mode == GPIO_OUTPUT) {
cfg = 0x1;
} else if (mode == (GPIO_OUTPUT | GPIO_OPEN_DRAIN)) {
cfg = 0x5;
} else if (mode == GPIO_ANALOG) {
cfg = 0x0;
} else {
if (mode & GPIO_OPEN_DRAIN)
// Alternate function with open-drain mode
cfg = 0xd;
else if (pullup > 0)
// Alternate function input pins use GPIO_INPUT mode on the stm32f1
cfg = 0x8;
else
cfg = 0x9;
}
if (pos & 0x8)
regs->CRH = (regs->CRH & ~msk) | (cfg << shift);
else
regs->CRL = (regs->CRL & ~msk) | (cfg << shift);
if (pullup > 0)
regs->BSRR = 1 << pos;
else if (pullup < 0)
regs->BSRR = 1 << (pos + 16);
if (gpio == GPIO('A', 13) || gpio == GPIO('A', 14))
// Disable SWD to free PA13, PA14
stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk,
AFIO_MAPR_SWJ_CFG_DISABLE);
// STM32F1 remaps functions to pins in a very different
// way from other STM32s.
// Code below is emulating a few mappings to work like an STM32F4
uint32_t func = (mode >> 4) & 0xf;
if(( gpio == GPIO('B', 8) || gpio == GPIO('B', 9)) &&
func == 9) { // CAN
stm32f1_alternative_remap(AFIO_MAPR_CAN_REMAP_Msk,
AFIO_MAPR_CAN_REMAP_REMAP2);
}
// Add more as needed
}
// Main clock setup called at chip startup // Main clock setup called at chip startup
static void static void
clock_setup(void) clock_setup(void)
@ -140,9 +53,14 @@ clock_setup(void)
uint32_t cfgr; uint32_t cfgr;
if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { if (!CONFIG_STM32_CLOCK_REF_INTERNAL) {
// Configure 72Mhz PLL from external crystal (HSE) // Configure 72Mhz PLL from external crystal (HSE)
uint32_t div = CONFIG_CLOCK_FREQ / CONFIG_CLOCK_REF_FREQ;
RCC->CR |= RCC_CR_HSEON; RCC->CR |= RCC_CR_HSEON;
cfgr = (1 << RCC_CFGR_PLLSRC_Pos) | ((div - 2) << RCC_CFGR_PLLMULL_Pos); uint32_t div = CONFIG_CLOCK_FREQ / (CONFIG_CLOCK_REF_FREQ / 2);
cfgr = 1 << RCC_CFGR_PLLSRC_Pos;
if ((div & 1) && div <= 16)
cfgr |= RCC_CFGR_PLLXTPRE_HSE_DIV2;
else
div /= 2;
cfgr |= (div - 2) << RCC_CFGR_PLLMULL_Pos;
} else { } else {
// Configure 72Mhz PLL from internal 8Mhz oscillator (HSI) // Configure 72Mhz PLL from internal 8Mhz oscillator (HSI)
uint32_t div2 = (CONFIG_CLOCK_FREQ / 8000000) * 2; uint32_t div2 = (CONFIG_CLOCK_FREQ / 8000000) * 2;
@ -166,6 +84,131 @@ clock_setup(void)
; ;
} }
/****************************************************************
* GPIO setup
****************************************************************/
static void
stm32f1_alternative_remap(uint32_t mapr_mask, uint32_t mapr_value)
{
// The MAPR register is a mix of write only and r/w bits
// We have to save the written values in a global variable
static uint32_t mapr = 0;
mapr &= ~mapr_mask;
mapr |= mapr_value;
AFIO->MAPR = mapr;
}
#define STM_OSPEED 0x1 // ~10Mhz at 50pF
// Set the mode and extended function of a pin
void
gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
{
GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)];
// Enable GPIO clock
gpio_clock_enable(regs);
// Configure GPIO
uint32_t pos = gpio % 16, shift = (pos % 8) * 4, msk = 0xf << shift, cfg;
if (mode == GPIO_INPUT) {
cfg = pullup ? 0x8 : 0x4;
} else if (mode == GPIO_OUTPUT) {
cfg = STM_OSPEED;
} else if (mode == (GPIO_OUTPUT | GPIO_OPEN_DRAIN)) {
cfg = 0x4 | STM_OSPEED;
} else if (mode == GPIO_ANALOG) {
cfg = 0x0;
} else {
if (mode & GPIO_OPEN_DRAIN)
// Alternate function with open-drain mode
cfg = 0xc | STM_OSPEED;
else if (pullup > 0)
// Alternate function input pins use GPIO_INPUT mode on the stm32f1
cfg = 0x8;
else
cfg = 0x8 | STM_OSPEED;
}
if (pos & 0x8)
regs->CRH = (regs->CRH & ~msk) | (cfg << shift);
else
regs->CRL = (regs->CRL & ~msk) | (cfg << shift);
if (pullup > 0)
regs->BSRR = 1 << pos;
else if (pullup < 0)
regs->BSRR = 1 << (pos + 16);
if (gpio == GPIO('A', 13) || gpio == GPIO('A', 14))
// Disable SWD to free PA13, PA14
stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk,
AFIO_MAPR_SWJ_CFG_DISABLE);
// STM32F1 remaps functions to pins in a very different
// way from other STM32s.
// Code below is emulating a few mappings to work like an STM32F4
uint32_t func = (mode >> 4) & 0xf;
if (func == 1) {
// TIM2
if (gpio == GPIO('A', 15) || gpio == GPIO('B', 3))
stm32f1_alternative_remap(AFIO_MAPR_TIM2_REMAP_Msk,
AFIO_MAPR_TIM2_REMAP_PARTIALREMAP1);
else if (gpio == GPIO('B', 10) || gpio == GPIO('B', 11))
stm32f1_alternative_remap(AFIO_MAPR_TIM2_REMAP_Msk,
AFIO_MAPR_TIM2_REMAP_PARTIALREMAP2);
} else if (func == 2) {
// TIM3 and TIM4
if (gpio == GPIO('B', 4) || gpio == GPIO('B', 5))
stm32f1_alternative_remap(AFIO_MAPR_TIM3_REMAP_Msk,
AFIO_MAPR_TIM3_REMAP_PARTIALREMAP);
else if (gpio == GPIO('C', 6) || gpio == GPIO('C', 7)
|| gpio == GPIO('C', 8) || gpio == GPIO('C', 9))
stm32f1_alternative_remap(AFIO_MAPR_TIM3_REMAP_Msk,
AFIO_MAPR_TIM3_REMAP_FULLREMAP);
else if (gpio == GPIO('D', 12) || gpio == GPIO('D', 13)
|| gpio == GPIO('D', 14) || gpio == GPIO('D', 15))
stm32f1_alternative_remap(AFIO_MAPR_TIM4_REMAP_Msk,
AFIO_MAPR_TIM4_REMAP);
} else if (func == 4) {
// I2C
if (gpio == GPIO('B', 8) || gpio == GPIO('B', 9))
stm32f1_alternative_remap(AFIO_MAPR_I2C1_REMAP_Msk,
AFIO_MAPR_I2C1_REMAP);
} else if (func == 5) {
// SPI
if (gpio == GPIO('B', 3) || gpio == GPIO('B', 4)
|| gpio == GPIO('B', 5))
stm32f1_alternative_remap(AFIO_MAPR_SPI1_REMAP_Msk,
AFIO_MAPR_SPI1_REMAP);
} else if (func == 7) {
// USART
if (gpio == GPIO('B', 6) || gpio == GPIO('B', 7))
stm32f1_alternative_remap(AFIO_MAPR_USART1_REMAP_Msk,
AFIO_MAPR_USART1_REMAP);
else if (gpio == GPIO('D', 5) || gpio == GPIO('D', 6))
stm32f1_alternative_remap(AFIO_MAPR_USART2_REMAP_Msk,
AFIO_MAPR_USART2_REMAP);
else if (gpio == GPIO('D', 8) || gpio == GPIO('D', 9))
stm32f1_alternative_remap(AFIO_MAPR_USART3_REMAP_Msk,
AFIO_MAPR_USART3_REMAP_FULLREMAP);
} else if (func == 9) {
// CAN
if (gpio == GPIO('B', 8) || gpio == GPIO('B', 9))
stm32f1_alternative_remap(AFIO_MAPR_CAN_REMAP_Msk,
AFIO_MAPR_CAN_REMAP_REMAP2);
if (gpio == GPIO('D', 0) || gpio == GPIO('D', 1))
stm32f1_alternative_remap(AFIO_MAPR_CAN_REMAP_Msk,
AFIO_MAPR_CAN_REMAP_REMAP3);
}
}
/****************************************************************
* Startup
****************************************************************/
// Main entry point - called from armcm_boot.c:ResetHandler() // Main entry point - called from armcm_boot.c:ResetHandler()
void void
armcm_main(void) armcm_main(void)
@ -174,7 +217,7 @@ armcm_main(void)
SystemInit(); SystemInit();
SCB->VTOR = (uint32_t)VectorTable; SCB->VTOR = (uint32_t)VectorTable;
// Reset peripheral clocks // Reset peripheral clocks (for some bootloaders that don't)
RCC->AHBENR = 0x14; RCC->AHBENR = 0x14;
RCC->APB1ENR = 0; RCC->APB1ENR = 0;
RCC->APB2ENR = 0; RCC->APB2ENR = 0;
@ -184,8 +227,13 @@ armcm_main(void)
// Disable JTAG to free PA15, PB3, PB4 // Disable JTAG to free PA15, PB3, PB4
enable_pclock(AFIO_BASE); enable_pclock(AFIO_BASE);
stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk, if (CONFIG_STM32F103GD_DISABLE_SWD)
AFIO_MAPR_SWJ_CFG_JTAGDISABLE); // GigaDevice clone can't enable PA13/PA14 at runtime - enable here
stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk,
AFIO_MAPR_SWJ_CFG_DISABLE);
else
stm32f1_alternative_remap(AFIO_MAPR_SWJ_CFG_Msk,
AFIO_MAPR_SWJ_CFG_JTAGDISABLE);
canboot_main(); canboot_main();
} }

View File

@ -1,6 +1,6 @@
// Code to setup clocks and gpio on stm32f2/stm32f4 // Code to setup clocks on stm32f2/stm32f4
// //
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net> // Copyright (C) 2019-2021 Kevin O'Connor <kevin@koconnor.net>
// //
// This file may be distributed under the terms of the GNU GPLv3 license. // This file may be distributed under the terms of the GNU GPLv3 license.
@ -11,45 +11,34 @@
#include "internal.h" // enable_pclock #include "internal.h" // enable_pclock
#include "canboot_main.h" // sched_main #include "canboot_main.h" // sched_main
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 4)
/****************************************************************
* Clock setup
****************************************************************/
#define FREQ_PERIPH_DIV (CONFIG_MACH_STM32F401 ? 2 : 4)
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / FREQ_PERIPH_DIV)
#define FREQ_USB 48000000 #define FREQ_USB 48000000
// Enable a peripheral clock // Map a peripheral address to its enable bits
void struct cline
enable_pclock(uint32_t periph_base) lookup_clock_line(uint32_t periph_base)
{ {
if (periph_base < APB2PERIPH_BASE) { if (periph_base >= AHB1PERIPH_BASE) {
uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; uint32_t bit = 1 << ((periph_base - AHB1PERIPH_BASE) / 0x400);
RCC->APB1ENR |= (1<<pos); return (struct cline){.en=&RCC->AHB1ENR, .rst=&RCC->AHB1RSTR, .bit=bit};
RCC->APB1ENR; } else if (periph_base >= APB2PERIPH_BASE) {
} else if (periph_base < AHB1PERIPH_BASE) { uint32_t bit = 1 << ((periph_base - APB2PERIPH_BASE) / 0x400);
uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400; if (bit & 0x700)
RCC->APB2ENR |= (1<<pos); // Skip ADC peripheral reset as they share a bit
RCC->APB2ENR; return (struct cline){.en=&RCC->APB2ENR, .bit=bit};
} else if (periph_base < AHB2PERIPH_BASE) { return (struct cline){.en=&RCC->APB2ENR, .rst=&RCC->APB2RSTR, .bit=bit};
uint32_t pos = (periph_base - AHB1PERIPH_BASE) / 0x400; } else {
RCC->AHB1ENR |= (1<<pos); uint32_t bit = 1 << ((periph_base - APB1PERIPH_BASE) / 0x400);
RCC->AHB1ENR; return (struct cline){.en=&RCC->APB1ENR, .rst=&RCC->APB1RSTR, .bit=bit};
} }
} }
// Check if a peripheral clock has been enabled
int
is_enabled_pclock(uint32_t periph_base)
{
if (periph_base < APB2PERIPH_BASE) {
uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400;
return RCC->APB1ENR & (1<<pos);
} else if (periph_base < AHB1PERIPH_BASE) {
uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400;
return RCC->APB2ENR & (1<<pos);
} else if (periph_base < AHB2PERIPH_BASE) {
uint32_t pos = (periph_base - AHB1PERIPH_BASE) / 0x400;
return RCC->AHB1ENR & (1<<pos);
}
return 0;
}
// Return the frequency of the given peripheral clock // Return the frequency of the given peripheral clock
uint32_t uint32_t
get_pclock_frequency(uint32_t periph_base) get_pclock_frequency(uint32_t periph_base)
@ -66,52 +55,6 @@ gpio_clock_enable(GPIO_TypeDef *regs)
RCC->AHB1ENR; RCC->AHB1ENR;
} }
// Set the mode and extended function of a pin
void
gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
{
GPIO_TypeDef *regs = digital_regs[GPIO2PORT(gpio)];
// Enable GPIO clock
gpio_clock_enable(regs);
// Configure GPIO
uint32_t mode_bits = mode & 0xf, func = (mode >> 4) & 0xf, od = mode >> 8;
uint32_t pup = pullup ? (pullup > 0 ? 1 : 2) : 0;
uint32_t pos = gpio % 16, af_reg = pos / 8;
uint32_t af_shift = (pos % 8) * 4, af_msk = 0x0f << af_shift;
uint32_t m_shift = pos * 2, m_msk = 0x03 << m_shift;
regs->AFR[af_reg] = (regs->AFR[af_reg] & ~af_msk) | (func << af_shift);
regs->MODER = (regs->MODER & ~m_msk) | (mode_bits << m_shift);
regs->PUPDR = (regs->PUPDR & ~m_msk) | (pup << m_shift);
regs->OTYPER = (regs->OTYPER & ~(1 << pos)) | (od << pos);
regs->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (0x02 << m_shift);
}
#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 4096)
#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT"
// Handle USB reboot requests
void
usb_request_bootloader(void)
{
irq_disable();
if (CONFIG_STM32_FLASH_START_4000) {
// HID Bootloader
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
RCC->APB1ENR;
PWR->CR |= PWR_CR_DBP;
// HID Bootloader magic key
RTC->BKP4R = 0x424C;
PWR->CR &= ~PWR_CR_DBP;
} else {
// System DFU Bootloader
*(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG;
}
NVIC_SystemReset();
}
// Clock configuration // Clock configuration
static void static void
enable_clock_stm32f20x(void) enable_clock_stm32f20x(void)
@ -138,8 +81,10 @@ enable_clock_stm32f20x(void)
static void static void
enable_clock_stm32f40x(void) enable_clock_stm32f40x(void)
{ {
#if CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407 #if CONFIG_MACH_STM32F401 || CONFIG_MACH_STM32F4x5
uint32_t pll_base = 2000000, pll_freq = CONFIG_CLOCK_FREQ * 2, pllcfgr; uint32_t pll_base = (CONFIG_STM32_CLOCK_REF_25M) ? 1000000 : 2000000;
uint32_t pllp = (CONFIG_MACH_STM32F401) ? 4 : 2;
uint32_t pll_freq = CONFIG_CLOCK_FREQ * pllp, pllcfgr;
if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { if (!CONFIG_STM32_CLOCK_REF_INTERNAL) {
// Configure 168Mhz PLL from external crystal (HSE) // Configure 168Mhz PLL from external crystal (HSE)
uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base; uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base;
@ -151,7 +96,7 @@ enable_clock_stm32f40x(void)
pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos); pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | (div << RCC_PLLCFGR_PLLM_Pos);
} }
RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos) RCC->PLLCFGR = (pllcfgr | ((pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos)
| (0 << RCC_PLLCFGR_PLLP_Pos) | (((pllp >> 1) - 1) << RCC_PLLCFGR_PLLP_Pos)
| ((pll_freq/FREQ_USB) << RCC_PLLCFGR_PLLQ_Pos)); | ((pll_freq/FREQ_USB) << RCC_PLLCFGR_PLLQ_Pos));
RCC->CR |= RCC_CR_PLLON; RCC->CR |= RCC_CR_PLLON;
#endif #endif
@ -213,7 +158,7 @@ clock_setup(void)
// Configure and enable PLL // Configure and enable PLL
if (CONFIG_MACH_STM32F207) if (CONFIG_MACH_STM32F207)
enable_clock_stm32f20x(); enable_clock_stm32f20x();
else if (CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407) else if (CONFIG_MACH_STM32F4x5)
enable_clock_stm32f40x(); enable_clock_stm32f40x();
else else
enable_clock_stm32f446(); enable_clock_stm32f446();
@ -227,26 +172,32 @@ clock_setup(void)
; ;
// Switch system clock to PLL // Switch system clock to PLL
RCC->CFGR = RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_PPRE2_DIV4 | RCC_CFGR_SW_PLL; if (FREQ_PERIPH_DIV == 2)
RCC->CFGR = RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_SW_PLL;
else
RCC->CFGR = RCC_CFGR_PPRE1_DIV4 | RCC_CFGR_PPRE2_DIV4 | RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL)
; ;
} }
/****************************************************************
* Startup
****************************************************************/
// Main entry point - called from armcm_boot.c:ResetHandler() // Main entry point - called from armcm_boot.c:ResetHandler()
void void
armcm_main(void) armcm_main(void)
{ {
if (CONFIG_USBSERIAL && *(uint64_t*)USB_BOOT_FLAG_ADDR == USB_BOOT_FLAG) {
*(uint64_t*)USB_BOOT_FLAG_ADDR = 0;
uint32_t *sysbase = (uint32_t*)0x1fff0000;
asm volatile("mov sp, %0\n bx %1"
: : "r"(sysbase[0]), "r"(sysbase[1]));
}
// Run SystemInit() and then restore VTOR // Run SystemInit() and then restore VTOR
SystemInit(); SystemInit();
SCB->VTOR = (uint32_t)VectorTable; SCB->VTOR = (uint32_t)VectorTable;
// Reset peripheral clocks (for some bootloaders that don't)
RCC->AHB1ENR = 0x38000;
RCC->AHB2ENR = 0;
RCC->APB1ENR = 0;
RCC->APB2ENR = 0;
clock_setup(); clock_setup();
sched_main(); sched_main();