kopia lustrzana https://github.com/micropython/micropython
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
rodzic
b41360d119
commit
e8e9a39a6d
|
@ -30,5 +30,5 @@ void init_clocks(uint32_t cpu_freq);
|
||||||
void set_cpu_freq(uint32_t cpu_freq);
|
void set_cpu_freq(uint32_t cpu_freq);
|
||||||
uint32_t get_cpu_freq(void);
|
uint32_t get_cpu_freq(void);
|
||||||
uint32_t get_peripheral_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);
|
void enable_sercom_clock(int id);
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "shared/runtime/pyexec.h"
|
#include "shared/runtime/pyexec.h"
|
||||||
#include "shared/runtime/softtimer.h"
|
#include "shared/runtime/softtimer.h"
|
||||||
#include "shared/tinyusb/mp_usbd.h"
|
#include "shared/tinyusb/mp_usbd.h"
|
||||||
|
#include "clock_config.h"
|
||||||
|
|
||||||
extern uint8_t _sstack, _estack, _sheap, _eheap;
|
extern uint8_t _sstack, _estack, _sheap, _eheap;
|
||||||
extern void adc_deinit_all(void);
|
extern void adc_deinit_all(void);
|
||||||
|
@ -59,6 +60,7 @@ void samd_main(void) {
|
||||||
int ret = pyexec_file_if_exists("boot.py");
|
int ret = pyexec_file_if_exists("boot.py");
|
||||||
|
|
||||||
mp_usbd_init();
|
mp_usbd_init();
|
||||||
|
check_usb_clock_recovery_mode();
|
||||||
|
|
||||||
if (ret & PYEXEC_FORCED_EXIT) {
|
if (ret & PYEXEC_FORCED_EXIT) {
|
||||||
goto soft_reset_exit;
|
goto soft_reset_exit;
|
||||||
|
|
|
@ -111,8 +111,29 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
|
||||||
SysTick_Config(cpu_freq / 1000);
|
SysTick_Config(cpu_freq / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_usb_recovery_mode(void) {
|
static void sync_dfll48_with_xosc32kulp(void) {
|
||||||
#if !MICROPY_HW_XOSC32K
|
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,
|
// Check USB status for up to 1 second. If not connected,
|
||||||
// switch DFLL48M back to open loop
|
// switch DFLL48M back to open loop
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
|
@ -121,10 +142,9 @@ void check_usb_recovery_mode(void) {
|
||||||
}
|
}
|
||||||
mp_hal_delay_ms(10);
|
mp_hal_delay_ms(10);
|
||||||
}
|
}
|
||||||
// Set/keep the open loop mode of the device.
|
// No USB sync. Use XOSC32KULP as clock reference for DFLL48M
|
||||||
SYSCTRL->DFLLVAL.reg = dfll48m_calibration;
|
sync_dfll48_with_xosc32kulp();
|
||||||
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | SYSCTRL_DFLLCTRL_ENABLE;
|
#endif
|
||||||
#endif // MICROPY_HW_XOSC32K
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Purpose of the #defines for the clock configuration.
|
// 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
|
// GCLK1: 32kHz, source: XOSC32K or OSCULP32K, usage: FDPLL96M reference
|
||||||
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
|
// GCLK2: 1-48MHz, source: DFLL48M, usage: Peripherals
|
||||||
// GCLK3: 2Mhz, source: DFLL48M, usage: us-counter (TC4/TC5)
|
// 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
|
// GCLK5: 48MHz, source: DFLL48M, usage: USB
|
||||||
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
|
// GCLK8: 1kHz, source: XOSC32K or OSCULP32K, usage: WDT and RTC
|
||||||
// DFLL48M: Reference sources:
|
// DFLL48M: Reference sources:
|
||||||
// - in closed loop mode: either XOSC32K or OSCULP32K or USB clock
|
// - in closed loop mode: either XOSC32K or OSCULP32K from GCLK4
|
||||||
// from GCLK4.
|
// or USB clock.
|
||||||
// - in open loop mode: None
|
// - in open loop mode: None
|
||||||
// FDPLL96M: Reference source GCLK1
|
// FDPLL96M: Reference source GCLK1
|
||||||
// Used for the CPU clock for freq >= 48Mhz
|
// Used for the CPU clock for freq >= 48Mhz
|
||||||
|
@ -256,6 +276,17 @@ void init_clocks(uint32_t cpu_freq) {
|
||||||
|
|
||||||
#else // MICROPY_HW_XOSC32K
|
#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
|
// Enable DFLL48M
|
||||||
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
|
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
|
||||||
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
|
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)
|
uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk)
|
||||||
>> FUSES_DFLL48M_COARSE_CAL_Pos;
|
>> 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) {
|
if (coarse == 0x3f) {
|
||||||
coarse = 0x1f;
|
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
|
#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.
|
// Set the Multiplication factor.
|
||||||
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1)
|
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | SYSCTRL_DFLLMUL_FSTEP(1)
|
||||||
| SYSCTRL_DFLLMUL_MUL(48000);
|
| SYSCTRL_DFLLMUL_MUL(48000);
|
||||||
// Set the mode to closed loop USB Recovery mode
|
// Set the mode to closed loop USB Recovery mode
|
||||||
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_USBCRM | SYSCTRL_DFLLCTRL_CCDIS
|
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_USBCRM | SYSCTRL_DFLLCTRL_CCDIS
|
||||||
| SYSCTRL_DFLLCTRL_MODE | SYSCTRL_DFLLCTRL_ENABLE;
|
| 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) {
|
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect the GCLK1 to the XOSC32KULP
|
#else // MICROPY_HW_DFLL_USB_SYNC
|
||||||
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);
|
sync_dfll48_with_xosc32kulp();
|
||||||
while (GCLK->STATUS.bit.SYNCBUSY) {
|
|
||||||
}
|
#endif // MICROPY_HW_DFLL_USB_SYNC
|
||||||
|
|
||||||
// Set GCLK8 to 1 kHz.
|
// Set GCLK8 to 1 kHz.
|
||||||
GCLK->GENDIV.reg = GCLK_GENDIV_ID(8) | GCLK_GENDIV_DIV(32);
|
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);
|
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);
|
||||||
|
|
|
@ -115,8 +115,8 @@ void set_cpu_freq(uint32_t cpu_freq_arg) {
|
||||||
SysTick_Config(cpu_freq / 1000);
|
SysTick_Config(cpu_freq / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_usb_recovery_mode(void) {
|
void check_usb_clock_recovery_mode(void) {
|
||||||
#if !MICROPY_HW_XOSC32K
|
#if MICROPY_HW_DFLL_USB_SYNC
|
||||||
// Check USB status for up to 1 second. If not connected,
|
// Check USB status for up to 1 second. If not connected,
|
||||||
// switch DFLL48M back to open loop
|
// switch DFLL48M back to open loop
|
||||||
for (int i = 0; i < 100; i++) {
|
for (int i = 0; i < 100; i++) {
|
||||||
|
@ -144,7 +144,7 @@ void check_usb_recovery_mode(void) {
|
||||||
OSCCTRL->DFLLCTRLB.reg = 0;
|
OSCCTRL->DFLLCTRLB.reg = 0;
|
||||||
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
|
while (OSCCTRL->DFLLSYNC.bit.DFLLCTRLB == 1) {
|
||||||
}
|
}
|
||||||
#endif // MICROPY_HW_XOSC32K
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Purpose of the #defines for the clock configuration.
|
// Purpose of the #defines for the clock configuration.
|
||||||
|
|
|
@ -116,7 +116,6 @@ void samd_init(void) {
|
||||||
init_clocks(get_cpu_freq());
|
init_clocks(get_cpu_freq());
|
||||||
init_us_counter();
|
init_us_counter();
|
||||||
usb_init();
|
usb_init();
|
||||||
check_usb_recovery_mode();
|
|
||||||
#if defined(MCU_SAMD51)
|
#if defined(MCU_SAMD51)
|
||||||
mp_hal_ticks_cpu_enable();
|
mp_hal_ticks_cpu_enable();
|
||||||
#endif
|
#endif
|
||||||
|
|
Ładowanie…
Reference in New Issue