@@ -55,10 +55,10 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
55
55
// Set 1 waitstate to be safe
56
56
NVMCTRL -> CTRLB .reg = NVMCTRL_CTRLB_MANW | NVMCTRL_CTRLB_RWS (1 );
57
57
58
- int div = DFLL48M_FREQ / cpu_freq_arg ;
59
- peripheral_freq = cpu_freq = DFLL48M_FREQ / div ;
58
+ int div = MAX ( DFLL48M_FREQ / cpu_freq_arg , 1 ) ;
59
+ peripheral_freq = DFLL48M_FREQ / div ;
60
60
61
- // Enable GCLK output: 48M on both CCLK0 and GCLK2
61
+ // Enable GCLK output: 48MHz from DFLL48M on both CCLK0 and GCLK2
62
62
GCLK -> GENDIV .reg = GCLK_GENDIV_ID (0 ) | GCLK_GENDIV_DIV (div );
63
63
GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID (0 );
64
64
while (GCLK -> STATUS .bit .SYNCBUSY ) {
@@ -67,6 +67,32 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
67
67
GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID (2 );
68
68
while (GCLK -> STATUS .bit .SYNCBUSY ) {
69
69
}
70
+ // The comparison is >=, such that for 48MHz still the FDPLL96 is used for the CPU clock.
71
+ if (cpu_freq_arg >= 48000000 ) {
72
+ cpu_freq = cpu_freq_arg ;
73
+ // Connect GCLK1 to the FDPLL96 input.
74
+ GCLK -> CLKCTRL .reg = GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID_FDPLL | GCLK_CLKCTRL_CLKEN ;
75
+ while (GCLK -> STATUS .bit .SYNCBUSY ) {
76
+ }
77
+ // configure the FDPLL96
78
+ // CtrlB: Set the ref ource to GCLK, set the Wakup-Fast Flag.
79
+ SYSCTRL -> DPLLCTRLB .reg = SYSCTRL_DPLLCTRLB_REFCLK_GCLK | SYSCTRL_DPLLCTRLB_WUF ;
80
+ // Set the FDPLL ratio and enable the DPLL.
81
+ int ldr = cpu_freq_arg / FDPLL_REF_FREQ - 1 ;
82
+ SYSCTRL -> DPLLRATIO .reg = SYSCTRL_DPLLRATIO_LDR (ldr );
83
+ SYSCTRL -> DPLLCTRLA .reg = SYSCTRL_DPLLCTRLA_ENABLE ;
84
+ // Wait for the DPLL lock.
85
+ while (!SYSCTRL -> DPLLSTATUS .bit .LOCK ) {
86
+ }
87
+ // Finally switch GCLK0 to FDPLL96M.
88
+ GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DPLL96M | GCLK_GENCTRL_ID (0 );
89
+ while (GCLK -> STATUS .bit .SYNCBUSY ) {
90
+ }
91
+ } else {
92
+ cpu_freq = peripheral_freq ;
93
+ // Disable the FDPLL96M in case it was enabled.
94
+ SYSCTRL -> DPLLCTRLA .reg = 0 ;
95
+ }
70
96
if (cpu_freq >= 8000000 ) {
71
97
// Enable GCLK output: 48MHz on GCLK5 for USB
72
98
GCLK -> GENDIV .reg = GCLK_GENDIV_ID (5 ) | GCLK_GENDIV_DIV (1 );
@@ -136,17 +162,19 @@ void init_clocks(uint32_t cpu_freq) {
136
162
137
163
// SAMD21 Clock settings
138
164
//
139
- // GCLK0: 48MHz, source: DFLL48M, usage: CPU
140
- // GCLK1: 32kHz, source: XOSC32K or OSCULP32K or DFLL48M , usage: FDPLL96M reference
165
+ // GCLK0: 48MHz, source: DFLL48M or FDPLL96M , usage: CPU
166
+ // GCLK1: 32kHz, source: XOSC32K or OSCULP32K, usage: FDPLL96M reference
141
167
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
142
168
// GCLK3: 1Mhz, source: DFLL48M, usage: us-counter (TC4/TC5)
143
169
// GCLK4: 32kHz, source: XOSC32K, if crystal present, usage: DFLL48M reference
144
170
// GCLK5: 48MHz, source: DFLL48M, usage: USB
145
171
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
146
172
// DFLL48M: Reference sources:
147
173
// - in closed loop mode: eiter XOSC32K or OSCULP32K or USB clock
174
+ // from GCLK4.
148
175
// - in open loop mode: None
149
- // FDPLL96M: Not used (yet). Option to use it for the CPU clock.
176
+ // FDPLL96M: Reference source GCLK1
177
+ // Used for the CPU clock for freq >= 48Mhz
150
178
151
179
NVMCTRL -> CTRLB .bit .MANW = 1 ; // errata "Spurious Writes"
152
180
NVMCTRL -> CTRLB .bit .RWS = 1 ; // 1 read wait state for 48MHz
@@ -166,7 +194,7 @@ void init_clocks(uint32_t cpu_freq) {
166
194
GCLK -> GENDIV .reg = GCLK_GENDIV_ID (1 ) | GCLK_GENDIV_DIV (1 );
167
195
GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID (1 );
168
196
#else
169
- // Connect the GCLK1 to OSC32K via GCLK1 to the DFLL input and for further use.
197
+ // Connect the GCLK1 to OSC32K
170
198
GCLK -> GENDIV .reg = GCLK_GENDIV_ID (1 ) | GCLK_GENDIV_DIV (1 );
171
199
GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID (1 );
172
200
#endif
@@ -247,9 +275,9 @@ void init_clocks(uint32_t cpu_freq) {
247
275
while (!SYSCTRL -> PCLKSR .bit .DFLLRDY ) {
248
276
}
249
277
250
- // Enable 32768 Hz on GCLK1 for consistency
251
- GCLK -> GENDIV .reg = GCLK_GENDIV_ID (1 ) | GCLK_GENDIV_DIV (48016384 / 32768 );
252
- GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID (1 );
278
+ // Connect the GCLK1 to the XOSC32KULP
279
+ GCLK -> GENDIV .reg = GCLK_GENDIV_ID (1 ) | GCLK_GENDIV_DIV (1 );
280
+ GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID (1 );
253
281
while (GCLK -> STATUS .bit .SYNCBUSY ) {
254
282
}
255
283
// Set GCLK8 to 1 kHz.
0 commit comments