diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2019-09-16 11:45:36 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2019-10-23 21:19:03 -0400 |
commit | 2c535106ee5bbbcc019cb0820d1a5fcf0639eb9e (patch) | |
tree | a3a3cbf9f03ab5ed0b2d63600ed205561796ee27 /src/stm32/stm32f0.c | |
parent | 7e090a996a85016b2e72fa5d426ba95fe8bdc703 (diff) | |
download | kutter-2c535106ee5bbbcc019cb0820d1a5fcf0639eb9e.tar.gz kutter-2c535106ee5bbbcc019cb0820d1a5fcf0639eb9e.tar.xz kutter-2c535106ee5bbbcc019cb0820d1a5fcf0639eb9e.zip |
stm32: Initial support for stm32f070
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/stm32/stm32f0.c')
-rw-r--r-- | src/stm32/stm32f0.c | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/src/stm32/stm32f0.c b/src/stm32/stm32f0.c new file mode 100644 index 00000000..199fb066 --- /dev/null +++ b/src/stm32/stm32f0.c @@ -0,0 +1,136 @@ +// Code to setup clocks and gpio on stm32f0 +// +// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU GPLv3 license. + +#include "autoconf.h" // CONFIG_CLOCK_REF_8M +#include "command.h" // DECL_CONSTANT_STR +#include "internal.h" // enable_pclock + +#define FREQ_PERIPH 48000000 + +// Enable a peripheral clock +void +enable_pclock(uint32_t periph_base) +{ + if (periph_base < SYSCFG_BASE) { + uint32_t pos = (periph_base - APBPERIPH_BASE) / 0x400; + RCC->APB1ENR |= 1 << pos; + RCC->APB1ENR; + } else if (periph_base < AHBPERIPH_BASE) { + uint32_t pos = (periph_base - SYSCFG_BASE) / 0x400; + RCC->APB2ENR |= 1 << pos; + RCC->APB2ENR; + } else { + uint32_t pos = (periph_base - AHB2PERIPH_BASE) / 0x400; + RCC->AHBENR |= 1 << (pos + 17); + 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)); + } +} + +// 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 - AHB2PERIPH_BASE) / 0x400; + RCC->AHBENR |= 1 << (rcc_pos + 17); + 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); +} + +// Handle USB reboot requests +void +usb_request_bootloader(void) +{ +} + +#if CONFIG_CLOCK_REF_8M +DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PF0,PF1"); +#endif + +// Configure and enable the PLL as clock source +static void +pll_setup(void) +{ + uint32_t cfgr; + if (CONFIG_CLOCK_REF_8M) { + // Configure 48Mhz PLL from external 8Mhz crystal (HSE) + RCC->CR |= RCC_CR_HSEON; + cfgr = RCC_CFGR_PLLSRC_HSE_PREDIV | ((6 - 2) << RCC_CFGR_PLLMUL_Pos); + } else { + // Configure 48Mhz PLL from internal 8Mhz oscillator (HSI) + cfgr = RCC_CFGR_PLLSRC_HSI_DIV2 | ((12 - 2) << RCC_CFGR_PLLMUL_Pos); + } + RCC->CFGR = cfgr; + RCC->CR |= RCC_CR_PLLON; + + // 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) + ; + + // Select PLL as source for USB clock + if (CONFIG_USBSERIAL) + RCC->CFGR3 = RCC_CFGR3_USBSW; +} + +// Main clock setup called at chip startup +void +clock_setup(void) +{ + // Set flash latency + FLASH->ACR = (1 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE; + + // Configure main clock + pll_setup(); +} |