Skip to content

Commit e8e9a39

Browse files
robert-hhdpgeorge
authored andcommitted
samd/mcu: Update clock config after changes to USB.
For all MCUs: run the test for USB clock recovery mode fallback after USB has been started. For samd21: change DFLL48 config from the open loop mode variant to sync with the XOSC32KULP. Matches better the 48MHz value. Signed-off-by: robert-hh <[email protected]>
1 parent b41360d commit e8e9a39

File tree

5 files changed

+56
-29
lines changed

5 files changed

+56
-29
lines changed

ports/samd/clock_config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,5 @@ void init_clocks(uint32_t cpu_freq);
3030
void set_cpu_freq(uint32_t cpu_freq);
3131
uint32_t get_cpu_freq(void);
3232
uint32_t get_peripheral_freq(void);
33-
void check_usb_recovery_mode(void);
33+
void check_usb_clock_recovery_mode(void);
3434
void enable_sercom_clock(int id);

ports/samd/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "shared/runtime/pyexec.h"
3535
#include "shared/runtime/softtimer.h"
3636
#include "shared/tinyusb/mp_usbd.h"
37+
#include "clock_config.h"
3738

3839
extern uint8_t _sstack, _estack, _sheap, _eheap;
3940
extern void adc_deinit_all(void);
@@ -59,6 +60,7 @@ void samd_main(void) {
5960
int ret = pyexec_file_if_exists("boot.py");
6061

6162
mp_usbd_init();
63+
check_usb_clock_recovery_mode();
6264

6365
if (ret & PYEXEC_FORCED_EXIT) {
6466
goto soft_reset_exit;

ports/samd/mcu/samd21/clock_config.c

Lines changed: 50 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,29 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
111111
SysTick_Config(cpu_freq / 1000);
112112
}
113113

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
116137
// Check USB status for up to 1 second. If not connected,
117138
// switch DFLL48M back to open loop
118139
for (int i = 0; i < 100; i++) {
@@ -121,10 +142,9 @@ void check_usb_recovery_mode(void) {
121142
}
122143
mp_hal_delay_ms(10);
123144
}
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
128148
}
129149

130150
// Purpose of the #defines for the clock configuration.
@@ -178,12 +198,12 @@ void init_clocks(uint32_t cpu_freq) {
178198
// GCLK1: 32kHz, source: XOSC32K or OSCULP32K, usage: FDPLL96M reference
179199
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
180200
// 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
182202
// GCLK5: 48MHz, source: DFLL48M, usage: USB
183203
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
184204
// 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.
187207
// - in open loop mode: None
188208
// FDPLL96M: Reference source GCLK1
189209
// Used for the CPU clock for freq >= 48Mhz
@@ -256,42 +276,48 @@ void init_clocks(uint32_t cpu_freq) {
256276

257277
#else // MICROPY_HW_XOSC32K
258278

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+
259290
// Enable DFLL48M
260291
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
261292
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
262293
}
263294

264295
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
265296
>> 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;
266299
if (coarse == 0x3f) {
267300
coarse = 0x1f;
268301
}
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);
270304

271305
#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;
276306
// Set the Multiplication factor.
277307
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1)
278308
| SYSCTRL_DFLLMUL_MUL(48000);
279309
// Set the mode to closed loop USB Recovery mode
280310
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_USBCRM | SYSCTRL_DFLLCTRL_CCDIS
281311
| 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-
287312
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
288313
}
289314

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+
295321
// Set GCLK8 to 1 kHz.
296322
GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
297323
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);

ports/samd/mcu/samd51/clock_config.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
115115
SysTick_Config(cpu_freq / 1000);
116116
}
117117

118-
void check_usb_recovery_mode(void) {
119-
#if !MICROPY_HW_XOSC32K
118+
void check_usb_clock_recovery_mode(void) {
119+
#if MICROPY_HW_DFLL_USB_SYNC
120120
// Check USB status for up to 1 second. If not connected,
121121
// switch DFLL48M back to open loop
122122
for (int i = 0; i < 100; i++) {
@@ -144,7 +144,7 @@ void check_usb_recovery_mode(void) {
144144
OSCCTRL->DFLLCTRLB.reg = 0;
145145
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
146146
}
147-
#endif // MICROPY_HW_XOSC32K
147+
#endif
148148
}
149149

150150
// Purpose of the #defines for the clock configuration.

ports/samd/samd_soc.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@ void samd_init(void) {
116116
init_clocks(get_cpu_freq());
117117
init_us_counter();
118118
usb_init();
119-
check_usb_recovery_mode();
120119
#if defined(MCU_SAMD51)
121120
mp_hal_ticks_cpu_enable();
122121
#endif

0 commit comments

Comments
 (0)