aboutsummaryrefslogtreecommitdiffstats
path: root/src/stm32f4/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stm32f4/clock.c')
-rw-r--r--src/stm32f4/clock.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/src/stm32f4/clock.c b/src/stm32f4/clock.c
new file mode 100644
index 00000000..339a7fde
--- /dev/null
+++ b/src/stm32f4/clock.c
@@ -0,0 +1,74 @@
+// Code to setup clocks on stm32f446
+//
+// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU GPLv3 license.
+
+#include "internal.h" // enable_pclock
+
+#define FREQ_PERIPH 45000000
+
+// 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;
+ }
+}
+
+// Return the frequency of the given peripheral clock
+uint32_t
+get_pclock_frequency(uint32_t periph_base)
+{
+ return FREQ_PERIPH;
+}
+
+// Main clock setup called at chip startup
+void
+clock_setup(void)
+{
+ // Configure 180Mhz PLL from internal oscillator (HSI)
+ RCC->PLLCFGR = (
+ RCC_PLLCFGR_PLLSRC_HSI | (16 << RCC_PLLCFGR_PLLM_Pos)
+ | (360 << 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))
+ ;
+
+ // 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)
+ ;
+
+ // Enable GPIO clocks
+ enable_pclock(GPIOA_BASE);
+ enable_pclock(GPIOB_BASE);
+ enable_pclock(GPIOC_BASE);
+}