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 <robert@hammelrath.com>
pull/14133/head
robert-hh 2024-03-19 17:16:41 +01:00 zatwierdzone przez Damien George
rodzic b41360d119
commit e8e9a39a6d
5 zmienionych plików z 56 dodań i 29 usunięć

Wyświetl plik

@ -30,5 +30,5 @@ void init_clocks(uint32_t cpu_freq);
void set_cpu_freq(uint32_t cpu_freq);
uint32_t get_cpu_freq(void);
uint32_t get_peripheral_freq(void);
void check_usb_recovery_mode(void);
void check_usb_clock_recovery_mode(void);
void enable_sercom_clock(int id);

Wyświetl plik

@ -34,6 +34,7 @@
#include "shared/runtime/pyexec.h"
#include "shared/runtime/softtimer.h"
#include "shared/tinyusb/mp_usbd.h"
#include "clock_config.h"
extern uint8_t _sstack, _estack, _sheap, _eheap;
extern void adc_deinit_all(void);
@ -59,6 +60,7 @@ void samd_main(void) {
int ret = pyexec_file_if_exists("boot.py");
mp_usbd_init();
check_usb_clock_recovery_mode();
if (ret & PYEXEC_FORCED_EXIT) {
goto soft_reset_exit;

Wyświetl plik

@ -111,8 +111,29 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
SysTick_Config(cpu_freq / 1000);
}
void check_usb_recovery_mode(void) {
#if !MICROPY_HW_XOSC32K
static void sync_dfll48_with_xosc32kulp(void) {
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
// Connect GCLK4 to the DFLL input.
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK4 | GCLK_CLKCTRL_ID_DFLL48 | GCLK_CLKCTRL_CLKEN;
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Set the multiplication values. The offset of 16384 to the freq is for rounding.
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_MUL((CPU_FREQ + 16384) / 32768) |
SYSCTRL_DFLLMUL_FSTEP(1) | SYSCTRL_DFLLMUL_CSTEP(1);
while (SYSCTRL->PCLKSR.bit.DFLLRDY == 0) {
}
// Start the DFLL and wait for the PLL lock. We just wait for the fine lock, since
// coarse adjusting is bypassed.
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_WAITLOCK | SYSCTRL_DFLLCTRL_STABLE |
SYSCTRL_DFLLCTRL_BPLCKC | SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLLCKF) {
}
}
void check_usb_clock_recovery_mode(void) {
#if MICROPY_HW_DFLL_USB_SYNC
// Check USB status for up to 1 second. If not connected,
// switch DFLL48M back to open loop
for (int i = 0; i < 100; i++) {
@ -121,10 +142,9 @@ void check_usb_recovery_mode(void) {
}
mp_hal_delay_ms(10);
}
// Set/keep the open loop mode of the device.
SYSCTRL->DFLLVAL.reg = dfll48m_calibration;
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
#endif // MICROPY_HW_XOSC32K
// No USB sync. Use XOSC32KULP as clock reference for DFLL48M
sync_dfll48_with_xosc32kulp();
#endif
}
// Purpose of the #defines for the clock configuration.
@ -178,12 +198,12 @@ void init_clocks(uint32_t cpu_freq) {
// GCLK1: 32kHz, source: XOSC32K or OSCULP32K, usage: FDPLL96M reference
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
// GCLK3: 2Mhz, source: DFLL48M, usage: us-counter (TC4/TC5)
// GCLK4: 32kHz, source: XOSC32K, if crystal present, usage: DFLL48M reference
// GCLK4: 32kHz, source: XOSC32K or OSCULP32K, usage: DFLL48M reference
// GCLK5: 48MHz, source: DFLL48M, usage: USB
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
// DFLL48M: Reference sources:
// - in closed loop mode: either XOSC32K or OSCULP32K or USB clock
// from GCLK4.
// - in closed loop mode: either XOSC32K or OSCULP32K from GCLK4
// or USB clock.
// - in open loop mode: None
// FDPLL96M: Reference source GCLK1
// Used for the CPU clock for freq >= 48Mhz
@ -256,6 +276,17 @@ void init_clocks(uint32_t cpu_freq) {
#else // MICROPY_HW_XOSC32K
// Connect the GCLK1 to the XOSC32KULP
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(1);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(1);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Connect the GCLK4 to the XOSC32KULP
GCLK->GENDIV.reg = GCLK_GENDIV_ID(4) | GCLK_GENDIV_DIV(1);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(4);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
// Enable DFLL48M
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
@ -263,35 +294,30 @@ void init_clocks(uint32_t cpu_freq) {
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
>> FUSES_DFLL48M_COARSE_CAL_Pos;
uint32_t fine = (*((uint32_t *)FUSES_DFLL48M_FINE_CAL_ADDR) & FUSES_DFLL48M_FINE_CAL_Msk)
>> FUSES_DFLL48M_COARSE_CAL_Pos;
if (coarse == 0x3f) {
coarse = 0x1f;
}
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(511);
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine);
dfll48m_calibration = SYSCTRL_DFLLVAL_COARSE(coarse) | SYSCTRL_DFLLVAL_FINE(fine);
#if MICROPY_HW_DFLL_USB_SYNC
// Configure the DFLL48M for USB clock recovery.
// Will have to switch back if no USB
SYSCTRL->DFLLSYNC.bit.READREQ = 1;
dfll48m_calibration = SYSCTRL->DFLLVAL.reg;
// Set the Multiplication factor.
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1)
| SYSCTRL_DFLLMUL_MUL(48000);
// Set the mode to closed loop USB Recovery mode
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_USBCRM | SYSCTRL_DFLLCTRL_CCDIS
| SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ENABLE;
#else
// Set/keep the open loop mode of the device.
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
#endif
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
// Connect the GCLK1 to the XOSC32KULP
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(1);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(1);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
#else // MICROPY_HW_DFLL_USB_SYNC
sync_dfll48_with_xosc32kulp();
#endif // MICROPY_HW_DFLL_USB_SYNC
// Set GCLK8 to 1 kHz.
GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);

Wyświetl plik

@ -115,8 +115,8 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
SysTick_Config(cpu_freq / 1000);
}
void check_usb_recovery_mode(void) {
#if !MICROPY_HW_XOSC32K
void check_usb_clock_recovery_mode(void) {
#if MICROPY_HW_DFLL_USB_SYNC
// Check USB status for up to 1 second. If not connected,
// switch DFLL48M back to open loop
for (int i = 0; i < 100; i++) {
@ -144,7 +144,7 @@ void check_usb_recovery_mode(void) {
OSCCTRL->DFLLCTRLB.reg = 0;
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
}
#endif // MICROPY_HW_XOSC32K
#endif
}
// Purpose of the #defines for the clock configuration.

Wyświetl plik

@ -116,7 +116,6 @@ void samd_init(void) {
init_clocks(get_cpu_freq());
init_us_counter();
usb_init();
check_usb_recovery_mode();
#if defined(MCU_SAMD51)
mp_hal_ticks_cpu_enable();
#endif