aboutsummaryrefslogtreecommitdiff
path: root/02-usart/src/arch/stm32l4xxx/peripherals/clock.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2020-11-22 01:06:30 -0700
committerJosh Rahm <joshuarahm@gmail.com>2020-11-22 01:06:30 -0700
commit9f28e53c71d28d04e2775c59944d2887a99f1e86 (patch)
treec0ecb2872c6d27acf08aa73919d709f949200de5 /02-usart/src/arch/stm32l4xxx/peripherals/clock.c
parentebb9123c00d1e9629376b6f0a2f1f4e7e550c2af (diff)
downloadstm32l4-9f28e53c71d28d04e2775c59944d2887a99f1e86.tar.gz
stm32l4-9f28e53c71d28d04e2775c59944d2887a99f1e86.tar.bz2
stm32l4-9f28e53c71d28d04e2775c59944d2887a99f1e86.zip
Large reorganization.
What was in core/ is now moved to arch/stm34l4xxx/peripherals. This new directory is *supposed to* to contain raw header files defining just the pertinent register structures for the various peripherals. Peripheral management belongs somewhere in the new `kern/..` directories. This is not completely the case at the moment, so more refactoring needs to be done. What was sitting in the root has now been moved into the kern/ directory. The kern/ directory is to contain everything else other than raw device register definitions. The root of the kern/ tree is reserved for standard library-esque headers. The kern/<peripheral> directory contains management systems for that peripheral. (At the moment DMA is the only peripheral with a decent management system.) Preferably these peripheral systems should only include their correlating header in arch/stm34l4xxx/peripherals, and use other management systems for handling other peripherals rather than manipulating their raw registers directly. (Though this ideal will require much more critical mass of management systems.)
Diffstat (limited to '02-usart/src/arch/stm32l4xxx/peripherals/clock.c')
-rw-r--r--02-usart/src/arch/stm32l4xxx/peripherals/clock.c107
1 files changed, 107 insertions, 0 deletions
diff --git a/02-usart/src/arch/stm32l4xxx/peripherals/clock.c b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c
new file mode 100644
index 0000000..ba127a9
--- /dev/null
+++ b/02-usart/src/arch/stm32l4xxx/peripherals/clock.c
@@ -0,0 +1,107 @@
+/*
+ * This file sets the system clock to its full glory of 80Mhz
+ */
+
+#include "arch/stm32l4xxx/peripherals/clock.h"
+#include "arch/stm32l4xxx/peripherals/flash.h"
+
+#include <stdint.h>
+#include "kern/spin.h"
+
+#define TIMEOUT 10000
+
+int pll_off()
+{
+ uint32_t c;
+
+ RCC.c_r &= ~BIT(24); /* Turn off pll. */
+ for (c = 0; c < TIMEOUT && RCC.c_r & BIT(25); ++c)
+ ; /* Wait for OFF. */
+
+ if (c == TIMEOUT) {
+ return E_TIMEOUT;
+ }
+
+ return 0;
+}
+
+int pll_on()
+{
+ uint32_t c;
+
+ RCC.c_r |= BIT(24); /* Turn on PLL. */
+ for (c = 0; c < TIMEOUT && !(RCC.c_r & BIT(25)); ++c)
+ ; /* Wait for RDY. */
+
+ if (c == TIMEOUT) {
+ return E_TIMEOUT;
+ }
+
+ return 0;
+}
+
+int configure_pll(
+ uint8_t pllp_div_factor, pll_divisor_t pllr, /* System clock divisor. */
+ pll_divisor_t pllq, /* Divison factor for PLL48M1CLK. */
+ pllp_divisor_t pllp, /* Divison factor for PLLSAI2CLK. */
+ uint8_t plln, /* PLL numerator. */
+ pllm_divisor_t pllm, /* PLL denominator. */
+ pll_src_t pllsrc /* PLL source */)
+{
+ if (RCC.c_r & BIT(25)) {
+ /* PLL must be off to configure it. */
+ return E_NOT_OFF;
+ }
+
+ /* Make sure inputs are valid. */
+ if (pllp_div_factor == 1 || pllp_div_factor > 31) {
+ return E_BADPLLP_DIV;
+ }
+ if (plln < 8 || plln > 86) {
+ return E_BADPLLN;
+ }
+
+ RCC.pllcfg_r = (pllp_div_factor << 27) | (pllr << 24) | (pllq << 20) |
+ (pllp << 16) | (plln << 8) | (pllm << 4) | (pllsrc << 0);
+
+ return 0;
+}
+
+int set_system_clock_MHz(uint8_t mhz)
+{
+ /* Set the source of the system colck to MSI temporarily. */
+ set_system_clock_src(SYSTEM_CLOCK_SRC_MSI);
+
+ if (mhz <= 8 || mhz > 80) {
+ return E_BAD_ARG;
+ }
+
+ pll_off();
+
+ configure_pll(
+ 0 /* pllp_div_factor */, PLL_DIVISOR_4 /* pllr: VCO / 4 = mhz MHz. */,
+ PLL_DIVISOR_4 /* pllq: VCO / 4 = mhz MHz */, PLLP_DIVISOR_7 /* pllp */,
+
+ /* The following set the frequency of VCO to (mhz*4)MHz: mhz * 1 * 4MHz.
+ */
+ mhz /* plln | mhz */, PLLM_DIVISOR_1 /* pllm | 01 */,
+ PLL_SRC_MSI /* pll src | 04 Mhz */);
+
+ pll_on();
+
+ /* Configure the flash to have 4 wait states. This is required at
+ * 80 MHz. */
+ FLASH.ac_r &= ~0x07;
+ FLASH.ac_r |= 0x04;
+
+ /* Set the source of the system colck to PLL. */
+ set_system_clock_src(SYSTEM_CLOCK_SRC_PLL);
+ return 0;
+}
+
+int set_system_clock_src(system_clock_src_t src)
+{
+ uint8_t value = RCC.cfg_r & ~0x03;
+ RCC.cfg_r = value | src;
+ return 0;
+}