From 46565ad3396c19b4487e26af9b50cae4121da9c9 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 12 Jun 2019 16:20:14 +0200 Subject: [PATCH 1/4] cpu: saml1x/saml21: reduce differences in cpu.c The init code for both MCUs is so alike, but it diverged over time. Re-order the code, so that it's the same on both families again. --- cpu/saml1x/cpu.c | 4 +++- cpu/saml21/cpu.c | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cpu/saml1x/cpu.c b/cpu/saml1x/cpu.c index 1234865ad3..cc04a1c40d 100644 --- a/cpu/saml1x/cpu.c +++ b/cpu/saml1x/cpu.c @@ -20,6 +20,7 @@ #include "cpu.h" #include "periph/init.h" +#include "periph_conf.h" #include "board.h" #ifdef CPU_FAM_SAML11 @@ -45,6 +46,7 @@ void cpu_init(void) /* turn on only needed APB peripherals */ MCLK->APBAMASK.reg = MCLK_APBAMASK_MCLK | MCLK_APBAMASK_OSCCTRL + | MCLK_APBAMASK_OSC32KCTRL | MCLK_APBAMASK_GCLK | MCLK_APBAMASK_PM #ifdef MODULE_PERIPH_GPIO_IRQ @@ -61,7 +63,7 @@ void cpu_init(void) while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_SWRST) {} PM->PLCFG.reg = PM_PLCFG_PLSEL_PL2; - while (0 == PM->INTFLAG.bit.PLRDY) {} + while (!PM->INTFLAG.bit.PLRDY) {} MCLK->APBBMASK.reg |= MCLK_APBBMASK_NVMCTRL; _NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(1); diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index c60a3b0cac..f9528f7fb3 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -20,11 +20,12 @@ #include "cpu.h" #include "periph/init.h" +#include "periph_conf.h" static void _gclk_setup(int gclk, uint32_t reg) { - while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclk)) {} GCLK->GENCTRL[gclk].reg = reg; + while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclk)) {} } /** @@ -59,17 +60,16 @@ void cpu_init(void) while (GCLK->CTRLA.reg & GCLK_CTRLA_SWRST) {} while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_SWRST) {} + PM->PLCFG.reg = PM_PLCFG_PLSEL_PL2; + while (!PM->INTFLAG.bit.PLRDY) {} + /* set OSC16M to 16MHz */ OSCCTRL->OSC16MCTRL.bit.FSEL = 3; OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 0; OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = 0; - PM->PLCFG.reg = PM_PLCFG_PLSEL_PL2; - while (!PM->INTFLAG.bit.PLRDY) {} - /* Setup GCLK generators */ _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); - _gclk_setup(1, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K); #ifdef MODULE_PERIPH_PM PM->CTRLA.reg = PM_CTRLA_MASK & (~PM_CTRLA_IORET); From c9c3cb84bf70eeeb5ed14b64f1e2336a76c5d841 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 12 Jun 2019 17:49:57 +0200 Subject: [PATCH 2/4] cpu: saml1x/saml21: setup 32kHz Oscilator in cpu.c Clock setup does not belong in the peripheral driver. --- cpu/saml1x/cpu.c | 38 ++++++++++++++++++++++++++++++++++++++ cpu/saml21/cpu.c | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/cpu/saml1x/cpu.c b/cpu/saml1x/cpu.c index cc04a1c40d..80b9b5e1b6 100644 --- a/cpu/saml1x/cpu.c +++ b/cpu/saml1x/cpu.c @@ -35,6 +35,41 @@ static void _gclk_setup(int gclk, uint32_t reg) while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclk)) {} } +static void _osc32k_setup(void) +{ +#if INTERNAL_OSC32_SOURCE + uint32_t * pCalibrationArea; + uint32_t osc32kcal; + + /* Read OSC32KCAL, calibration data for OSC32 !!! */ + pCalibrationArea = (uint32_t*) NVMCTRL_OTP5; + osc32kcal = ( (*pCalibrationArea) & 0x1FC0 ) >> 6; + + /* RTC use Low Power Internal Oscillator at 32kHz */ + OSC32KCTRL->OSC32K.reg = OSC32KCTRL_OSC32K_RUNSTDBY + | OSC32KCTRL_OSC32K_EN32K + | OSC32KCTRL_OSC32K_CALIB(osc32kcal) + | OSC32KCTRL_OSC32K_ENABLE; + + /* Wait OSC32K Ready */ + while (!OSC32KCTRL->STATUS.bit.OSC32KRDY) {} +#endif /* INTERNAL_OSC32_SOURCE */ +} + +static void _xosc32k_setup(void) +{ +#if EXTERNAL_OSC32_SOURCE + /* RTC uses External 32,768KHz Oscillator */ + OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_XTALEN + | OSC32KCTRL_XOSC32K_RUNSTDBY + | OSC32KCTRL_XOSC32K_EN32K + | OSC32KCTRL_XOSC32K_ENABLE; + + /* Wait XOSC32K Ready */ + while (!OSC32KCTRL->STATUS.bit.XOSC32KRDY) {} +#endif +} + /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -74,6 +109,9 @@ void cpu_init(void) OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 0; OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = 0; + _osc32k_setup(); + _xosc32k_setup(); + /* Setup GCLK generators */ _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index f9528f7fb3..6fd326c795 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -28,6 +28,41 @@ static void _gclk_setup(int gclk, uint32_t reg) while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(gclk)) {} } +static void _osc32k_setup(void) +{ +#if INTERNAL_OSC32_SOURCE + uint32_t * pCalibrationArea; + uint32_t osc32kcal; + + /* Read OSC32KCAL, calibration data for OSC32 !!! */ + pCalibrationArea = (uint32_t*) NVMCTRL_OTP5; + osc32kcal = ( (*pCalibrationArea) & 0x1FC0 ) >> 6; + + /* RTC use Low Power Internal Oscillator at 32kHz */ + OSC32KCTRL->OSC32K.reg = OSC32KCTRL_OSC32K_RUNSTDBY + | OSC32KCTRL_OSC32K_EN32K + | OSC32KCTRL_OSC32K_CALIB(osc32kcal) + | OSC32KCTRL_OSC32K_ENABLE; + + /* Wait OSC32K Ready */ + while (!OSC32KCTRL->STATUS.bit.OSC32KRDY) {} +#endif /* INTERNAL_OSC32_SOURCE */ +} + +static void _xosc32k_setup(void) +{ +#if EXTERNAL_OSC32_SOURCE + /* RTC uses External 32,768KHz Oscillator */ + OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_XTALEN + | OSC32KCTRL_XOSC32K_RUNSTDBY + | OSC32KCTRL_XOSC32K_EN32K + | OSC32KCTRL_XOSC32K_ENABLE; + + /* Wait XOSC32K Ready */ + while (!OSC32KCTRL->STATUS.bit.XOSC32KRDY) {} +#endif +} + /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -68,6 +103,9 @@ void cpu_init(void) OSCCTRL->OSC16MCTRL.bit.ONDEMAND = 0; OSCCTRL->OSC16MCTRL.bit.RUNSTDBY = 0; + _osc32k_setup(); + _xosc32k_setup(); + /* Setup GCLK generators */ _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); From 7928c74e260af2e244688167d5a34ddfc12e784d Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 12 Jun 2019 18:18:12 +0200 Subject: [PATCH 3/4] sam0_common: rtc/rtt: don't setup oscilators leave that to cpu.c --- cpu/sam0_common/periph/rtc.c | 61 +++++++----------------------------- cpu/sam0_common/periph/rtt.c | 53 +++++++++++-------------------- 2 files changed, 30 insertions(+), 84 deletions(-) diff --git a/cpu/sam0_common/periph/rtc.c b/cpu/sam0_common/periph/rtc.c index a88c66e8a6..aac433e939 100644 --- a/cpu/sam0_common/periph/rtc.c +++ b/cpu/sam0_common/periph/rtc.c @@ -65,71 +65,34 @@ static inline void _rtc_set_enabled(bool on) #ifdef CPU_SAMD21 static void _rtc_clock_setup(void) { - /* RTC uses External 32,768KHz Oscillator (OSC32K isn't accurate enough p1075/1138)*/ - SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND | - SYSCTRL_XOSC32K_EN32K | - SYSCTRL_XOSC32K_XTALEN | - SYSCTRL_XOSC32K_STARTUP(6) | - SYSCTRL_XOSC32K_ENABLE; - /* Setup clock GCLK2 with OSC32K divided by 32 */ - GCLK->GENDIV.reg = GCLK_GENDIV_ID(2)|GCLK_GENDIV_DIV(4); - GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_DIVSEL ); - GCLK->CLKCTRL.reg = (uint32_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK2 | (RTC_GCLK_ID << GCLK_CLKCTRL_ID_Pos))); + GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(4); + GCLK->GENCTRL.bit.DIVSEL = 1; + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(2) | GCLK_CLKCTRL_ID_RTC; while (GCLK->STATUS.bit.SYNCBUSY) {} } #else static void _rtc_clock_setup(void) { - MCLK->APBAMASK.reg |= MCLK_APBAMASK_OSC32KCTRL; - -#if EXTERNAL_OSC32_SOURCE - - /* RTC uses External 32,768KHz Oscillator */ - OSC32KCTRL->XOSC32K.reg = OSC32KCTRL_XOSC32K_XTALEN - | OSC32KCTRL_XOSC32K_EN1K - | OSC32KCTRL_XOSC32K_RUNSTDBY - | OSC32KCTRL_XOSC32K_ENABLE; - - /* Wait XOSC32K Ready */ - while (OSC32KCTRL->STATUS.bit.XOSC32KRDY==0) {} - /* RTC source clock is external oscillator at 1kHz */ +#if EXTERNAL_OSC32_SOURCE + OSC32KCTRL->XOSC32K.bit.EN1K = 1; OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC1K; -#endif /* EXTERNAL_OSC32_SOURCE */ - -#if INTERNAL_OSC32_SOURCE - uint32_t * pCalibrationArea; - uint32_t osc32kcal; - - /* Read OSC32KCAL, calibration data for OSC32 !!! */ - pCalibrationArea = (uint32_t*) NVMCTRL_OTP5; - osc32kcal = ( (*pCalibrationArea) & 0x1FC0 ) >> 6; - - /* RTC use Low Power Internal Oscillator at 1kHz */ - OSC32KCTRL->OSC32K.reg = OSC32KCTRL_OSC32K_RUNSTDBY - | OSC32KCTRL_OSC32K_EN1K - | OSC32KCTRL_OSC32K_CALIB(osc32kcal) - | OSC32KCTRL_OSC32K_ENABLE; - - /* Wait OSC32K Ready */ - while (OSC32KCTRL->STATUS.bit.OSC32KRDY==0) {} - /* RTC uses internal 32,768KHz Oscillator */ +#elif INTERNAL_OSC32_SOURCE + OSC32KCTRL->OSC32K.bit.EN1K = 1; OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_OSC1K; - -#endif /* INTERNAL_OSC32_SOURCE */ - -#if ULTRA_LOW_POWER_INTERNAL_OSC_SOURCE - /* RTC uses Ultra Low Power internal 32,768KHz Oscillator */ +#elif ULTRA_LOW_POWER_INTERNAL_OSC_SOURCE OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP1K; -#endif /* ULTRA_LOW_POWER_INTERNAL_OSC_SOURCE */ +#else +#error "No clock source for RTC selected. " +#endif } -#endif /* CPU_SAMD21 - Clock Setup */ +#endif /* !CPU_SAMD21 - Clock Setup */ void rtc_init(void) { diff --git a/cpu/sam0_common/periph/rtt.c b/cpu/sam0_common/periph/rtt.c index 878c6a3650..b40b2c2d2c 100644 --- a/cpu/sam0_common/periph/rtt.c +++ b/cpu/sam0_common/periph/rtt.c @@ -22,7 +22,7 @@ #include #include "periph/rtt.h" -#include "board.h" +#include "periph_conf.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -56,48 +56,31 @@ static inline void _rtt_reset(void) #ifdef CPU_SAMD21 static void _rtt_clock_setup(void) { - /* RTC uses External 32,768KHz Oscillator because OSC32K isn't accurate - * enough (p1075/1138). Also keep running in standby. */ - SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND | - SYSCTRL_XOSC32K_EN32K | - SYSCTRL_XOSC32K_XTALEN | - SYSCTRL_XOSC32K_STARTUP(6) | -#if RTT_RUNSTDBY - SYSCTRL_XOSC32K_RUNSTDBY | -#endif - SYSCTRL_XOSC32K_ENABLE; - - /* Setup clock GCLK2 with divider 1 */ - GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(1); - while (GCLK->STATUS.bit.SYNCBUSY) {} - - /* Enable GCLK2 with XOSC32K as source. Use divider without modification - * and keep running in standby. */ - GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(2) | - GCLK_GENCTRL_GENEN | -#if RTT_RUNSTDBY - GCLK_GENCTRL_RUNSTDBY | -#endif - GCLK_GENCTRL_SRC_XOSC32K; - while (GCLK->STATUS.bit.SYNCBUSY) {} - - /* Connect GCLK2 to RTC */ - GCLK->CLKCTRL.reg = GCLK_CLKCTRL_GEN_GCLK2 | - GCLK_CLKCTRL_CLKEN | - GCLK_CLKCTRL_ID(RTC_GCLK_ID); + /* Setup clock GCLK2 with OSC32K */ + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(2) | GCLK_CLKCTRL_ID_RTC; while (GCLK->STATUS.bit.SYNCBUSY) {} } -/* !CPU_SAMD21 */ #else static void _rtt_clock_setup(void) { - /* Turn on power manager for RTC */ - MCLK->APBAMASK.reg |= MCLK_APBAMASK_OSC32KCTRL; + /* RTC source clock is external oscillator at 32kHz */ +#if EXTERNAL_OSC32_SOURCE + OSC32KCTRL->XOSC32K.bit.EN32K = 1; + OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_XOSC32K; - /* set clock source */ + /* RTC uses internal 32,768KHz Oscillator */ +#elif INTERNAL_OSC32_SOURCE + OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_OSC32K; + + /* RTC uses Ultra Low Power internal 32,768KHz Oscillator */ +#elif ULTRA_LOW_POWER_INTERNAL_OSC_SOURCE OSC32KCTRL->RTCCTRL.reg = OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K; -} + +#else +#error "No clock source for RTT selected. " #endif +} +#endif /* !CPU_SAMD21 - Clock Setup */ void rtt_init(void) { From d6b8df1ff716570610760b82db0fe62691742e11 Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Wed, 12 Jun 2019 18:19:30 +0200 Subject: [PATCH 4/4] cpu/samd21: allow to use XOSC32K for GCLK2 GCLK2 is needed by RTC/RTT, so make it possible to configure it with XOSC32K as source. --- cpu/samd21/cpu.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cpu/samd21/cpu.c b/cpu/samd21/cpu.c index 9590e9fccd..5c0481c7fc 100644 --- a/cpu/samd21/cpu.c +++ b/cpu/samd21/cpu.c @@ -187,14 +187,20 @@ static void clk_init(void) /* make sure we synchronize clock generator 0 before we go on */ while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} -#if GEN2_ULP32K /* Setup Clock generator 2 with divider 1 (32.768kHz) */ GCLK->GENDIV.reg = (GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(0)); - GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN | - GCLK_GENCTRL_RUNSTDBY | - GCLK_GENCTRL_SRC_OSCULP32K); + GCLK->GENCTRL.reg = (GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_GENEN + | GCLK_GENCTRL_RUNSTDBY +#if GEN2_ULP32K + | GCLK_GENCTRL_SRC_OSCULP32K); +#else + | GCLK_GENCTRL_SRC_XOSC32K); - while (GCLK->STATUS.bit.SYNCBUSY) {} + SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND + | SYSCTRL_XOSC32K_EN32K + | SYSCTRL_XOSC32K_XTALEN + | SYSCTRL_XOSC32K_STARTUP(6) + | SYSCTRL_XOSC32K_ENABLE; #endif /* redirect all peripherals to a disabled clock generator (7) by default */