From 3f3e49d391c2102e32b9b2fc7d75a6d0006e9efb Mon Sep 17 00:00:00 2001 From: Dan Evans Date: Tue, 29 Aug 2017 15:44:27 -0600 Subject: [PATCH] second attempt at combining clock generators --- .../arduino-mkr-common/include/periph_conf.h | 40 +--- boards/arduino-zero/include/periph_conf.h | 40 +--- boards/samd21-xpro/include/periph_conf.h | 40 +--- boards/samr21-xpro/include/periph_conf.h | 40 +--- boards/sodaq-autonomo/include/periph_conf.h | 40 +--- cpu/samd21/cpu.c | 201 +++++++++++------- cpu/samd21/include/periph_clock_config.h | 55 ++--- cpu/samd21/include/periph_cpu.h | 7 + cpu/samd21/periph/gpio.c | 8 +- cpu/samd21/periph/rtc.c | 6 +- cpu/samd21/periph/rtt.c | 13 +- cpu/samd21/periph/timer.c | 8 +- 12 files changed, 220 insertions(+), 278 deletions(-) diff --git a/boards/arduino-mkr-common/include/periph_conf.h b/boards/arduino-mkr-common/include/periph_conf.h index eca16a3caaafd..3a165539da495 100644 --- a/boards/arduino-mkr-common/include/periph_conf.h +++ b/boards/arduino-mkr-common/include/periph_conf.h @@ -31,14 +31,13 @@ extern "C" { #endif /** - * @name External oscillator and clock configuration + * @name External oscillator and clock configuration * * There are three choices for selection of CORECLOCK: * - * - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz - * - usage of the PLL fed by the internal 8MHz oscillator divided by 8 - * - usage of the internal 8MHz oscillator directly, divided by N if needed - * + * CLOCK_USE_PLL: PLL fed by the internal 8Mhz oscillator + * CLOCK_USE_DFLL: DFLL fed by external 32.768 kHz oscillator + * CLOCK_USE_8MHZ: internal 8MHz oscillator * * The PLL option allows for the usage of a wider frequency range and a more * stable clock with less jitter. This is why this option is default. @@ -46,11 +45,13 @@ extern "C" { * The target frequency is computed from the PLL multiplier and the PLL divisor. * Use the following formula to compute your values: * - * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / PLL_DIV + * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / DIV * * NOTE: The PLL circuit does not run with less than 32MHz while the maximum PLL * frequency is 96MHz. So PLL_MULL must be between 31 and 95! * + * The DFLL option can only be run at 48 MHz, but combined with an external + * oscillator it will provide the most clock stability. * * The internal Oscillator used directly can lead to a slightly better power * efficiency to the cost of a less stable clock. Use this option when you know @@ -62,29 +63,8 @@ extern "C" { * * @{ */ -#define CLOCK_USE_PLL (1) -#define CLOCK_USE_XOSC32_DFLL (0) -#define CLOCK_USE_8MHZ_DEFAULT (0) - -#if CLOCK_USE_PLL - /* edit these values to adjust the PLL output frequency */ -#define CLOCK_PLL_MUL (47U) /* must be >= 31 & <= 95 */ -#define CLOCK_PLL_DIV (1U) /* adjust to your needs */ - /* generate the actual used core clock frequency */ -#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV) -#elif CLOCK_USE_XOSC32_DFLL - /* Settings for 32 kHz external oscillator and 48 MHz DFLL */ -#define CLOCK_CORECLOCK (48000000UL) -#define CLOCK_XOSC32K (32768UL) -#define GEN2_XOSC32 (1) -#elif CLOCK_USE_8MHZ_DEFAULT - /* edit this value to your needs */ -#define CLOCK_DIV (1U) - /* generate the actual core clock frequency */ -#define CLOCK_CORECLOCK (8000000 / CLOCK_DIV) -#else -#error Need to select a core clock -#endif +#define CLOCK_SRC (CLOCK_USE_PLL) +#define CLOCK_CORECLOCK (48000000U) /** @} */ /** @@ -240,7 +220,7 @@ static const spi_conf_t spi_config[] = { #define I2C_0_SCL GPIO_PIN(PA, 9) /* SERCOM0-SCL, on-board pull-up */ #define I2C_0_MUX GPIO_MUX_C /** @} */ - + /** * @name RTC configuration * @{ diff --git a/boards/arduino-zero/include/periph_conf.h b/boards/arduino-zero/include/periph_conf.h index c59b803bd3346..1b8dfbec4e051 100644 --- a/boards/arduino-zero/include/periph_conf.h +++ b/boards/arduino-zero/include/periph_conf.h @@ -33,14 +33,13 @@ extern "C" { #endif /** - * @name External oscillator and clock configuration + * @name External oscillator and clock configuration * * There are three choices for selection of CORECLOCK: * - * - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz - * - usage of the PLL fed by the internal 8MHz oscillator divided by 8 - * - usage of the internal 8MHz oscillator directly, divided by N if needed - * + * CLOCK_USE_PLL: PLL fed by the internal 8Mhz oscillator + * CLOCK_USE_DFLL: DFLL fed by external 32.768 kHz oscillator + * CLOCK_USE_8MHZ: internal 8MHz oscillator * * The PLL option allows for the usage of a wider frequency range and a more * stable clock with less jitter. This is why this option is default. @@ -48,11 +47,13 @@ extern "C" { * The target frequency is computed from the PLL multiplier and the PLL divisor. * Use the following formula to compute your values: * - * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / PLL_DIV + * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / DIV * * NOTE: The PLL circuit does not run with less than 32MHz while the maximum PLL * frequency is 96MHz. So PLL_MULL must be between 31 and 95! * + * The DFLL option can only be run at 48 MHz, but combined with an external + * oscillator it will provide the most clock stability. * * The internal Oscillator used directly can lead to a slightly better power * efficiency to the cost of a less stable clock. Use this option when you know @@ -64,29 +65,8 @@ extern "C" { * * @{ */ -#define CLOCK_USE_PLL (1) -#define CLOCK_USE_XOSC32_DFLL (0) -#define CLOCK_USE_8MHZ_DEFAULT (0) - -#if CLOCK_USE_PLL - /* edit these values to adjust the PLL output frequency */ -#define CLOCK_PLL_MUL (47U) /* must be >= 31 & <= 95 */ -#define CLOCK_PLL_DIV (1U) /* adjust to your needs */ - /* generate the actual used core clock frequency */ -#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV) -#elif CLOCK_USE_XOSC32_DFLL - /* Settings for 32 kHz external oscillator and 48 MHz DFLL */ -#define CLOCK_CORECLOCK (48000000UL) -#define CLOCK_XOSC32K (32768UL) -#define GEN2_XOSC32 (1) -#elif CLOCK_USE_8MHZ_DEFAULT - /* edit this value to your needs */ -#define CLOCK_DIV (1U) - /* generate the actual core clock frequency */ -#define CLOCK_CORECLOCK (8000000 / CLOCK_DIV) -#else -#error Need to select a core clock -#endif +#define CLOCK_SRC (CLOCK_USE_PLL) +#define CLOCK_CORECLOCK (48000000U) /** @} */ /** @@ -243,7 +223,7 @@ static const spi_conf_t spi_config[] = { #define RTT_ISR isr_rtc #define RTT_MAX_VALUE (0xffffffff) #define RTT_FREQUENCY (32768U) /* in Hz. For changes see `rtt.c` */ -#define XOSC32_RUNSTDBY (1) /* Keep RTT running in sleep states */ +#define RTT_RUNSTDBY (1) /* Keep RTT running in sleep states */ /** @} */ #ifdef __cplusplus diff --git a/boards/samd21-xpro/include/periph_conf.h b/boards/samd21-xpro/include/periph_conf.h index 748ef201abb0a..2bcc8f0e2ee43 100644 --- a/boards/samd21-xpro/include/periph_conf.h +++ b/boards/samd21-xpro/include/periph_conf.h @@ -32,14 +32,13 @@ extern "C" { #endif /** - * @name External oscillator and clock configuration + * @name External oscillator and clock configuration * * There are three choices for selection of CORECLOCK: * - * - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz - * - usage of the PLL fed by the internal 8MHz oscillator divided by 8 - * - usage of the internal 8MHz oscillator directly, divided by N if needed - * + * CLOCK_USE_PLL: PLL fed by the internal 8Mhz oscillator + * CLOCK_USE_DFLL: DFLL fed by external 32.768 kHz oscillator + * CLOCK_USE_8MHZ: internal 8MHz oscillator * * The PLL option allows for the usage of a wider frequency range and a more * stable clock with less jitter. This is why this option is default. @@ -47,11 +46,13 @@ extern "C" { * The target frequency is computed from the PLL multiplier and the PLL divisor. * Use the following formula to compute your values: * - * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / PLL_DIV + * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / DIV * * NOTE: The PLL circuit does not run with less than 32MHz while the maximum PLL * frequency is 96MHz. So PLL_MULL must be between 31 and 95! * + * The DFLL option can only be run at 48 MHz, but combined with an external + * oscillator it will provide the most clock stability. * * The internal Oscillator used directly can lead to a slightly better power * efficiency to the cost of a less stable clock. Use this option when you know @@ -63,29 +64,8 @@ extern "C" { * * @{ */ -#define CLOCK_USE_PLL (1) -#define CLOCK_USE_XOSC32_DFLL (0) -#define CLOCK_USE_8MHZ_DEFAULT (0) - -#if CLOCK_USE_PLL -/* edit these values to adjust the PLL output frequency */ -#define CLOCK_PLL_MUL (47U) /* must be >= 31 & <= 95 */ -#define CLOCK_PLL_DIV (1U) /* adjust to your needs */ -/* generate the actual used core clock frequency */ -#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV) -#elif CLOCK_USE_XOSC32_DFLL -/* Settings for 32 kHz external oscillator and 48 MHz DFLL */ -#define CLOCK_CORECLOCK (48000000UL) -#define CLOCK_XOSC32K (32768UL) -#define GEN2_XOSC32 (1) -#elif CLOCK_USE_8MHZ_DEFAULT -/* edit this value to your needs */ -#define CLOCK_DIV (1U) -/* generate the actual core clock frequency */ -#define CLOCK_CORECLOCK (8000000 / CLOCK_DIV) -#else -#error Need to select a core clock -#endif +#define CLOCK_SRC (CLOCK_USE_8MHZ) +#define CLOCK_CORECLOCK (8000000U) /** @} */ /** @@ -274,7 +254,7 @@ static const spi_conf_t spi_config[] = { #define RTT_ISR isr_rtc #define RTT_MAX_VALUE (0xffffffff) #define RTT_FREQUENCY (32768U) /* in Hz. For changes see `rtt.c` */ -#define XOSC32_RUNSTDBY (1) /* Keep RTT running in sleep states */ +#define RTT_RUNSTDBY (1) /* Keep RTT running in sleep states */ /** @} */ /** diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 63421ccded994..ad981a96ffb15 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -32,14 +32,13 @@ extern "C" { #endif /** - * @name External oscillator and clock configuration + * @name External oscillator and clock configuration * * There are three choices for selection of CORECLOCK: * - * - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz - * - usage of the PLL fed by the internal 8MHz oscillator divided by 8 - * - usage of the internal 8MHz oscillator directly, divided by N if needed - * + * CLOCK_USE_PLL: PLL fed by the internal 8Mhz oscillator + * CLOCK_USE_DFLL: DFLL fed by external 32.768 kHz oscillator + * CLOCK_USE_8MHZ: internal 8MHz oscillator * * The PLL option allows for the usage of a wider frequency range and a more * stable clock with less jitter. This is why this option is default. @@ -47,11 +46,13 @@ extern "C" { * The target frequency is computed from the PLL multiplier and the PLL divisor. * Use the following formula to compute your values: * - * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / PLL_DIV + * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / DIV * * NOTE: The PLL circuit does not run with less than 32MHz while the maximum PLL * frequency is 96MHz. So PLL_MULL must be between 31 and 95! * + * The DFLL option can only be run at 48 MHz, but combined with an external + * oscillator it will provide the most clock stability. * * The internal Oscillator used directly can lead to a slightly better power * efficiency to the cost of a less stable clock. Use this option when you know @@ -63,29 +64,8 @@ extern "C" { * * @{ */ -#define CLOCK_USE_PLL (1) -#define CLOCK_USE_XOSC32_DFLL (0) -#define CLOCK_USE_8MHZ_DEFAULT (0) - -#if CLOCK_USE_PLL -/* edit these values to adjust the PLL output frequency */ -#define CLOCK_PLL_MUL (47U) /* must be >= 31 & <= 95 */ -#define CLOCK_PLL_DIV (1U) /* adjust to your needs */ -/* generate the actual used core clock frequency */ -#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV) -#elif CLOCK_USE_XOSC32_DFLL -/* Settings for 32 kHz external oscillator and 48 MHz DFLL */ -#define CLOCK_CORECLOCK (48000000UL) -#define CLOCK_XOSC32K (32768UL) -#define GEN2_XOSC32 (1) -#elif CLOCK_USE_8MHZ_DEFAULT -/* edit this value to your needs */ -#define CLOCK_DIV (1U) -/* generate the actual core clock frequency */ -#define CLOCK_CORECLOCK (8000000 / CLOCK_DIV) -#else -#error Need to select a core clock -#endif +#define CLOCK_SRC (CLOCK_USE_PLL) +#define CLOCK_CORECLOCK (48000000U) /** @} */ /** @@ -247,7 +227,7 @@ static const spi_conf_t spi_config[] = { #define RTT_ISR isr_rtc #define RTT_MAX_VALUE (0xffffffff) #define RTT_FREQUENCY (32768U) /* in Hz. For changes see `rtt.c` */ -#define XOSC32_RUNSTDBY (1) /* Keep RTT running in sleep states */ +#define RTT_RUNSTDBY (1) /* Keep RTT running in sleep states */ /** @} */ /** diff --git a/boards/sodaq-autonomo/include/periph_conf.h b/boards/sodaq-autonomo/include/periph_conf.h index add9b30a0f3c2..d9d1505df63e1 100644 --- a/boards/sodaq-autonomo/include/periph_conf.h +++ b/boards/sodaq-autonomo/include/periph_conf.h @@ -29,14 +29,13 @@ extern "C" { #endif /** - * @name External oscillator and clock configuration + * @name External oscillator and clock configuration * * There are three choices for selection of CORECLOCK: * - * - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz - * - usage of the PLL fed by the internal 8MHz oscillator divided by 8 - * - usage of the internal 8MHz oscillator directly, divided by N if needed - * + * CLOCK_USE_PLL: PLL fed by the internal 8Mhz oscillator + * CLOCK_USE_DFLL: DFLL fed by external 32.768 kHz oscillator + * CLOCK_USE_8MHZ: internal 8MHz oscillator * * The PLL option allows for the usage of a wider frequency range and a more * stable clock with less jitter. This is why this option is default. @@ -44,11 +43,13 @@ extern "C" { * The target frequency is computed from the PLL multiplier and the PLL divisor. * Use the following formula to compute your values: * - * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / PLL_DIV + * CORECLOCK = ((PLL_MUL + 1) * 1MHz) / DIV * * NOTE: The PLL circuit does not run with less than 32MHz while the maximum PLL * frequency is 96MHz. So PLL_MULL must be between 31 and 95! * + * The DFLL option can only be run at 48 MHz, but combined with an external + * oscillator it will provide the most clock stability. * * The internal Oscillator used directly can lead to a slightly better power * efficiency to the cost of a less stable clock. Use this option when you know @@ -60,29 +61,8 @@ extern "C" { * * @{ */ -#define CLOCK_USE_PLL (1) -#define CLOCK_USE_XOSC32_DFLL (0) -#define CLOCK_USE_8MHZ_DEFAULT (0) - -#if CLOCK_USE_PLL - /* edit these values to adjust the PLL output frequency */ -#define CLOCK_PLL_MUL (47U) /* must be >= 31 & <= 95 */ -#define CLOCK_PLL_DIV (1U) /* adjust to your needs */ - /* generate the actual used core clock frequency */ -#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV) -#elif CLOCK_USE_XOSC32_DFLL - /* Settings for 32 kHz external oscillator and 48 MHz DFLL */ -#define CLOCK_CORECLOCK (48000000UL) -#define CLOCK_XOSC32K (32768UL) -#define GEN2_XOSC32 (1) -#elif CLOCK_USE_8MHZ_DEFAULT - /* edit this value to your needs */ -#define CLOCK_DIV (1U) - /* generate the actual core clock frequency */ -#define CLOCK_CORECLOCK (8000000 / CLOCK_DIV) -#else -#error Need to select a core clock -#endif +#define CLOCK_SRC (CLOCK_USE_PLL) +#define CLOCK_CORECLOCK (48000000U) /** @} */ /** @@ -252,7 +232,7 @@ static const spi_conf_t spi_config[] = { #define RTT_ISR isr_rtc #define RTT_MAX_VALUE (0xffffffff) #define RTT_FREQUENCY (32768U) /* in Hz. For changes see `rtt.c` */ -#define XOSC32_RUNSTDBY (1) /* Keep RTT running in sleep states */ +#define RTT_RUNSTDBY (1) /* Keep RTT running in sleep states */ /** @} */ #ifdef __cplusplus diff --git a/cpu/samd21/cpu.c b/cpu/samd21/cpu.c index e796b7695468f..72e90b6c80e0f 100644 --- a/cpu/samd21/cpu.c +++ b/cpu/samd21/cpu.c @@ -24,66 +24,62 @@ #include "periph_clock_config.h" #include "periph/init.h" +/** + * @name Default Clock configurations + * @{ + */ + +/* make sure we have all needed information about the clock configuration */ +#ifndef CLOCK_SRC +#error "Please provide CLOCK_SRC in your board's perhip_conf.h" +#endif +#ifndef CLOCK_CORECLOCK +#error "Please provide CLOCK_CORECLOCK in your board's periph_conf.h" +#endif + +#ifndef CLOCK_DIV +#define CLOCK_DIV (1U) +#endif + +#if CLOCK_SRC == CLOCK_USE_PLL +#define CLOCK_PLL_MUL (((CLOCK_CORECLOCK * CLOCK_DIV) / 1000000U) - 1) +#endif + +#if CLOCK_SRC == CLOCK_USE_DFLL +#define CLOCK_XOSC32K (32768U) +#endif + +/* If never set then use these defaults */ +#ifndef CLOCK_XOSC32K +#define CLOCK_XOSC32K (0) +#endif + #ifndef VDD /** - * @brief Set system voltage level in mV (determines flash wait states) + * @brief set system voltage level in mV (determines flash wait states) * - * @note Override this value in your boards periph_conf.h file - * if a different system voltage is used. + * @note override this value in your boards periph_conf.h file + * if a different system voltage is used. */ -#define VDD (3300U) +#define VDD (3300U) #endif /* determine the needed flash wait states based on the system voltage (Vdd) * see SAMD21 datasheet Rev A (2017) table 37-40 , page 816 */ #if (VDD > 2700) -#define WAITSTATES ((CLOCK_CORECLOCK - 1) / 24000000) +#define WAITSTATES ((CLOCK_CORECLOCK - 1) / 24000000) #else -#define WAITSTATES ((CLOCK_CORECLOCK - 1) / 14000000) +#define WAITSTATES ((CLOCK_CORECLOCK - 1) / 14000000) #endif /** - * @brief Configure clock sources and the cpu frequency + * @brief setup 1 MHz (8MHz clock/8) clock on Generic Clock Generator 1 */ -static void clk_init(void) -{ - /* enable clocks for the power, sysctrl and gclk modules */ - PM->APBAMASK.reg = (PM_APBAMASK_PM | PM_APBAMASK_SYSCTRL | - PM_APBAMASK_GCLK); - - /* adjust NVM wait states */ - PM->APBBMASK.reg |= PM_APBBMASK_NVMCTRL; - NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(WAITSTATES); - PM->APBBMASK.reg &= ~PM_APBBMASK_NVMCTRL; - -#if CLOCK_8MHZ - /* configure internal 8MHz oscillator to run without prescaler */ - SYSCTRL->OSC8M.bit.PRESC = 0; - SYSCTRL->OSC8M.bit.ONDEMAND = 1; - SYSCTRL->OSC8M.bit.RUNSTDBY = 0; - SYSCTRL->OSC8M.bit.ENABLE = 1; - while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {} -#endif - -#if CLOCK_XOSC32K - /* Use External 32.768KHz Oscillator */ - SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND | - SYSCTRL_XOSC32K_EN32K | - SYSCTRL_XOSC32K_XTALEN | - SYSCTRL_XOSC32K_STARTUP(6) | - SYSCTRL_XOSC32K_RUNSTDBY; - /* Enable with Seperate Call */ - SYSCTRL->XOSC32K.bit.ENABLE = 1; -#endif - - /* reset the GCLK module so it is in a known state */ - GCLK->CTRL.reg = GCLK_CTRL_SWRST; - while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} - -#if GEN1_1MHZ -#if CLOCK_8MHZ == 0 -#error Must turn on CLOCK_8MHZ to use GEN1_1MHZ -#endif +static bool is_enabled_gen1_1MHz = false; +uint8_t setup_gen1_1MHz(void) { + if (is_enabled_gen1_1MHz) { + return 1; + } /* Setup GCLK1 with 1MHz */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(8) | GCLK_GENDIV_ID(1)); @@ -91,25 +87,55 @@ static void clk_init(void) GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_ID(1)); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} -#endif + is_enabled_gen1_1MHz = true; + return 2; +} + +/** + * @brief setup 32 kHz XOSC on Generic Clock Generator 2 + */ +static bool is_enabled_gen2_xosc32 = false; +static bool run_standby_gen2_xosc32 = false; +void setup_gen2_xosc32(bool standby) { + if ((standby == true) && (run_standby_gen2_xosc32 == false)) { + GCLK->GENCTRL.bit.GENEN = 0; + is_enabled_gen2_xosc32 = false; + run_standby_gen2_xosc32 = true; + } + if (is_enabled_gen2_xosc32) { + return; + } + + /* Use External 32.768KHz Oscillator */ + SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND | + SYSCTRL_XOSC32K_EN32K | + SYSCTRL_XOSC32K_XTALEN | + SYSCTRL_XOSC32K_STARTUP(6) | + SYSCTRL_XOSC32K_RUNSTDBY; + /* Enable with Seperate Call */ + SYSCTRL->XOSC32K.bit.ENABLE = 1; -#if GEN2_XOSC32 -#if CLOCK_XOSC32K == 0 -#error Must turn on CLOCK_XOSC32K to use GEN2_XOSC32 -#endif /* Setup GCLK2 with XOSC32 */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(1) | GCLK_GENDIV_ID(2)); - GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | - GCLK_GENCTRL_SRC_XOSC32K | -#if XOSC32_RUNSTDBY - GCLK_GENCTRL_RUNSTDBY | -#endif + GCLK->GENCTRL.reg = (GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2)); + if (run_standby_gen2_xosc32) { + GCLK->GENCTRL.bit.RUNSTDBY = 1; + } + GCLK->GENCTRL.bit.GENEN = 1; while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} -#endif + is_enabled_gen2_xosc32 = true; +} -#if GEN3_ULP32K +/** + * @brief setup 32 kHz ULP internal clock on Generic Clock Generator 3 + */ +static bool is_enabled_gen3_ULP32k = false; +void setup_gen3_ULP32k(void) { + if (is_enabled_gen3_ULP32k) { + return; + } /* Setup Clock generator 3 with divider 32 (32.768kHz/32 = 1.024 kHz) */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(4) | GCLK_GENDIV_ID(3)); @@ -118,20 +144,44 @@ static void clk_init(void) GCLK_GENCTRL_RUNSTDBY | GCLK_GENCTRL_DIVSEL | GCLK_GENCTRL_ID(3)); - + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} -#endif + is_enabled_gen3_ULP32k = true; +} -#if CLOCK_USE_PLL -#if GEN1_1MHZ == 0 -#error Must turn on GEN1_1MHZ to use CLOCK_USE_PLL -#endif - /* Set GEN1_1MHZ as source for DFLL */ +/** + * @brief configure clock sources and the cpu frequency + */ +static void clk_init(void) +{ + /* enable clocks for the power, sysctrl and gclk modules */ + PM->APBAMASK.reg = (PM_APBAMASK_PM | PM_APBAMASK_SYSCTRL | + PM_APBAMASK_GCLK); + + /* adjust NVM wait states */ + PM->APBBMASK.reg |= PM_APBBMASK_NVMCTRL; + NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(WAITSTATES); + PM->APBBMASK.reg &= ~PM_APBBMASK_NVMCTRL; + + /* configure internal 8MHz oscillator to run without prescaler */ + SYSCTRL->OSC8M.bit.PRESC = 0; + SYSCTRL->OSC8M.bit.ONDEMAND = 1; + SYSCTRL->OSC8M.bit.RUNSTDBY = 0; + SYSCTRL->OSC8M.bit.ENABLE = 1; + while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {} + + /* reset the GCLK module so it is in a known state */ + GCLK->CTRL.reg = GCLK_CTRL_SWRST; + while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} + +#if CLOCK_SRC == CLOCK_USE_PLL + setup_gen1_1MHz(); + /* Set GEN1_1MHZ as source for PLL */ GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_ID_FDPLL | GCLK_CLKCTRL_CLKEN); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} - + /* Enable PLL */ SYSCTRL->DPLLRATIO.reg = (SYSCTRL_DPLLRATIO_LDR(CLOCK_PLL_MUL)); SYSCTRL->DPLLCTRLB.reg = (SYSCTRL_DPLLCTRLB_REFCLK_GCLK); @@ -139,17 +189,15 @@ static void clk_init(void) while(!(SYSCTRL->DPLLSTATUS.reg & (SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK))) {} - + /* Select the PLL as source for clock generator 0 (CPU core clock) */ - GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_PLL_DIV) | + GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_DIV) | GCLK_GENDIV_ID(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_FDPLL | GCLK_GENCTRL_ID(0)); -#elif CLOCK_USE_XOSC32_DFLL -#if CLOCK_XOSC32K == 0 -#error Must turn on CLOCK_XOSC32K to use CLOCK_USE_XOSC32_DFLL -#endif +#elif CLOCK_SRC == CLOCK_USE_DFLL + setup_gen2_xosc32(false); /* Set GEN2_XOSC32 as source for DFLL */ GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK2 | GCLK_CLKCTRL_ID_DFLL48 | @@ -195,18 +243,16 @@ static void clk_init(void) while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0) { /* Wait for DFLL sync */ } -#elif CLOCK_USE_8MHZ_DEFAULT -#if CLOCK_8MHZ == 0 -#error Must turn on CLOCK_8MHZ to use CLOCK_USE_8MHZ_DEFAULT -#endif +#elif CLOCK_SRC == CLOCK_USE_8MHZ /* use internal 8MHz oscillator directly */ GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_DIV) | GCLK_GENDIV_ID(0)); GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_ID(0)); + #else -#error Must setup GCLK0 +#error Must choose CLOCK_SRC in periph_conf.h #endif /* Make sure GCLK0 is on */ GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | @@ -220,6 +266,7 @@ static void clk_init(void) while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} } } +/** @} */ void cpu_init(void) { diff --git a/cpu/samd21/include/periph_clock_config.h b/cpu/samd21/include/periph_clock_config.h index 73e988a806c60..7989fc166f5c1 100644 --- a/cpu/samd21/include/periph_clock_config.h +++ b/cpu/samd21/include/periph_clock_config.h @@ -11,7 +11,7 @@ * @{ * * @file - * @brief CPU specific definitions for default clock configuration + * @brief CPU specific definitions for generic clock generators * * @author Daniel Evans */ @@ -24,43 +24,28 @@ extern "C" { #endif /** - * @brief Default Clock configurations + * @name generic clock generator 1 + * @brief setup 1 MHz clock on generic clock generator 1 + * @{ */ - -/* If RTC or RTT is on Need XOSC32 */ -#if RTC_NUMOF || RTT_NUMOF -#ifndef CLOCK_XOSC32K -#define CLOCK_XOSC32K (32768UL) -#endif -#ifndef GEN2_XOSC32 -#define GEN2_XOSC32 (1) -#endif -#endif - -/* If never set then use these defaults */ -#ifndef CLOCK_8MHZ -#define CLOCK_8MHZ (8000000UL) -#endif - -#ifndef CLOCK_XOSC32K -#define CLOCK_XOSC32K (0) -#endif - -#ifndef XOSC32_RUNSTDBY -#define XOSC32_RUNSTDBY (0) -#endif - -#ifndef GEN1_1MHZ -#define GEN1_1MHZ (1) -#endif +uint8_t setup_gen1_1MHz(void); +/** @} */ -#ifndef GEN2_XOSC32 -#define GEN2_XOSC32 (0) -#endif +/** + * @name generic clock generator 2 + * @brief setup 32 kHz XOSC on generic clock generator 2 + * @{ + */ +void setup_gen2_xosc32(bool standby); +/** @} */ -#ifndef GEN3_ULP32K -#define GEN3_ULP32K (0) -#endif +/** + * @name generic clock generator 3 + * @brief setup 32 kHz ULP internal clock on generic clock generator 3 + * @{ + */ +void setup_gen3_ULP32k(void); +/** @} */ #ifdef __cplusplus } diff --git a/cpu/samd21/include/periph_cpu.h b/cpu/samd21/include/periph_cpu.h index 459e41f254abe..391cd5f568329 100644 --- a/cpu/samd21/include/periph_cpu.h +++ b/cpu/samd21/include/periph_cpu.h @@ -28,6 +28,13 @@ extern "C" { #endif +/** + * @brief Available core clock configurations + */ +#define CLOCK_USE_PLL (0) +#define CLOCK_USE_DFLL (1) +#define CLOCK_USE_8MHZ (2) + /** * @brief Available ports on the SAMD21 */ diff --git a/cpu/samd21/periph/gpio.c b/cpu/samd21/periph/gpio.c index 424a3f2d4ab1a..4c97c955a6760 100644 --- a/cpu/samd21/periph/gpio.c +++ b/cpu/samd21/periph/gpio.c @@ -24,6 +24,7 @@ #include "cpu.h" #include "periph/gpio.h" #include "periph_conf.h" +#include "periph_clock_config.h" #define ENABLE_DEBUG (0) #include "debug.h" @@ -148,17 +149,20 @@ int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank, return -1; } + /* use ULP 32kHZ for EIC module */ + setup_gen3_ULP32k(); + /* save callback */ gpio_config[exti].cb = cb; gpio_config[exti].arg = arg; /* configure pin as input and set MUX to peripheral function A */ gpio_init(pin, mode); gpio_init_mux(pin, GPIO_MUX_A); - /* enable clocks for the EIC module */ + /* enable clock for the EIC module */ PM->APBAMASK.reg |= PM_APBAMASK_EIC; GCLK->CLKCTRL.reg = (EIC_GCLK_ID | GCLK_CLKCTRL_CLKEN | - GCLK_CLKCTRL_GEN_GCLK2); + GCLK_CLKCTRL_GEN_GCLK3); while (GCLK->STATUS.bit.SYNCBUSY) {} /* configure the active flank */ EIC->CONFIG[exti >> 3].reg &= ~(0xf << ((exti & 0x7) * 4)); diff --git a/cpu/samd21/periph/rtc.c b/cpu/samd21/periph/rtc.c index 18e1ab078013b..bee1b23d25575 100644 --- a/cpu/samd21/periph/rtc.c +++ b/cpu/samd21/periph/rtc.c @@ -29,10 +29,6 @@ /* guard file in case no RTC device was specified */ #if RTC_NUMOF -#if GEN2_XOSC32 == 0 -#error Set GEN2_XOSC32 in periph_conf.h to use RTC -#endif - typedef struct { rtc_alarm_cb_t cb; /**< callback called from RTC interrupt */ void *arg; /**< argument passed to the callback */ @@ -52,6 +48,8 @@ void rtc_init(void) /* Turn on power manager for RTC */ PM->APBAMASK.reg |= PM_APBAMASK_RTC; + setup_gen2_xosc32(false); + /* RTC uses GEN2_XOSC32 because OSC32K isn't accurate * enough (p1075/1138). */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK2 | diff --git a/cpu/samd21/periph/rtt.c b/cpu/samd21/periph/rtt.c index dbaa17977ced1..8cc917bd47b9a 100644 --- a/cpu/samd21/periph/rtt.c +++ b/cpu/samd21/periph/rtt.c @@ -28,16 +28,12 @@ /* guard file in case no RTT device was specified */ #if RTT_NUMOF -#if GEN2_XOSC32 == 0 -#error Set GEN2_XOSC32 in periph_conf.h to use RTT -#endif - typedef struct { rtt_cb_t overflow_cb; /**< called from RTT interrupt on overflow */ void* overflow_arg; /**< argument passed to overflow callback */ rtt_cb_t alarm_cb; /**< called from RTT interrupt on alarm */ - void* alarm_arg; /**< argument passen to alarm callback */ + void* alarm_arg; /**< argument passed to alarm callback */ } rtt_state_t; static rtt_state_t rtt_callback; @@ -66,6 +62,13 @@ void rtt_init(void) /* Turn on power manager for RTC */ PM->APBAMASK.reg |= PM_APBAMASK_RTC; +#if RTT_RUNSTDBY + bool rtt_run_in_standby = true; +#else + bool rtt_run_in_standby = false; +#endif + setup_gen2_xosc32(rtt_run_in_standby); + /* RTC uses GEN2_XOSC32 because OSC32K isn't accurate * enough (p1075/1138). Also keep running in standby. */ GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK2 | diff --git a/cpu/samd21/periph/timer.c b/cpu/samd21/periph/timer.c index b4208b644ee6c..a9a008f03a6c7 100644 --- a/cpu/samd21/periph/timer.c +++ b/cpu/samd21/periph/timer.c @@ -51,9 +51,7 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg) } /* Run using the 1 MHZ clock source */ -#if GEN1_1MHZ == 0 -#error Set GEN1_1MHZ in periph_conf.h to use timer -#endif + setup_gen1_1MHz(); /* USE GEN1_1MHZ to feed TC3, TC4 and TC5 */; /* configure GCLK1 to feed TC3, TC4 and TC5 */; GCLK->CLKCTRL.reg = ((GCLK_CLKCTRL_CLKEN | @@ -307,7 +305,7 @@ void TIMER_0_ISR(void) config[TIMER_0].cb(config[TIMER_0].arg, 1); } } - + cortexm_isr_end(); } #endif /* TIMER_0_EN */ @@ -329,7 +327,7 @@ void TIMER_1_ISR(void) config[TIMER_1].cb(config[TIMER_1].arg, 1); } } - + cortexm_isr_end(); } #endif /* TIMER_1_EN */