aboutsummaryrefslogtreecommitdiffstats
path: root/src/stm32/stm32f1.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stm32/stm32f1.c')
-rw-r--r--src/stm32/stm32f1.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/src/stm32/stm32f1.c b/src/stm32/stm32f1.c
new file mode 100644
index 00000000..3064d4c8
--- /dev/null
+++ b/src/stm32/stm32f1.c
@@ -0,0 +1,125 @@
+// Code to setup clocks and gpio on stm32f1
+//
+// 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 "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<<pos);
+ RCC->APB1ENR;
+ } else if (periph_base < AHBPERIPH_BASE) {
+ uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400;
+ RCC->APB2ENR |= (1<<pos);
+ RCC->APB2ENR;
+ } else {
+ uint32_t pos = (periph_base - AHBPERIPH_BASE) / 0x400;
+ RCC->AHBENR |= (1<<pos);
+ 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);
+ }
+}
+
+// Return the frequency of the given peripheral clock
+uint32_t
+get_pclock_frequency(uint32_t periph_base)
+{
+ return FREQ_PERIPH;
+}
+
+// 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
+ uint32_t rcc_pos = ((uint32_t)regs - APB2PERIPH_BASE) / 0x400;
+ RCC->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;
+}