@@ -111,8 +111,29 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
111
111
SysTick_Config (cpu_freq / 1000 );
112
112
}
113
113
114
- void check_usb_recovery_mode (void ) {
115
- #if !MICROPY_HW_XOSC32K
114
+ static void sync_dfll48_with_xosc32kulp (void ) {
115
+ SYSCTRL -> DFLLCTRL .reg = SYSCTRL_DFLLCTRL_ENABLE ;
116
+ while (!SYSCTRL -> PCLKSR .bit .DFLLRDY ) {
117
+ }
118
+ // Connect GCLK4 to the DFLL input.
119
+ GCLK -> CLKCTRL .reg = GCLK_CLKCTRL_GEN_GCLK4 | GCLK_CLKCTRL_ID_DFLL48 | GCLK_CLKCTRL_CLKEN ;
120
+ while (GCLK -> STATUS .bit .SYNCBUSY ) {
121
+ }
122
+ // Set the multiplication values. The offset of 16384 to the freq is for rounding.
123
+ SYSCTRL -> DFLLMUL .reg = SYSCTRL_DFLLMUL_MUL ((CPU_FREQ + 16384 ) / 32768 ) |
124
+ SYSCTRL_DFLLMUL_FSTEP (1 ) | SYSCTRL_DFLLMUL_CSTEP (1 );
125
+ while (SYSCTRL -> PCLKSR .bit .DFLLRDY == 0 ) {
126
+ }
127
+ // Start the DFLL and wait for the PLL lock. We just wait for the fine lock, since
128
+ // coarse adjusting is bypassed.
129
+ SYSCTRL -> DFLLCTRL .reg |= SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_STABLE |
130
+ SYSCTRL_DFLLCTRL_BPLCKC | SYSCTRL_DFLLCTRL_ENABLE ;
131
+ while (!SYSCTRL -> PCLKSR .bit .DFLLLCKF ) {
132
+ }
133
+ }
134
+
135
+ void check_usb_clock_recovery_mode (void ) {
136
+ #if MICROPY_HW_DFLL_USB_SYNC
116
137
// Check USB status for up to 1 second. If not connected,
117
138
// switch DFLL48M back to open loop
118
139
for (int i = 0 ; i < 100 ; i ++ ) {
@@ -121,10 +142,9 @@ void check_usb_recovery_mode(void) {
121
142
}
122
143
mp_hal_delay_ms (10 );
123
144
}
124
- // Set/keep the open loop mode of the device.
125
- SYSCTRL -> DFLLVAL .reg = dfll48m_calibration ;
126
- SYSCTRL -> DFLLCTRL .reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE ;
127
- #endif // MICROPY_HW_XOSC32K
145
+ // No USB sync. Use XOSC32KULP as clock reference for DFLL48M
146
+ sync_dfll48_with_xosc32kulp ();
147
+ #endif
128
148
}
129
149
130
150
// Purpose of the #defines for the clock configuration.
@@ -178,12 +198,12 @@ void init_clocks(uint32_t cpu_freq) {
178
198
// GCLK1: 32kHz, source: XOSC32K or OSCULP32K, usage: FDPLL96M reference
179
199
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
180
200
// GCLK3: 2Mhz, source: DFLL48M, usage: us-counter (TC4/TC5)
181
- // GCLK4: 32kHz, source: XOSC32K, if crystal present , usage: DFLL48M reference
201
+ // GCLK4: 32kHz, source: XOSC32K or OSCULP32K , usage: DFLL48M reference
182
202
// GCLK5: 48MHz, source: DFLL48M, usage: USB
183
203
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
184
204
// DFLL48M: Reference sources:
185
- // - in closed loop mode: either XOSC32K or OSCULP32K or USB clock
186
- // from GCLK4 .
205
+ // - in closed loop mode: either XOSC32K or OSCULP32K from GCLK4
206
+ // or USB clock .
187
207
// - in open loop mode: None
188
208
// FDPLL96M: Reference source GCLK1
189
209
// Used for the CPU clock for freq >= 48Mhz
@@ -256,42 +276,48 @@ void init_clocks(uint32_t cpu_freq) {
256
276
257
277
#else // MICROPY_HW_XOSC32K
258
278
279
+ // Connect the GCLK1 to the XOSC32KULP
280
+ GCLK -> GENDIV .reg = GCLK_GENDIV_ID (1 ) | GCLK_GENDIV_DIV (1 );
281
+ GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID (1 );
282
+ while (GCLK -> STATUS .bit .SYNCBUSY ) {
283
+ }
284
+ // Connect the GCLK4 to the XOSC32KULP
285
+ GCLK -> GENDIV .reg = GCLK_GENDIV_ID (4 ) | GCLK_GENDIV_DIV (1 );
286
+ GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID (4 );
287
+ while (GCLK -> STATUS .bit .SYNCBUSY ) {
288
+ }
289
+
259
290
// Enable DFLL48M
260
291
SYSCTRL -> DFLLCTRL .reg = SYSCTRL_DFLLCTRL_ENABLE ;
261
292
while (!SYSCTRL -> PCLKSR .bit .DFLLRDY ) {
262
293
}
263
294
264
295
uint32_t coarse = (* ((uint32_t * )FUSES_DFLL48M_COARSE_CAL_ADDR ) & FUSES_DFLL48M_COARSE_CAL_Msk )
265
296
>> FUSES_DFLL48M_COARSE_CAL_Pos ;
297
+ uint32_t fine = (* ((uint32_t * )FUSES_DFLL48M_FINE_CAL_ADDR ) & FUSES_DFLL48M_FINE_CAL_Msk )
298
+ >> FUSES_DFLL48M_COARSE_CAL_Pos ;
266
299
if (coarse == 0x3f ) {
267
300
coarse = 0x1f ;
268
301
}
269
- SYSCTRL -> DFLLVAL .reg = SYSCTRL_DFLLVAL_COARSE (coarse ) | SYSCTRL_DFLLVAL_FINE (511 );
302
+ SYSCTRL -> DFLLVAL .reg = SYSCTRL_DFLLVAL_COARSE (coarse ) | SYSCTRL_DFLLVAL_FINE (fine );
303
+ dfll48m_calibration = SYSCTRL_DFLLVAL_COARSE (coarse ) | SYSCTRL_DFLLVAL_FINE (fine );
270
304
271
305
#if MICROPY_HW_DFLL_USB_SYNC
272
- // Configure the DFLL48M for USB clock recovery.
273
- // Will have to switch back if no USB
274
- SYSCTRL -> DFLLSYNC .bit .READREQ = 1 ;
275
- dfll48m_calibration = SYSCTRL -> DFLLVAL .reg ;
276
306
// Set the Multiplication factor.
277
307
SYSCTRL -> DFLLMUL .reg = SYSCTRL_DFLLMUL_CSTEP (1 ) | SYSCTRL_DFLLMUL_FSTEP (1 )
278
308
| SYSCTRL_DFLLMUL_MUL (48000 );
279
309
// Set the mode to closed loop USB Recovery mode
280
310
SYSCTRL -> DFLLCTRL .reg = SYSCTRL_DFLLCTRL_USBCRM | SYSCTRL_DFLLCTRL_CCDIS
281
311
| SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ENABLE ;
282
- #else
283
- // Set/keep the open loop mode of the device.
284
- SYSCTRL -> DFLLCTRL .reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE ;
285
- #endif
286
-
287
312
while (!SYSCTRL -> PCLKSR .bit .DFLLRDY ) {
288
313
}
289
314
290
- // Connect the GCLK1 to the XOSC32KULP
291
- GCLK -> GENDIV .reg = GCLK_GENDIV_ID (1 ) | GCLK_GENDIV_DIV (1 );
292
- GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID (1 );
293
- while (GCLK -> STATUS .bit .SYNCBUSY ) {
294
- }
315
+ #else // MICROPY_HW_DFLL_USB_SYNC
316
+
317
+ sync_dfll48_with_xosc32kulp ();
318
+
319
+ #endif // MICROPY_HW_DFLL_USB_SYNC
320
+
295
321
// Set GCLK8 to 1 kHz.
296
322
GCLK -> GENDIV .reg = GCLK_GENDIV_ID (8 ) | GCLK_GENDIV_DIV (32 );
297
323
GCLK -> GENCTRL .reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID (8 );
0 commit comments