From 7efc53ff59111061908405dae889a38cc6e60dbb Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Sun, 28 Jul 2019 14:40:41 -0400 Subject: [PATCH] stm32f4: Add support for STM32F103 Signed-off-by: Kevin O'Connor --- src/stm32f4/Kconfig | 21 ++++++- src/stm32f4/Makefile | 23 +++++--- src/stm32f4/adc.c | 24 ++++++-- src/stm32f4/gpio.c | 7 ++- src/stm32f4/internal.h | 6 ++ src/stm32f4/stm32f1.c | 125 +++++++++++++++++++++++++++++++++++++++++ src/stm32f4/watchdog.c | 2 +- 7 files changed, 191 insertions(+), 17 deletions(-) create mode 100644 src/stm32f4/stm32f1.c diff --git a/src/stm32f4/Kconfig b/src/stm32f4/Kconfig index c8da361c..53b7967c 100644 --- a/src/stm32f4/Kconfig +++ b/src/stm32f4/Kconfig @@ -16,32 +16,47 @@ config BOARD_DIRECTORY choice prompt "Processor model" + config MACH_STM32F103 + bool "STM32F103" + select MACH_STM32F1xx config MACH_STM32F405 bool "STM32F405" + select MACH_STM32F4xx config MACH_STM32F407 bool "STM32F407" + select MACH_STM32F4xx config MACH_STM32F446 bool "STM32F446" + select MACH_STM32F4xx endchoice +config MACH_STM32F1xx + bool +config MACH_STM32F4xx + bool + config MCU string - default "stm32f405" if MACH_STM32F405 - default "stm32f407" if MACH_STM32F407 - default "stm32f446" if MACH_STM32F446 + default "stm32f103xb" if MACH_STM32F103 + default "stm32f405xx" if MACH_STM32F405 + default "stm32f407xx" if MACH_STM32F407 + default "stm32f446xx" if MACH_STM32F446 config CLOCK_FREQ int + default 72000000 if MACH_STM32F103 default 168000000 if MACH_STM32F405 || MACH_STM32F407 default 180000000 if MACH_STM32F446 config FLASH_SIZE hex + default 0x10000 if MACH_STM32F103 default 0x80000 if MACH_STM32F405 || MACH_STM32F407 default 0x80000 if MACH_STM32F446 config RAM_SIZE hex + default 0x5000 if MACH_STM32F103 default 0x30000 if MACH_STM32F405 || MACH_STM32F407 default 0x20000 if MACH_STM32F446 diff --git a/src/stm32f4/Makefile b/src/stm32f4/Makefile index 5e32d647..d91a0f43 100644 --- a/src/stm32f4/Makefile +++ b/src/stm32f4/Makefile @@ -4,20 +4,26 @@ CROSS_PREFIX=arm-none-eabi- dirs-y += src/stm32f4 src/generic -dirs-y += lib/stm32f4 lib/stm32f4/gcc +dirs-$(CONFIG_MACH_STM32F1xx) += lib/stm32f1 lib/stm32f1/gcc +dirs-$(CONFIG_MACH_STM32F4xx) += lib/stm32f4 lib/stm32f4/gcc -MCU := $(shell echo $(CONFIG_MCU) | tr a-z A-Z) -CFLAGS += -D$(MCU)xx +MCU := $(shell echo $(CONFIG_MCU)) +MCU_UPPER := $(shell echo $(CONFIG_MCU) | tr a-z A-Z | tr X x) -CFLAGS += -mthumb -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard -CFLAGS += -Ilib/cmsis-core -Ilib/stm32f4/include +CFLAGS-$(CONFIG_MACH_STM32F1xx) += -mcpu=cortex-m3 -Ilib/stm32f1/include +CFLAGS-$(CONFIG_MACH_STM32F4xx) += -mcpu=cortex-m4 -Ilib/stm32f4/include +CFLAGS-$(CONFIG_MACH_STM32F4xx) += -mfpu=fpv4-sp-d16 -mfloat-abi=hard +CFLAGS += $(CFLAGS-y) -D$(MCU_UPPER) -mthumb -Ilib/cmsis-core CFLAGS_klipper.elf += -T $(OUT)stm32f4.ld --specs=nano.specs --specs=nosys.specs # Add source files -src-y += stm32f4/main.c stm32f4/clock.c stm32f4/watchdog.c stm32f4/gpio.c +src-y += stm32f4/main.c stm32f4/watchdog.c stm32f4/gpio.c src-y += generic/crc16_ccitt.c generic/armcm_irq.c generic/armcm_timer.c -src-y += ../lib/stm32f4/system_stm32f4xx.c +src-$(CONFIG_MACH_STM32F1xx) += ../lib/stm32f1/system_stm32f1xx.c +src-$(CONFIG_MACH_STM32F1xx) += stm32f4/stm32f1.c +src-$(CONFIG_MACH_STM32F4xx) += ../lib/stm32f4/system_stm32f4xx.c +src-$(CONFIG_MACH_STM32F4xx) += stm32f4/clock.c src-$(CONFIG_HAVE_GPIO_ADC) += stm32f4/adc.c src-$(CONFIG_HAVE_GPIO_SPI) += stm32f4/spi.c src-$(CONFIG_SERIAL) += stm32f4/serial.c generic/serial_irq.c @@ -27,7 +33,8 @@ $(OUT)%.o: %.s $(OUT)autoconf.h $(OUT)board-link @echo " Assembling $@" $(Q)$(AS) $< -o $@ -asmsrc-y := ../lib/stm32f4/gcc/startup_$(shell echo $(CONFIG_MCU))xx.s +asmsrc-$(CONFIG_MACH_STM32F1xx) := ../lib/stm32f1/gcc/startup_$(MCU).s +asmsrc-$(CONFIG_MACH_STM32F4xx) := ../lib/stm32f4/gcc/startup_$(MCU).s OBJS_klipper.elf += $(patsubst %.s, $(OUT)src/%.o,$(asmsrc-y)) # Build the linker script diff --git a/src/stm32f4/adc.c b/src/stm32f4/adc.c index 07d03003..8cd50b48 100644 --- a/src/stm32f4/adc.c +++ b/src/stm32f4/adc.c @@ -8,6 +8,7 @@ #include "board/misc.h" // timer_from_us #include "command.h" // shutdown #include "compiler.h" // ARRAY_SIZE +#include "generic/armcm_timer.h" // udelay #include "gpio.h" // gpio_adc_setup #include "internal.h" // GPIO #include "sched.h" // sched_shutdown @@ -21,6 +22,12 @@ static const uint8_t adc_pins[] = { GPIO('C', 2), GPIO('C', 3), GPIO('C', 4), GPIO('C', 5) }; +#if CONFIG_MACH_STM32F1xx +#define CR2_FLAGS (ADC_CR2_ADON | (7 << ADC_CR2_EXTSEL_Pos) | ADC_CR2_EXTTRIG) +#else +#define CR2_FLAGS ADC_CR2_ADON +#endif + struct gpio_adc gpio_adc_setup(uint32_t pin) { @@ -36,14 +43,22 @@ gpio_adc_setup(uint32_t pin) // Enable the ADC if (!is_enabled_pclock(ADC1_BASE)) { enable_pclock(ADC1_BASE); - uint32_t aticks = 3; // 56 adc cycles + uint32_t aticks = 3; // 2.5-3.2us (depending on stm32 chip) ADC1->SMPR1 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9) | (aticks << 12) | (aticks << 15) | (aticks << 18) | (aticks << 21) | (aticks << 24)); ADC1->SMPR2 = (aticks | (aticks << 3) | (aticks << 6) | (aticks << 9) | (aticks << 12) | (aticks << 15) | (aticks << 18) | (aticks << 21) | (aticks << 24) | (aticks << 27)); - ADC1->CR2 = ADC_CR2_ADON; + ADC1->CR2 = CR2_FLAGS; + +#if CONFIG_MACH_STM32F1xx + // Perform calibration + udelay(timer_from_us(1)); + ADC1->CR2 = ADC_CR2_CAL | CR2_FLAGS; + while (ADC1->CR2 & ADC_CR2_CAL) + ; +#endif } gpio_peripheral(pin, GPIO_ANALOG, 0); @@ -67,9 +82,10 @@ gpio_adc_sample(struct gpio_adc g) } // Start sample ADC1->SQR3 = g.chan; - ADC1->CR2 = ADC_CR2_SWSTART | ADC_CR2_ADON; + ADC1->CR2 = ADC_CR2_SWSTART | CR2_FLAGS; + need_delay: - return timer_from_us(4); + return timer_from_us(10); } // Read a value; use only after gpio_adc_sample() returns zero diff --git a/src/stm32f4/gpio.c b/src/stm32f4/gpio.c index 77a00c0f..9fbbdaec 100644 --- a/src/stm32f4/gpio.c +++ b/src/stm32f4/gpio.c @@ -16,15 +16,20 @@ DECL_ENUMERATION_RANGE("pin", "PB0", GPIO('B', 0), 32); DECL_ENUMERATION_RANGE("pin", "PC0", GPIO('C', 0), 32); DECL_ENUMERATION_RANGE("pin", "PD0", GPIO('D', 0), 32); DECL_ENUMERATION_RANGE("pin", "PE0", GPIO('E', 0), 32); +#ifdef GPIOH DECL_ENUMERATION_RANGE("pin", "PF0", GPIO('F', 0), 32); DECL_ENUMERATION_RANGE("pin", "PG0", GPIO('G', 0), 32); DECL_ENUMERATION_RANGE("pin", "PH0", GPIO('H', 0), 32); +#endif #ifdef GPIOI DECL_ENUMERATION_RANGE("pin", "PI0", GPIO('I', 0), 32); #endif GPIO_TypeDef * const digital_regs[] = { - GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, GPIOF, GPIOG, GPIOH, + GPIOA, GPIOB, GPIOC, GPIOD, GPIOE, +#ifdef GPIOH + GPIOF, GPIOG, GPIOH, +#endif #ifdef GPIOI GPIOI, #endif diff --git a/src/stm32f4/internal.h b/src/stm32f4/internal.h index 22720a96..d19a0b98 100644 --- a/src/stm32f4/internal.h +++ b/src/stm32f4/internal.h @@ -2,7 +2,13 @@ #define __STM32F4_INTERNAL_H // Local definitions for STM32F4 code +#include "autoconf.h" // CONFIG_MACH_STM32F1xx + +#if CONFIG_MACH_STM32F1xx +#include "stm32f1xx.h" +#else #include "stm32f4xx.h" +#endif extern GPIO_TypeDef * const digital_regs[]; diff --git a/src/stm32f4/stm32f1.c b/src/stm32f4/stm32f1.c new file mode 100644 index 00000000..3064d4c8 --- /dev/null +++ b/src/stm32f4/stm32f1.c @@ -0,0 +1,125 @@ +// Code to setup clocks and gpio on stm32f1 +// +// Copyright (C) 2019 Kevin O'Connor +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_REF_8M +#include "internal.h" // enable_pclock + +#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2) + +// Enable a peripheral clock +void +enable_pclock(uint32_t periph_base) +{ + if (periph_base < APB2PERIPH_BASE) { + uint32_t pos = (periph_base - APB1PERIPH_BASE) / 0x400; + RCC->APB1ENR |= (1<APB1ENR; + } else if (periph_base < AHBPERIPH_BASE) { + uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400; + RCC->APB2ENR |= (1<APB2ENR; + } else { + uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400; + RCC->AHBENR |= (1<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<APB2ENR & (1<AHBENR & (1<APB2ENR |= 1 << rcc_pos; + + // 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_ANALOG) { + cfg = 0x0; + } 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); +} + +// Main clock setup called at chip startup +void +clock_setup(void) +{ + uint32_t cfgr; + if (CONFIG_CLOCK_REF_8M) { + // Configure 72Mhz PLL from external 8Mhz crystal (HSE) + RCC->CR |= RCC_CR_HSEON; + cfgr = ((1 << RCC_CFGR_PLLSRC_Pos) | ((9 - 2) << RCC_CFGR_PLLMULL_Pos) + | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 + | RCC_CFGR_ADCPRE_DIV4); + } else { + // Configure 72Mhz PLL from internal 8Mhz oscillator (HSI) + cfgr = ((0 << RCC_CFGR_PLLSRC_Pos) | ((18 - 2) << RCC_CFGR_PLLMULL_Pos) + | RCC_CFGR_PPRE1_DIV2 | RCC_CFGR_PPRE2_DIV2 + | RCC_CFGR_ADCPRE_DIV4); + } + RCC->CFGR = cfgr; + RCC->CR |= RCC_CR_PLLON; + + // Set flash latency + FLASH->ACR = (2 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE; + + // Wait for PLL lock + while (!(RCC->CR & RCC_CR_PLLRDY)) + ; + + // Switch system clock to PLL + RCC->CFGR = cfgr | RCC_CFGR_SW_PLL; + while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_PLL) + ; + + // Disable JTAG to free PA15, PB3, PB4 + enable_pclock(AFIO_BASE); + AFIO->MAPR = AFIO_MAPR_SWJ_CFG_JTAGDISABLE; +} diff --git a/src/stm32f4/watchdog.c b/src/stm32f4/watchdog.c index 1f642616..2851560a 100644 --- a/src/stm32f4/watchdog.c +++ b/src/stm32f4/watchdog.c @@ -19,7 +19,7 @@ watchdog_init(void) { IWDG->KR = 0x5555; IWDG->PR = 0; - IWDG->RLR = 0x0FFF; // 512ms timeout + IWDG->RLR = 0x0FFF; // 410-512ms timeout (depending on stm32 chip) IWDG->KR = 0xCCCC; } DECL_INIT(watchdog_init);