summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ports/samd/mcu/samd21/clock_config.c43
-rw-r--r--ports/samd/mcu/samd21/mpconfigmcu.h1
-rw-r--r--ports/samd/mcu/samd51/mpconfigmcu.h1
-rw-r--r--ports/samd/modmachine.c4
-rw-r--r--ports/samd/samd_soc.c2
5 files changed, 36 insertions, 15 deletions
diff --git a/ports/samd/mcu/samd21/clock_config.c b/ports/samd/mcu/samd21/clock_config.c
index 2402ed2e3..204a5294f 100644
--- a/ports/samd/mcu/samd21/clock_config.c
+++ b/ports/samd/mcu/samd21/clock_config.c
@@ -51,7 +51,36 @@ uint32_t get_peripheral_freq(void) {
}
void set_cpu_freq(uint32_t cpu_freq_arg) {
- cpu_freq = cpu_freq_arg;
+
+ // Set 1 waitstate to be safe
+ NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_MANW | NVMCTRL_CTRLB_RWS(1);
+
+ int div = DFLL48M_FREQ / cpu_freq_arg;
+ peripheral_freq = cpu_freq = DFLL48M_FREQ / div;
+
+ // Enable GCLK output: 48M on both CCLK0 and GCLK2
+ GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(div);
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(0);
+ while (GCLK->STATUS.bit.SYNCBUSY) {
+ }
+ GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(div);
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(2);
+ while (GCLK->STATUS.bit.SYNCBUSY) {
+ }
+ if (cpu_freq >= 8000000) {
+ // Enable GCLK output: 48MHz on GCLK5 for USB
+ GCLK->GENDIV.reg = GCLK_GENDIV_ID(5) | GCLK_GENDIV_DIV(1);
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(5);
+ while (GCLK->STATUS.bit.SYNCBUSY) {
+ }
+ } else {
+ // Disable GCLK output on GCLK5 for USB, since USB is not reliable below 8 Mhz.
+ GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(5);
+ while (GCLK->STATUS.bit.SYNCBUSY) {
+ }
+ }
+ // Set 0 waitstates for slower CPU clock
+ NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_MANW | NVMCTRL_CTRLB_RWS(cpu_freq > 24000000 ? 1 : 0);
}
void check_usb_recovery_mode(void) {
@@ -76,6 +105,7 @@ void init_clocks(uint32_t cpu_freq) {
// GCLK2: 48MHz from DFLL for Peripherals
// GCLK3: 1Mhz for the us-counter (TC4/TC5)
// GCLK4: 32kHz from crystal, if present
+ // GCLK5: 48MHz from DFLL for USB
// GCLK8: 1kHz clock for WDT
NVMCTRL->CTRLB.bit.MANW = 1; // errata "Spurious Writes"
@@ -180,15 +210,7 @@ void init_clocks(uint32_t cpu_freq) {
#endif // MICROPY_HW_XOSC32K
- // Enable GCLK output: 48M on both CCLK0 and GCLK2
- GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(1);
- GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(0);
- while (GCLK->STATUS.bit.SYNCBUSY) {
- }
- GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(1);
- GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(2);
- while (GCLK->STATUS.bit.SYNCBUSY) {
- }
+ set_cpu_freq(cpu_freq);
// Enable GCLK output: 1MHz on GCLK3 for TC4
GCLK->GENDIV.reg = GCLK_GENDIV_ID(3) | GCLK_GENDIV_DIV(48);
@@ -200,7 +222,6 @@ void init_clocks(uint32_t cpu_freq) {
GCLK->GENCTRL.reg = GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K | GCLK_GENCTRL_ID(8);
while (GCLK->STATUS.bit.SYNCBUSY) {
}
-
}
void enable_sercom_clock(int id) {
diff --git a/ports/samd/mcu/samd21/mpconfigmcu.h b/ports/samd/mcu/samd21/mpconfigmcu.h
index a84b31276..e0af60552 100644
--- a/ports/samd/mcu/samd21/mpconfigmcu.h
+++ b/ports/samd/mcu/samd21/mpconfigmcu.h
@@ -19,6 +19,7 @@
#define CPU_FREQ (48000000)
#define DFLL48M_FREQ (48000000)
+#define MAX_CPU_FREQ (48000000)
#define IRQ_PRI_PENDSV ((1 << __NVIC_PRIO_BITS) - 1)
diff --git a/ports/samd/mcu/samd51/mpconfigmcu.h b/ports/samd/mcu/samd51/mpconfigmcu.h
index 19193992f..819bc1bb1 100644
--- a/ports/samd/mcu/samd51/mpconfigmcu.h
+++ b/ports/samd/mcu/samd51/mpconfigmcu.h
@@ -26,6 +26,7 @@ unsigned long trng_random_u32(void);
#define CPU_FREQ (120000000)
#define DFLL48M_FREQ (48000000)
+#define MAX_CPU_FREQ (200000000)
#define DPLLx_REF_FREQ (32768)
#define NVIC_PRIORITYGROUP_4 ((uint32_t)0x00000003)
diff --git a/ports/samd/modmachine.c b/ports/samd/modmachine.c
index d16b66064..21d700ac3 100644
--- a/ports/samd/modmachine.c
+++ b/ports/samd/modmachine.c
@@ -67,13 +67,11 @@ STATIC mp_obj_t machine_freq(size_t n_args, const mp_obj_t *args) {
if (n_args == 0) {
return MP_OBJ_NEW_SMALL_INT(get_cpu_freq());
} else {
- #if defined(MCU_SAMD51)
uint32_t freq = mp_obj_get_int(args[0]);
- if (freq >= 1000000 && freq <= 200000000) {
+ if (freq >= 1000000 && freq <= MAX_CPU_FREQ) {
set_cpu_freq(freq);
SysTick_Config(get_cpu_freq() / 1000);
}
- #endif
return mp_const_none;
}
}
diff --git a/ports/samd/samd_soc.c b/ports/samd/samd_soc.c
index 113529aee..6d8348ebc 100644
--- a/ports/samd/samd_soc.c
+++ b/ports/samd/samd_soc.c
@@ -41,7 +41,7 @@
static void usb_init(void) {
// Init USB clock
#if defined(MCU_SAMD21)
- GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID_USB;
+ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK5 | GCLK_CLKCTRL_ID_USB;
PM->AHBMASK.bit.USB_ = 1;
PM->APBBMASK.bit.USB_ = 1;
uint8_t alt = 6; // alt G, USB