1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
/*
* This file sets the system clock to its full glory of 80Mhz
*/
#include "arch/stm32l4xxx/peripherals/clock.h"
#include <stdint.h>
#include "arch/stm32l4xxx/peripherals/flash.h"
#include "kern/init.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;
}
static _no_init uint8_t clock_mHz;
uint8_t get_clock_mhz()
{
return clock_mHz;
}
int set_system_clock_MHz(uint8_t mhz)
{
clock_mHz = 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;
}
|