summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/samd/clock_config.h2
-rw-r--r--ports/samd/main.c2
-rw-r--r--ports/samd/mcu/samd21/clock_config.c74
-rw-r--r--ports/samd/mcu/samd51/clock_config.c6
-rw-r--r--ports/samd/samd_soc.c1
5 files changed, 56 insertions, 29 deletions
diff --git a/ports/samd/clock_config.h b/ports/samd/clock_config.h
index 35b7e5328..b04529939 100644
--- a/ports/samd/clock_config.h
+++ b/ports/samd/clock_config.h
@@ -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);
diff --git a/ports/samd/main.c b/ports/samd/main.c
index 9f213f27d..2bbaf63e6 100644
--- a/ports/samd/main.c
+++ b/ports/samd/main.c
@@ -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;
diff --git a/ports/samd/mcu/samd21/clock_config.c b/ports/samd/mcu/samd21/clock_config.c
index d84ee5267..033d0f7c1 100644
--- a/ports/samd/mcu/samd21/clock_config.c
+++ b/ports/samd/mcu/samd21/clock_config.c
@@ -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);
diff --git a/ports/samd/mcu/samd51/clock_config.c b/ports/samd/mcu/samd51/clock_config.c
index b30cc46f2..77b6e4c63 100644
--- a/ports/samd/mcu/samd51/clock_config.c
+++ b/ports/samd/mcu/samd51/clock_config.c
@@ -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.
diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c
index 5e6c5c4fc..1c8d49d15 100644
--- a/ports/samd/samd_soc.c
+++ b/ports/samd/samd_soc.c
@@ -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