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
121
122
123
124
125
126
127
128
129
130
131
|
/*
* This file sets the system clock to its full glory of 80Mhz
*/
#include "clock.h"
#include <stdint.h>
#include "flash.h"
#include "gpio.h"
#include "spin.h"
#define TIMEOUT 10000
int pll_off()
{
uint32_t c;
RCC.c.pllon = false;
for (c = 0; c < TIMEOUT && RCC.c.pllrdy; ++c)
; /* Wait for OFF. */
if (c == TIMEOUT) {
return E_TIMEOUT;
}
return 0;
}
int pll_on()
{
uint32_t c;
RCC.c.pllon = true;
for (c = 0; c < TIMEOUT && !RCC.c.pllrdy; ++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.pllrdy) {
/* 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;
}
union RCC_PLLCFGR tmp;
tmp.pllpdiv = pllp_div_factor;
tmp.pllr = pllr >> 1;
tmp.pllren = pllr & 1;
tmp.pllp = pllp >> 1;
tmp.pllpen = pllp & 1;
tmp.pllq = pllq >> 1;
tmp.pllqen = pllq & 1;
tmp.plln = plln;
tmp.pllm = pllm;
tmp.pllsrc = pllsrc;
RCC.pllcfg = tmp;
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,
PLL_DIVISOR_4,
PLL_DIVISOR_4,
PLLP_DIVISOR_7,
mhz,
PLLM_DIVISOR_1,
PLL_SRC_MSI);
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;
}
int enable_hsi(__IO rcc_t* rcc, bool enable)
{
uint32_t c;
rcc->c.hsion = !!enable;
for(c = 0; c < TIMEOUT && !rcc->c.hsirdy; ++ c)
;
if (c == TIMEOUT) {
return E_TIMEOUT;
}
return 0;
}
|