diff --git a/ports/atmel-samd/clocks.h b/ports/atmel-samd/clocks.h index 3421ae24c3..e78e6173d9 100644 --- a/ports/atmel-samd/clocks.h +++ b/ports/atmel-samd/clocks.h @@ -50,7 +50,9 @@ void reset_gclks(void); void connect_gclk_to_peripheral(uint8_t gclk, uint8_t peripheral); void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral); -void enable_clock_generator(uint8_t gclk, uint8_t source, uint16_t divisor); +void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor); void disable_clock_generator(uint8_t gclk); +void clock_init(void); + #endif // MICROPY_INCLUDED_ATMEL_SAMD_CLOCKS_H diff --git a/ports/atmel-samd/samd21_clocks.c b/ports/atmel-samd/samd21_clocks.c index 727c0a3d59..b695a7fe8a 100644 --- a/ports/atmel-samd/samd21_clocks.c +++ b/ports/atmel-samd/samd21_clocks.c @@ -57,9 +57,19 @@ void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral) { GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(peripheral) | GCLK_CLKCTRL_GEN(gclk); } -void enable_clock_generator(uint8_t gclk, uint8_t source, uint16_t divisor) { +void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor) { + uint32_t divsel = 0; + if (gclk == 2 && divisor > 31) { + divsel = GCLK_GENCTRL_DIVSEL; + for (int i = 15; i > 4; i++) { + if (divisor & (1 << i)) { + divisor = i - 1; + break; + } + } + } GCLK->GENDIV.reg = GCLK_GENDIV_ID(gclk) | GCLK_GENDIV_DIV(divisor); - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk) | GCLK_GENCTRL_SRC(source) | GCLK_GENCTRL_GENEN; + GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk) | GCLK_GENCTRL_SRC(source) | divsel | GCLK_GENCTRL_OE | GCLK_GENCTRL_GENEN; while (GCLK->STATUS.bit.SYNCBUSY != 0) {} } @@ -67,3 +77,48 @@ void disable_clock_generator(uint8_t gclk) { GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(gclk); while (GCLK->STATUS.bit.SYNCBUSY != 0) {} } + +static void init_clock_source_osc8m(void) { + // Preserve CALIB and FRANGE + SYSCTRL->OSC8M.bit.ONDEMAND = 0; + SYSCTRL->OSC8M.bit.PRESC = 3; + SYSCTRL->OSC8M.bit.ENABLE = 1; + while (!SYSCTRL->PCLKSR.bit.OSC8MRDY) {} +} + +static void init_clock_source_osc32k(void) { + uint32_t calib = (*((uint32_t *)FUSES_OSC32K_CAL_ADDR) & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos; + SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) | + SYSCTRL_OSC32K_EN32K | + SYSCTRL_OSC32K_ENABLE; + while (!SYSCTRL->PCLKSR.bit.OSC32KRDY) {} +} + +static void init_clock_source_dfll48m(void) { + SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {} + SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(1) | + SYSCTRL_DFLLMUL_FSTEP(1) | + SYSCTRL_DFLLMUL_MUL(48000); + uint32_t coarse = (*((uint32_t *)FUSES_DFLL48M_COARSE_CAL_ADDR) & FUSES_DFLL48M_COARSE_CAL_Msk) >> FUSES_DFLL48M_COARSE_CAL_Pos; + if (coarse == 0x3f) + coarse = 0x1f; + SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) | + SYSCTRL_DFLLVAL_FINE(512); + SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_CCDIS | + SYSCTRL_DFLLCTRL_USBCRM | + SYSCTRL_DFLLCTRL_MODE | + SYSCTRL_DFLLCTRL_ENABLE; + while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {} + while (GCLK->STATUS.bit.SYNCBUSY) {} +} + +void clock_init(void) +{ + init_clock_source_osc8m(); + init_clock_source_osc32k(); + enable_clock_generator(0, GCLK_GENCTRL_SRC_DFLL48M_Val, 1); + enable_clock_generator(1, GCLK_GENCTRL_SRC_DFLL48M_Val, 150); + init_clock_source_dfll48m(); + enable_clock_generator(2, GCLK_GENCTRL_SRC_OSC32K_Val, 32); +} diff --git a/ports/atmel-samd/samd51_clocks.c b/ports/atmel-samd/samd51_clocks.c index 3bd458582b..72f3de871e 100644 --- a/ports/atmel-samd/samd51_clocks.c +++ b/ports/atmel-samd/samd51_clocks.c @@ -51,7 +51,7 @@ void disconnect_gclk_from_peripheral(uint8_t gclk, uint8_t peripheral) { GCLK->PCHCTRL[peripheral].reg = 0; } -void enable_clock_generator(uint8_t gclk, uint8_t source, uint16_t divisor) { +void enable_clock_generator(uint8_t gclk, uint32_t source, uint16_t divisor) { GCLK->GENCTRL[gclk].reg = GCLK_GENCTRL_SRC(source) | GCLK_GENCTRL_DIV(divisor) | GCLK_GENCTRL_GENEN; while ((GCLK->SYNCBUSY.vec.GENCTRL & (1 << gclk)) != 0) {} } diff --git a/ports/atmel-samd/supervisor/port.c b/ports/atmel-samd/supervisor/port.c index 3ac9cbfc96..8d069e7741 100644 --- a/ports/atmel-samd/supervisor/port.c +++ b/ports/atmel-samd/supervisor/port.c @@ -120,8 +120,14 @@ safe_mode_t port_init(void) { } #endif +#ifdef SAMD21 + hri_nvmctrl_set_CTRLB_RWS_bf(NVMCTRL, 2); + _pm_init(); + clock_init(); +#endif +#ifdef SAMD51 init_mcu(); - +#endif board_init(); // Configure millisecond timer initialization.