From 6e8f28117b25a19c865b9ac8660c22339b2e2b76 Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sat, 18 Dec 2021 19:11:17 -0500 Subject: [PATCH] stm32: Initial support for stm32g0 Signed-off-by: Kevin O'Connor --- src/stm32/Kconfig | 19 +++- src/stm32/Makefile | 5 + src/stm32/gpioperiph.c | 1 + src/stm32/internal.h | 2 + src/stm32/stm32f0_serial.c | 17 ++- src/stm32/stm32g0.c | 217 +++++++++++++++++++++++++++++++++++++ 6 files changed, 253 insertions(+), 8 deletions(-) create mode 100644 src/stm32/stm32g0.c diff --git a/src/stm32/Kconfig b/src/stm32/Kconfig index dfaa96eb..2263bec9 100644 --- a/src/stm32/Kconfig +++ b/src/stm32/Kconfig @@ -6,9 +6,9 @@ config STM32_SELECT bool default y select HAVE_GPIO - select HAVE_GPIO_ADC - select HAVE_GPIO_I2C if !(MACH_STM32F031 || MACH_STM32H7) - select HAVE_GPIO_SPI if !MACH_STM32F031 + select HAVE_GPIO_ADC if !MACH_STM32G0 + select HAVE_GPIO_I2C if !(MACH_STM32F031 || MACH_STM32G0 || MACH_STM32H7) + select HAVE_GPIO_SPI if !(MACH_STM32F031 || MACH_STM32G0) select HAVE_GPIO_HARD_PWM if MACH_STM32F1 || MACH_STM32F4 || MACH_STM32H7 select HAVE_GPIO_BITBANGING if !MACH_STM32F031 select HAVE_STRICT_TIMING @@ -64,6 +64,9 @@ choice bool "STM32F072" select MACH_STM32F0 select MACH_STM32F0x2 + config MACH_STM32G0B1 + bool "STM32G0B1" + select MACH_STM32G0 config MACH_STM32H743 bool "STM32H743" select MACH_STM32H7 @@ -80,6 +83,8 @@ config MACH_STM32F2 bool config MACH_STM32F4 bool +config MACH_STM32G0 + bool config MACH_STM32H7 bool config MACH_STM32F0x2 # F042, F072 series @@ -109,6 +114,7 @@ config MCU default "stm32f407xx" if MACH_STM32F407 default "stm32f429xx" if MACH_STM32F429 default "stm32f446xx" if MACH_STM32F446 + default "stm32g0b1xx" if MACH_STM32G0B1 default "stm32h743xx" if MACH_STM32H743 default "stm32h750xx" if MACH_STM32H750 @@ -121,6 +127,7 @@ config CLOCK_FREQ default 84000000 if MACH_STM32F401 default 168000000 if MACH_STM32F4x5 default 180000000 if MACH_STM32F446 + default 64000000 if MACH_STM32G0 default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports config FLASH_SIZE @@ -131,6 +138,7 @@ config FLASH_SIZE default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB) default 0x40000 if MACH_STM32F2 || MACH_STM32F401 default 0x80000 if MACH_STM32F4x5 || MACH_STM32F446 + default 0x20000 if MACH_STM32G0B1 default 0x20000 if MACH_STM32H750 default 0x200000 if MACH_STM32H743 @@ -148,6 +156,7 @@ config RAM_SIZE default 0x20000 if MACH_STM32F207 default 0x10000 if MACH_STM32F401 default 0x20000 if MACH_STM32F4x5 || MACH_STM32F446 + default 0x24000 if MACH_STM32G0B1 default 0x20000 if MACH_STM32H750 default 0x80000 if MACH_STM32H743 @@ -171,9 +180,9 @@ config STM32F103GD_DISABLE_SWD ###################################################################### choice - prompt "Bootloader offset" if MACH_STM32F1 || MACH_STM32F2 || MACH_STM32F4 || MACH_STM32F070 || MACH_STM32H743 + prompt "Bootloader offset" config STM32_FLASH_START_2000 - bool "8KiB bootloader (stm32duino)" if MACH_STM32F103 || MACH_STM32F070 + bool "8KiB bootloader" if MACH_STM32F103 || MACH_STM32F070 || MACH_STM32G0 config STM32_FLASH_START_5000 bool "20KiB bootloader" if MACH_STM32F103 config STM32_FLASH_START_7000 diff --git a/src/stm32/Makefile b/src/stm32/Makefile index b018c14c..d3683954 100644 --- a/src/stm32/Makefile +++ b/src/stm32/Makefile @@ -8,6 +8,7 @@ dirs-$(CONFIG_MACH_STM32F0) += lib/stm32f0 dirs-$(CONFIG_MACH_STM32F1) += lib/stm32f1 dirs-$(CONFIG_MACH_STM32F2) += lib/stm32f2 dirs-$(CONFIG_MACH_STM32F4) += lib/stm32f4 +dirs-$(CONFIG_MACH_STM32G0) += lib/stm32g0 dirs-$(CONFIG_MACH_STM32H7) += lib/stm32h7 MCU := $(shell echo $(CONFIG_MCU)) @@ -17,6 +18,7 @@ CFLAGS-$(CONFIG_MACH_STM32F0) += -mcpu=cortex-m0 -Ilib/stm32f0/include CFLAGS-$(CONFIG_MACH_STM32F1) += -mcpu=cortex-m3 -Ilib/stm32f1/include CFLAGS-$(CONFIG_MACH_STM32F2) += -mcpu=cortex-m3 -Ilib/stm32f2/include CFLAGS-$(CONFIG_MACH_STM32F4) += -mcpu=cortex-m4 -Ilib/stm32f4/include +CFLAGS-$(CONFIG_MACH_STM32G0) += -mcpu=cortex-m0plus -Ilib/stm32g0/include CFLAGS-$(CONFIG_MACH_STM32H7) += -mcpu=cortex-m7 -Ilib/stm32h7/include CFLAGS += $(CFLAGS-y) -D$(MCU_UPPER) -mthumb -Ilib/cmsis-core -Ilib/fast-hash @@ -40,6 +42,8 @@ src-$(CONFIG_MACH_STM32F2) += stm32/gpioperiph.c stm32/adc.c stm32/i2c.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/gpioperiph.c stm32/adc.c stm32/i2c.c +src-$(CONFIG_MACH_STM32G0) += generic/timer_irq.c stm32/stm32f0_timer.c +src-$(CONFIG_MACH_STM32G0) += stm32/stm32g0.c stm32/gpioperiph.c src-$(CONFIG_MACH_STM32H7) += ../lib/stm32h7/system_stm32h7xx.c src-$(CONFIG_MACH_STM32H7) += stm32/stm32h7.c generic/armcm_timer.c src-$(CONFIG_MACH_STM32H7) += stm32/gpioperiph.c stm32/stm32h7_adc.c @@ -51,6 +55,7 @@ usb-src-$(CONFIG_HAVE_STM32_USBOTG) := stm32/usbotg.c src-$(CONFIG_USBSERIAL) += $(usb-src-y) stm32/chipid.c generic/usb_cdc.c serial-src-y := stm32/serial.c serial-src-$(CONFIG_MACH_STM32F0) := stm32/stm32f0_serial.c +serial-src-$(CONFIG_MACH_STM32G0) := stm32/stm32f0_serial.c serial-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_serial.c src-$(CONFIG_SERIAL) += $(serial-src-y) generic/serial_irq.c src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c diff --git a/src/stm32/gpioperiph.c b/src/stm32/gpioperiph.c index e003e9f0..06cdaa05 100644 --- a/src/stm32/gpioperiph.c +++ b/src/stm32/gpioperiph.c @@ -31,6 +31,7 @@ gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup) // 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); diff --git a/src/stm32/internal.h b/src/stm32/internal.h index 9c0da6c6..6101e0f2 100644 --- a/src/stm32/internal.h +++ b/src/stm32/internal.h @@ -12,6 +12,8 @@ #include "stm32f2xx.h" #elif CONFIG_MACH_STM32F4 #include "stm32f4xx.h" +#elif CONFIG_MACH_STM32G0 +#include "stm32g0xx.h" #elif CONFIG_MACH_STM32H7 #include "stm32h7xx.h" #endif diff --git a/src/stm32/stm32f0_serial.c b/src/stm32/stm32f0_serial.c index 367c2991..c214ed01 100644 --- a/src/stm32/stm32f0_serial.c +++ b/src/stm32/stm32f0_serial.c @@ -43,9 +43,20 @@ #endif #if CONFIG_MACH_STM32F031 -// The stm32f031 has same pins for USART2, but everything is routed to USART1 -#define USART2 USART1 -#define USART2_IRQn USART1_IRQn + // The stm32f031 has same pins for USART2, but everything is routed to USART1 + #define USART2 USART1 + #define USART2_IRQn USART1_IRQn +#endif + +#if CONFIG_MACH_STM32G0 + // The stm32g0 has slightly different register names + #define USART2_IRQn USART2_LPUART2_IRQn + #define USART_CR1_RXNEIE USART_CR1_RXNEIE_RXFNEIE + #define USART_CR1_TXEIE USART_CR1_TXEIE_TXFNFIE + #define USART_ISR_RXNE USART_ISR_RXNE_RXFNE + #define USART_ISR_TXE USART_ISR_TXE_TXFNF + #define USART_BRR_DIV_MANTISSA_Pos 4 + #define USART_BRR_DIV_FRACTION_Pos 0 #endif #define CR1_FLAGS (USART_CR1_UE | USART_CR1_RE | USART_CR1_TE \ diff --git a/src/stm32/stm32g0.c b/src/stm32/stm32g0.c new file mode 100644 index 00000000..9374376a --- /dev/null +++ b/src/stm32/stm32g0.c @@ -0,0 +1,217 @@ +// Code to setup clocks on stm32g0 +// +// Copyright (C) 2019-2021 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ +#include "board/armcm_boot.h" // armcm_main +#include "board/irq.h" // irq_disable +#include "command.h" // DECL_CONSTANT_STR +#include "internal.h" // enable_pclock +#include "sched.h" // sched_main + + +/**************************************************************** + * Clock setup + ****************************************************************/ + +#define FREQ_PERIPH 64000000 +#define FREQ_USB 48000000 + +// Map an APB peripheral address to an enable bit +static int +lookup_apb_bit(uint32_t periph_base) +{ + if (periph_base == USB_BASE) + return 13; + if (periph_base == CRS_BASE) + return 16; + if (periph_base == SPI1_BASE) + return 32 + 12; + if (periph_base == USART1_BASE) + return 32 + 14; + if (periph_base == ADC1_BASE) + return 32 + 20; + return (periph_base - APBPERIPH_BASE) / 0x400; +} + +// Enable a peripheral clock +void +enable_pclock(uint32_t periph_base) +{ + if (periph_base >= IOPORT_BASE) { + uint32_t pos = (periph_base - IOPORT_BASE) / 0x400; + RCC->IOPENR |= 1 << pos; + RCC->IOPENR; + RCC->IOPRSTR |= (1<IOPRSTR &= ~(1<= AHBPERIPH_BASE) { + uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400; + RCC->AHBENR |= 1 << pos; + RCC->AHBENR; + RCC->AHBRSTR |= (1<AHBRSTR &= ~(1<APBENR1 |= 1 << pos; + RCC->APBENR1; + RCC->APBRSTR1 |= (1 << pos); + RCC->APBRSTR1 &= ~(1 << pos); + } else { + RCC->APBENR2 |= 1 << (pos - 32); + RCC->APBENR2; + RCC->APBRSTR2 |= (1 << (pos - 32)); + RCC->APBRSTR2 &= ~(1 << (pos - 32)); + } + } +} + +// Check if a peripheral clock has been enabled +int +is_enabled_pclock(uint32_t periph_base) +{ + if (periph_base >= IOPORT_BASE) { + uint32_t pos = (periph_base - IOPORT_BASE) / 0x400; + return RCC->IOPENR & (1 << pos); + } else if (periph_base >= AHBPERIPH_BASE) { + uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400; + return RCC->AHBENR & (1 << pos); + } else { + uint32_t pos = lookup_apb_bit(periph_base); + if (pos < 32) + return RCC->APBENR1 & (1 << pos); + return RCC->APBENR2 & (1 << (pos - 32)); + } +} + +// Return the frequency of the given peripheral clock +uint32_t +get_pclock_frequency(uint32_t periph_base) +{ + return FREQ_PERIPH; +} + +// Enable a GPIO peripheral clock +void +gpio_clock_enable(GPIO_TypeDef *regs) +{ + uint32_t rcc_pos = ((uint32_t)regs - IOPORT_BASE) / 0x400; + RCC->IOPENR |= 1 << rcc_pos; + RCC->IOPENR; +} + +#if !CONFIG_STM32_CLOCK_REF_INTERNAL +DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PF0,PF1"); +#endif + +// Configure and enable the PLL as clock source +static void +clock_setup(void) +{ + uint32_t pll_base = 4000000, pll_freq = 192000000, pllcfgr; + if (!CONFIG_STM32_CLOCK_REF_INTERNAL) { + // Configure PLL from external crystal (HSE) + uint32_t div = CONFIG_CLOCK_REF_FREQ / pll_base; + RCC->CR |= RCC_CR_HSEON; + pllcfgr = RCC_PLLCFGR_PLLSRC_HSE | ((div - 1) << RCC_PLLCFGR_PLLM_Pos); + } else { + // Configure PLL from internal 16Mhz oscillator (HSI) + uint32_t div = 16000000 / pll_base; + pllcfgr = RCC_PLLCFGR_PLLSRC_HSI | ((div - 1) << RCC_PLLCFGR_PLLM_Pos); + } + pllcfgr |= (pll_freq/pll_base) << RCC_PLLCFGR_PLLN_Pos; + pllcfgr |= (pll_freq/CONFIG_CLOCK_FREQ - 1) << RCC_PLLCFGR_PLLR_Pos; + RCC->PLLCFGR = pllcfgr | RCC_PLLCFGR_PLLREN; + RCC->CR |= RCC_CR_PLLON; + + // Wait for PLL lock + while (!(RCC->CR & RCC_CR_PLLRDY)) + ; + + // Switch system clock to PLL + RCC->CFGR = (2 << RCC_CFGR_SW_Pos); + while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != (2 << RCC_CFGR_SWS_Pos)) + ; + + // Enable USB clock + if (CONFIG_USBSERIAL) { + RCC->CR |= RCC_CR_HSI48ON; + while (!(RCC->CR & RCC_CR_HSI48RDY)) + ; + enable_pclock(CRS_BASE); + CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN; + } +} + + +/**************************************************************** + * USB bootloader + ****************************************************************/ + +#define USB_BOOT_FLAG_ADDR (CONFIG_RAM_START + CONFIG_RAM_SIZE - 1024) +#define USB_BOOT_FLAG 0x55534220424f4f54 // "USB BOOT" + +// Flag that bootloader is desired and reboot +static void +usb_reboot_for_dfu_bootloader(void) +{ + irq_disable(); + *(uint64_t*)USB_BOOT_FLAG_ADDR = USB_BOOT_FLAG; + NVIC_SystemReset(); +} + +// Check if rebooting into system DFU Bootloader +static void +check_usb_dfu_bootloader(void) +{ + if (!CONFIG_USBSERIAL || *(uint64_t*)USB_BOOT_FLAG_ADDR != USB_BOOT_FLAG) + return; + *(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])); +} + +// Handle USB reboot requests +void +usb_request_bootloader(void) +{ + usb_reboot_for_dfu_bootloader(); +} + + +/**************************************************************** + * Startup + ****************************************************************/ + +// Main entry point - called from armcm_boot.c:ResetHandler() +void +armcm_main(void) +{ + check_usb_dfu_bootloader(); + SCB->VTOR = (uint32_t)VectorTable; + + // Reset clock registers (in case bootloader has changed them) + RCC->CR |= RCC_CR_HSION; + while (!(RCC->CR & RCC_CR_HSIRDY)) + ; + RCC->CFGR = 0x00000000; + RCC->CR = RCC_CR_HSION; + while (RCC->CR & RCC_CR_PLLRDY) + ; + RCC->PLLCFGR = 0x00001000; + RCC->IOPENR = 0x00000000; + RCC->AHBENR = 0x00000100; + RCC->APBENR1 = 0x00000000; + RCC->APBENR2 = 0x00000000; + + // Set flash latency + FLASH->ACR = (2<