diff --git a/boards/saml21-xpro/include/periph_conf.h b/boards/saml21-xpro/include/periph_conf.h index 35ac5b5cc0..23418e3be6 100644 --- a/boards/saml21-xpro/include/periph_conf.h +++ b/boards/saml21-xpro/include/periph_conf.h @@ -32,7 +32,7 @@ extern "C" { /** * @brief GCLK reference speed */ -#define CLOCK_CORECLOCK (16000000U) +#define CLOCK_CORECLOCK (48000000U) /** * @name Timer peripheral configuration @@ -45,8 +45,8 @@ static const tc32_conf_t timer_config[] = { .mclk = &MCLK->APBCMASK.reg, .mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1, .gclk_id = TC0_GCLK_ID, - .gclk_src = SAM0_GCLK_MAIN, - .prescaler = TC_CTRLA_PRESCALER(4), + .gclk_src = SAM0_GCLK_8MHZ, + .prescaler = TC_CTRLA_PRESCALER(3), .flags = TC_CTRLA_MODE_COUNT32, } }; diff --git a/boards/samr30-xpro/include/periph_conf.h b/boards/samr30-xpro/include/periph_conf.h index f7601f23e3..2cbcadadcb 100644 --- a/boards/samr30-xpro/include/periph_conf.h +++ b/boards/samr30-xpro/include/periph_conf.h @@ -28,7 +28,7 @@ extern "C" { /** * @brief GCLK reference speed */ -#define CLOCK_CORECLOCK (16000000U) +#define CLOCK_CORECLOCK (48000000U) /** * @name Timer peripheral configuration @@ -41,8 +41,8 @@ static const tc32_conf_t timer_config[] = { .mclk = &MCLK->APBCMASK.reg, .mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1, .gclk_id = TC0_GCLK_ID, - .gclk_src = SAM0_GCLK_MAIN, - .prescaler = TC_CTRLA_PRESCALER(4), + .gclk_src = SAM0_GCLK_8MHZ, + .prescaler = TC_CTRLA_PRESCALER(3), .flags = TC_CTRLA_MODE_COUNT32, } }; diff --git a/boards/samr34-xpro/include/periph_conf.h b/boards/samr34-xpro/include/periph_conf.h index 80bb0184e8..1a6c66d234 100644 --- a/boards/samr34-xpro/include/periph_conf.h +++ b/boards/samr34-xpro/include/periph_conf.h @@ -29,7 +29,7 @@ extern "C" { /** * @brief GCLK reference speed */ -#define CLOCK_CORECLOCK (16000000U) +#define CLOCK_CORECLOCK (48000000U) /** * @name Timer peripheral configuration @@ -42,8 +42,8 @@ static const tc32_conf_t timer_config[] = { .mclk = &MCLK->APBCMASK.reg, .mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1, .gclk_id = TC0_GCLK_ID, - .gclk_src = SAM0_GCLK_MAIN, - .prescaler = TC_CTRLA_PRESCALER(4), + .gclk_src = SAM0_GCLK_8MHZ, + .prescaler = TC_CTRLA_PRESCALER(3), .flags = TC_CTRLA_MODE_COUNT32, } }; diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index 03e3b1dd1f..a8ca51ad65 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -75,6 +75,8 @@ uint32_t sam0_gclk_freq(uint8_t id) switch (id) { case SAM0_GCLK_MAIN: return CLOCK_CORECLOCK; + case SAM0_GCLK_8MHZ: + return 8000000; case SAM0_GCLK_32KHZ: return 32768; default: @@ -82,6 +84,48 @@ uint32_t sam0_gclk_freq(uint8_t id) } } +static void _dfll_setup(void) +{ +#if (CLOCK_CORECLOCK == 48000000U) || defined (MODULE_PERIPH_USBDEV) + GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_CHEN | + GCLK_PCHCTRL_GEN_GCLK2; + + /* wait for sync */ + while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg & GCLK_PCHCTRL_CHEN)) {} + + OSCCTRL->DFLLCTRL.reg = OSCCTRL_DFLLCTRL_ENABLE; + /* Wait for write synchronization */ + while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) {} + OSCCTRL->DFLLVAL.reg = OSCCTRL_DFLLVAL_COARSE((*(uint32_t*)NVMCTRL_OTP5) + >> 26) | OSCCTRL_DFLLVAL_FINE(512); + + /* Wait for write synchronization */ + while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) {} + /* Generate a 48 Mhz clock from the 32KHz */ + OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP(0x08) | + OSCCTRL_DFLLMUL_FSTEP(0x08) | + OSCCTRL_DFLLMUL_MUL((48000000U/32768)); + + /* Disable DFLL before setting its configuration */ + OSCCTRL->DFLLCTRL.reg = 0; + while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) {} + /* Write full configuration to DFLL control register */ + OSCCTRL->DFLLCTRL.reg = OSCCTRL_DFLLCTRL_WAITLOCK | + OSCCTRL_DFLLCTRL_MODE | + OSCCTRL_DFLLCTRL_CCDIS | + OSCCTRL_DFLLCTRL_BPLCKC | + OSCCTRL_DFLLCTRL_ENABLE; + + /* Ensure COARSE and FINE are locked */ + while ((!(OSCCTRL->STATUS.bit.DFLLLCKC)) && (!(OSCCTRL->STATUS.bit.DFLLLCKF))) {} + while (!(OSCCTRL->STATUS.bit.DFLLRDY)) {} + + /* Enable NVMCTRL */ + MCLK->APBBMASK.reg |= MCLK_APBBMASK_NVMCTRL; + /* Set Wait State to meet requirements */ + NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(3); +#endif +} /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -90,6 +134,14 @@ void cpu_init(void) /* disable the watchdog timer */ WDT->CTRLA.bit.ENABLE = 0; + /* Disable the RTC module to prevent synchronization issues during CPU init + if the RTC was running from a previous boot (e.g wakeup from backup) */ + if (RTC->MODE2.CTRLA.bit.ENABLE) { + while (RTC->MODE2.SYNCBUSY.reg) {} + RTC->MODE2.CTRLA.bit.ENABLE = 0; + while (RTC->MODE2.SYNCBUSY.reg) {} + } + /* initialize the Cortex-M core */ cortexm_init(); @@ -125,14 +177,36 @@ void cpu_init(void) _osc32k_setup(); _xosc32k_setup(); - /* Setup GCLK generators */ - _gclk_setup(SAM0_GCLK_MAIN, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); #if EXTERNAL_OSC32_SOURCE _gclk_setup(SAM0_GCLK_32KHZ, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K); #else _gclk_setup(SAM0_GCLK_32KHZ, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K); #endif + _dfll_setup(); + + /* Setup GCLK generators */ +#if (CLOCK_CORECLOCK == 16000000U) + _gclk_setup(SAM0_GCLK_MAIN, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); +#elif (CLOCK_CORECLOCK == 48000000U) + _gclk_setup(SAM0_GCLK_MAIN, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M); +#else +#error "Please select a valid CPU frequency" +#endif + + /* Ensure APB Backup domain clock is within the 6MHZ limit, BUPDIV value + must be a power of 2 and between 1(2^0) and 128(2^7) */ + for (unsigned i = 0; i < 8; i++) { + if (CLOCK_CORECLOCK / (1 << i) <= 6000000) { + MCLK->BUPDIV.reg = (1 << i); + while (!MCLK->INTFLAG.bit.CKRDY) {} + break; + } + } + /* clock used by timers */ + _gclk_setup(SAM0_GCLK_8MHZ, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M + | GCLK_GENCTRL_DIV(2)); + #ifdef MODULE_PERIPH_PM PM->CTRLA.reg = PM_CTRLA_MASK & (~PM_CTRLA_IORET); diff --git a/cpu/saml21/include/periph_cpu.h b/cpu/saml21/include/periph_cpu.h index 309caa8c09..485e6ee363 100644 --- a/cpu/saml21/include/periph_cpu.h +++ b/cpu/saml21/include/periph_cpu.h @@ -36,8 +36,9 @@ extern "C" { * @{ */ enum { - SAM0_GCLK_MAIN = 0, /**< 16 MHz main clock */ - SAM0_GCLK_32KHZ, /**< 32 kHz clock */ + SAM0_GCLK_MAIN = 0, /**< Main clock */ + SAM0_GCLK_8MHZ = 1, /**< 8MHz clock */ + SAM0_GCLK_32KHZ = 2, /**< 32 kHz clock */ }; /** @} */