aboutsummaryrefslogtreecommitdiffstats
path: root/src/stm32/stm32f4.c
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2019-07-28 23:35:16 -0400
committerKevinOConnor <kevin@koconnor.net>2019-08-05 11:25:40 -0400
commitfe065d72d00319adcc7e27a392193733dc566922 (patch)
tree735c64417c012d7b366b5c9ecf003f4399db5473 /src/stm32/stm32f4.c
parent8b9cc62359057a686929cc713ffe2931e2203946 (diff)
downloadkutter-fe065d72d00319adcc7e27a392193733dc566922.tar.gz
kutter-fe065d72d00319adcc7e27a392193733dc566922.tar.xz
kutter-fe065d72d00319adcc7e27a392193733dc566922.zip
stm32: Rename clock.c to stm32f4.c
Rename the clock.c file to stm32f4.c to make it more clear that the code is specific to the stm32f4 chips. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/stm32/stm32f4.c')
-rw-r--r--src/stm32/stm32f4.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/stm32/stm32f4.c b/src/stm32/stm32f4.c
new file mode 100644
index 00000000..d0a2f249
--- /dev/null
+++ b/src/stm32/stm32f4.c
@@ -0,0 +1,158 @@
+// Code to setup clocks and gpio on stm32f4
+//
+// 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 (CONFIG_CLOCK_FREQ / 4)
+
+// 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 < AHB1PERIPH_BASE) {
+ uint32_t pos = (periph_base - APB2PERIPH_BASE) / 0x400;
+ RCC->APB2ENR |= (1<<pos);
+ RCC->APB2ENR;
+ } else if (periph_base < AHB2PERIPH_BASE) {
+ uint32_t pos = (periph_base - AHB1PERIPH_BASE) / 0x400;
+ RCC->AHB1ENR |= (1<<pos);
+ RCC->AHB1ENR;
+ }
+}
+
+// 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
+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 - AHB1PERIPH_BASE) / 0x400;
+ RCC->AHB1ENR |= (1<<rcc_pos);
+
+ // Configure GPIO
+ uint32_t mode_bits = mode & 0x0f, func = mode >> 4;
+ 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->OSPEEDR = (regs->OSPEEDR & ~m_msk) | (0x02 << m_shift);
+}
+
+#if CONFIG_CLOCK_REF_8M
+DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PH0,PH1");
+#endif
+
+// Clock configuration
+static void
+enable_clock_stm32f40x(void)
+{
+#if CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407
+ if (CONFIG_CLOCK_REF_8M) {
+ // Configure 168Mhz PLL from external 8Mhz crystal (HSE)
+ RCC->CR |= RCC_CR_HSEON;
+ RCC->PLLCFGR = (
+ RCC_PLLCFGR_PLLSRC_HSE | (4 << RCC_PLLCFGR_PLLM_Pos)
+ | (168 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos)
+ | (7 << RCC_PLLCFGR_PLLQ_Pos));
+ } else {
+ // Configure 168Mhz PLL from internal 16Mhz oscillator (HSI)
+ RCC->PLLCFGR = (
+ RCC_PLLCFGR_PLLSRC_HSI | (8 << RCC_PLLCFGR_PLLM_Pos)
+ | (168 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos)
+ | (7 << RCC_PLLCFGR_PLLQ_Pos));
+ }
+ RCC->CR |= RCC_CR_PLLON;
+#endif
+}
+
+static void
+enable_clock_stm32f446(void)
+{
+#if CONFIG_MACH_STM32F446
+ if (CONFIG_CLOCK_REF_8M) {
+ // Configure 180Mhz PLL from external 8Mhz crystal (HSE)
+ RCC->CR |= RCC_CR_HSEON;
+ RCC->PLLCFGR = (
+ RCC_PLLCFGR_PLLSRC_HSE | (4 << RCC_PLLCFGR_PLLM_Pos)
+ | (180 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos)
+ | (7 << RCC_PLLCFGR_PLLQ_Pos) | (6 << RCC_PLLCFGR_PLLR_Pos));
+ } else {
+ // Configure 180Mhz PLL from internal 16Mhz oscillator (HSI)
+ RCC->PLLCFGR = (
+ RCC_PLLCFGR_PLLSRC_HSI | (8 << RCC_PLLCFGR_PLLM_Pos)
+ | (180 << RCC_PLLCFGR_PLLN_Pos) | (0 << RCC_PLLCFGR_PLLP_Pos)
+ | (7 << RCC_PLLCFGR_PLLQ_Pos) | (6 << RCC_PLLCFGR_PLLR_Pos));
+ }
+ RCC->CR |= RCC_CR_PLLON;
+
+ // Enable "over drive"
+ enable_pclock(PWR_BASE);
+ PWR->CR = (3 << PWR_CR_VOS_Pos) | PWR_CR_ODEN;
+ while (!(PWR->CSR & PWR_CSR_ODRDY))
+ ;
+ PWR->CR = (3 << PWR_CR_VOS_Pos) | PWR_CR_ODEN | PWR_CR_ODSWEN;
+ while (!(PWR->CSR & PWR_CSR_ODSWRDY))
+ ;
+#endif
+}
+
+// Main clock setup called at chip startup
+void
+clock_setup(void)
+{
+ if (CONFIG_MACH_STM32F405 || CONFIG_MACH_STM32F407)
+ enable_clock_stm32f40x();
+ else
+ enable_clock_stm32f446();
+
+ // Set flash latency
+ FLASH->ACR = (FLASH_ACR_LATENCY_5WS | FLASH_ACR_ICEN | FLASH_ACR_DCEN
+ | FLASH_ACR_PRFTEN);
+
+ // Wait for PLL lock
+ while (!(RCC->CR & RCC_CR_PLLRDY))
+ ;
+
+ // Switch system clock to PLL
+ 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)
+ ;
+}