diff --git a/boards/arduino-zero/include/periph_conf.h b/boards/arduino-zero/include/periph_conf.h index ce277c220a..2741971354 100644 --- a/boards/arduino-zero/include/periph_conf.h +++ b/boards/arduino-zero/include/periph_conf.h @@ -295,6 +295,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_G, .device = &USB->DEVICE, + .gclk_src = 0 } }; /** @} */ diff --git a/boards/common/arduino-mkr/include/periph_conf_common.h b/boards/common/arduino-mkr/include/periph_conf_common.h index e0c84c2cf5..97c006543e 100644 --- a/boards/common/arduino-mkr/include/periph_conf_common.h +++ b/boards/common/arduino-mkr/include/periph_conf_common.h @@ -221,6 +221,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_G, .device = &USB->DEVICE, + .gclk_src = 0 } }; /** @} */ diff --git a/boards/common/sodaq/include/cfg_usbdev_default.h b/boards/common/sodaq/include/cfg_usbdev_default.h index 49d93e506e..bdd197d6de 100644 --- a/boards/common/sodaq/include/cfg_usbdev_default.h +++ b/boards/common/sodaq/include/cfg_usbdev_default.h @@ -38,6 +38,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_G, .device = &USB->DEVICE, + .gclk_src = 0 } }; /** @} */ diff --git a/boards/feather-m0/include/periph_conf.h b/boards/feather-m0/include/periph_conf.h index af3fd6fc94..ed539938da 100644 --- a/boards/feather-m0/include/periph_conf.h +++ b/boards/feather-m0/include/periph_conf.h @@ -274,6 +274,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_G, .device = &USB->DEVICE, + .gclk_src = 0 } }; /** @} */ diff --git a/boards/same54-xpro/include/periph_conf.h b/boards/same54-xpro/include/periph_conf.h index 69a235e3c9..e6093a99ff 100644 --- a/boards/same54-xpro/include/periph_conf.h +++ b/boards/same54-xpro/include/periph_conf.h @@ -167,6 +167,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_H, .device = &USB->DEVICE, + .gclk_src = 6 } }; diff --git a/boards/samr21-xpro/include/periph_conf.h b/boards/samr21-xpro/include/periph_conf.h index 36036b43fe..ae632ec0d5 100644 --- a/boards/samr21-xpro/include/periph_conf.h +++ b/boards/samr21-xpro/include/periph_conf.h @@ -309,6 +309,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_G, .device = &USB->DEVICE, + .gclk_src = 0 } }; /** @} */ diff --git a/boards/sensebox_samd21/include/periph_conf.h b/boards/sensebox_samd21/include/periph_conf.h index 77641c810e..6faae4528a 100644 --- a/boards/sensebox_samd21/include/periph_conf.h +++ b/boards/sensebox_samd21/include/periph_conf.h @@ -253,6 +253,7 @@ static const sam0_common_usb_config_t sam_usbdev_config[] = { .dp = GPIO_PIN(PA, 25), .d_mux = GPIO_MUX_G, .device = &USB->DEVICE, + .gclk_src = 0 } }; /** @} */ diff --git a/cpu/sam0_common/include/periph_cpu_common.h b/cpu/sam0_common/include/periph_cpu_common.h index 08c19a6ba5..19753d91fe 100644 --- a/cpu/sam0_common/include/periph_cpu_common.h +++ b/cpu/sam0_common/include/periph_cpu_common.h @@ -352,6 +352,22 @@ typedef struct { */ void gpio_init_mux(gpio_t pin, gpio_mux_t mux); +/** + * @brief Returns the frequency of a GCLK provider. + * + * @param[in] id The ID of the GCLK + * + * @return The frequency of the GCLK with the given ID. + */ +uint32_t sam0_gclk_freq(uint8_t id); + +/** + * @brief Enables an on-demand GCLK that has been configured in cpu.c + * + * @param[in] id The ID of the GCLK + */ +void sam0_gclk_enable(uint8_t id); + /** * @brief Return the numeric id of a SERCOM device derived from its address * @@ -488,6 +504,7 @@ static inline uint8_t _sercom_gclk_id_core(uint8_t sercom_id) { static inline void sercom_set_gen(void *sercom, uint8_t gclk) { const uint8_t id = sercom_id(sercom); + sam0_gclk_enable(gclk); #if defined(CPU_FAM_SAMD21) GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN(gclk) | (SERCOM0_GCLK_ID_CORE + id)); @@ -535,6 +552,7 @@ typedef struct { gpio_t dp; /**< D+ line gpio */ gpio_mux_t d_mux; /**< alternate function (mux) for data pins */ UsbDevice *device; /**< ptr to the device registers */ + uint8_t gclk_src; /**< GCLK source which supplys 48 MHz */ } sam0_common_usb_config_t; #endif /* USB_INST_NUM */ diff --git a/cpu/sam0_common/periph/i2c.c b/cpu/sam0_common/periph/i2c.c index eca811d58f..10ac2baa63 100644 --- a/cpu/sam0_common/periph/i2c.c +++ b/cpu/sam0_common/periph/i2c.c @@ -137,7 +137,7 @@ void i2c_init(i2c_t dev) return; } /* Get the baudrate */ - tmp_baud = (int32_t)(((CLOCK_CORECLOCK + + tmp_baud = (int32_t)(((sam0_gclk_freq(i2c_config[dev].gclk_src) + (2 * (i2c_config[dev].speed)) - 1) / (2 * (i2c_config[dev].speed))) - (i2c_config[dev].speed == I2C_SPEED_HIGH ? 1 : 5)); diff --git a/cpu/sam0_common/periph/spi.c b/cpu/sam0_common/periph/spi.c index 33159dd32f..f76e2a028d 100644 --- a/cpu/sam0_common/periph/spi.c +++ b/cpu/sam0_common/periph/spi.c @@ -76,11 +76,7 @@ void spi_init(spi_t bus) (dev(bus)->SYNCBUSY.reg & SERCOM_SPI_SYNCBUSY_SWRST)) {} /* configure base clock: using GLK GEN 0 */ -#ifdef GCLK_CLKCTRL_GEN_GCLK0 - sercom_set_gen(dev(bus), GCLK_CLKCTRL_GEN_GCLK0); -#else - sercom_set_gen(dev(bus), GCLK_PCHCTRL_GEN_GCLK0); -#endif + sercom_set_gen(dev(bus), spi_config[bus].gclk_src); /* enable receiver and configure character size to 8-bit * no synchronization needed, as SERCOM device is not enabled */ @@ -108,7 +104,7 @@ int spi_acquire(spi_t bus, spi_cs_t cs, spi_mode_t mode, spi_clk_t clk) /* configure bus clock, in synchronous mode its calculated from * BAUD.reg = (f_ref / (2 * f_bus) - 1) * with f_ref := CLOCK_CORECLOCK as defined by the board */ - const uint8_t baud = (((uint32_t)CLOCK_CORECLOCK) / (2 * clk) - 1); + const uint8_t baud = (sam0_gclk_freq(spi_config[bus].gclk_src) / (2 * clk) - 1); /* configure device to be master and set mode and pads, * diff --git a/cpu/sam0_common/periph/timer.c b/cpu/sam0_common/periph/timer.c index 61df4756cd..fbd3e249da 100644 --- a/cpu/sam0_common/periph/timer.c +++ b/cpu/sam0_common/periph/timer.c @@ -87,6 +87,7 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg) /* make sure the timer is not running */ timer_stop(tim); + sam0_gclk_enable(cfg->gclk_src); #ifdef MCLK GCLK->PCHCTRL[cfg->gclk_id].reg = GCLK_PCHCTRL_GEN(cfg->gclk_src) | GCLK_PCHCTRL_CHEN; *cfg->mclk |= cfg->mclk_mask; diff --git a/cpu/sam0_common/periph/uart.c b/cpu/sam0_common/periph/uart.c index 75cf8a7bbd..eeff0fa310 100644 --- a/cpu/sam0_common/periph/uart.c +++ b/cpu/sam0_common/periph/uart.c @@ -116,7 +116,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) } /* calculate and set baudrate */ - uint32_t baud = ((((uint32_t)CLOCK_CORECLOCK * 8) / baudrate) / 16); + uint32_t baud = (((sam0_gclk_freq(uart_config[uart].gclk_src) * 8) / baudrate) / 16); dev(uart)->BAUD.FRAC.FP = (baud % 8); dev(uart)->BAUD.FRAC.BAUD = (baud / 8); diff --git a/cpu/sam0_common/periph/usbdev.c b/cpu/sam0_common/periph/usbdev.c index 9230371cfe..2af64171a6 100644 --- a/cpu/sam0_common/periph/usbdev.c +++ b/cpu/sam0_common/periph/usbdev.c @@ -230,8 +230,10 @@ static bool _syncbusy_swrst(sam0_common_usb_t *dev) return dev->config->device->SYNCBUSY.bit.SWRST; } -static inline void _poweron(void) +static inline void _poweron(sam0_common_usb_t *dev) { + sam0_gclk_enable(dev->config->gclk_src); + #if defined(MCLK) MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB; MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB; @@ -241,17 +243,12 @@ static inline void _poweron(void) #endif #if defined(CPU_FAM_SAMD21) - GCLK->CLKCTRL.reg = (uint32_t)(GCLK_CLKCTRL_CLKEN | - GCLK_CLKCTRL_GEN_GCLK0 | - (GCLK_CLKCTRL_ID(USB_GCLK_ID))); -#elif defined(CPU_FAM_SAML21) - GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | - GCLK_PCHCTRL_GEN_GCLK0; -#elif defined(CPU_FAM_SAMD5X) - GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_CHEN | - GCLK_PCHCTRL_GEN_GCLK6; + GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN + | GCLK_CLKCTRL_GEN(dev->config->gclk_src) + | GCLK_CLKCTRL_ID(USB_GCLK_ID); #else -#error "Unknown CPU family for sam0 common usbdev driver" + GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_CHEN + | GCLK_PCHCTRL_GEN(dev->config->gclk_src); #endif } @@ -340,7 +337,7 @@ static void _usbdev_init(usbdev_t *dev) gpio_init(usbdev->config->dm, GPIO_IN); gpio_init_mux(usbdev->config->dm, usbdev->config->d_mux); gpio_init_mux(usbdev->config->dp, usbdev->config->d_mux); - _poweron(); + _poweron(usbdev); /* Reset peripheral */ usbdev->config->device->CTRLA.reg |= USB_CTRLA_SWRST; diff --git a/cpu/samd21/cpu.c b/cpu/samd21/cpu.c index 7fd48e16ea..30d24c78e2 100644 --- a/cpu/samd21/cpu.c +++ b/cpu/samd21/cpu.c @@ -49,6 +49,30 @@ #define WAITSTATES ((CLOCK_CORECLOCK - 1) / 14000000) #endif +void sam0_gclk_enable(uint8_t id) +{ + (void) id; + /* clocks are always running */ +} + +uint32_t sam0_gclk_freq(uint8_t id) +{ + switch (id) { + case 0: + return CLOCK_CORECLOCK; + case 1: + return 1000000; + case 2: + return 32768; + case 3: + return 32768; + case 4: + return 1024; + default: + return 0; + } +} + /** * @brief Configure clock sources and the cpu frequency */ diff --git a/cpu/samd5x/cpu.c b/cpu/samd5x/cpu.c index e942a6ecd4..9ff290fc24 100644 --- a/cpu/samd5x/cpu.c +++ b/cpu/samd5x/cpu.c @@ -105,6 +105,41 @@ static void gclk_connect(uint8_t id, uint8_t src, uint32_t flags) { while (GCLK->SYNCBUSY.reg & GCLK_SYNCBUSY_GENCTRL(id)) {} } +void sam0_gclk_enable(uint8_t id) +{ + /* clocks 0 & 1 are always running */ + + switch (id) { + case 5: + /* 8 MHz clock used by xtimer */ +#if USE_DPLL + gclk_connect(5, GCLK_SOURCE_DPLL0, GCLK_GENCTRL_DIV(DPLL_DIV * CLOCK_CORECLOCK / 8000000)); +#else + gclk_connect(5, GCLK_SOURCE_DFLL, GCLK_GENCTRL_DIV(SAM0_DFLL_FREQ_HZ / 8000000)); +#endif + break; + case 6: + gclk_connect(6, GCLK_SOURCE_DFLL, 0); + break; + } +} + +uint32_t sam0_gclk_freq(uint8_t id) +{ + switch (id) { + case 0: + return CLOCK_CORECLOCK; + case 1: + return 32768; + case 5: + return 8000000; + case 6: + return SAM0_DFLL_FREQ_HZ; + default: + return 0; + } +} + /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -155,18 +190,8 @@ void cpu_init(void) /* source main clock from DPLL */ gclk_connect(0, GCLK_SOURCE_DPLL0, GCLK_GENCTRL_DIV(DPLL_DIV)); - - /* clock used by xtimer */ - gclk_connect(5, GCLK_SOURCE_DPLL0, GCLK_GENCTRL_DIV(DPLL_DIV * CLOCK_CORECLOCK / 8000000)); #else gclk_connect(0, GCLK_SOURCE_DFLL, GCLK_GENCTRL_DIV(SAM0_DFLL_FREQ_HZ / CLOCK_CORECLOCK)); - - /* clock used by xtimer */ - gclk_connect(5, GCLK_SOURCE_DFLL, GCLK_GENCTRL_DIV(SAM0_DFLL_FREQ_HZ / 8000000)); -#endif - -#ifdef MODULE_PERIPH_USBDEV - gclk_connect(6, GCLK_SOURCE_DFLL, 0); #endif /* initialize stdio prior to periph_init() to allow use of DEBUG() there */ diff --git a/cpu/saml1x/cpu.c b/cpu/saml1x/cpu.c index 467261ffb4..99c6c9af2d 100644 --- a/cpu/saml1x/cpu.c +++ b/cpu/saml1x/cpu.c @@ -71,6 +71,24 @@ static void _xosc32k_setup(void) #endif } +void sam0_gclk_enable(uint8_t id) +{ + (void) id; + /* clocks are always running */ +} + +uint32_t sam0_gclk_freq(uint8_t id) +{ + switch (id) { + case 0: + return CLOCK_CORECLOCK; + case 1: + return 32768; + default: + return 0; + } +} + /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -115,6 +133,11 @@ void cpu_init(void) /* Setup GCLK generators */ _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); +#if EXTERNAL_OSC32_SOURCE + _gclk_setup(1, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K); +#else + _gclk_setup(1, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K); +#endif /* initialize stdio prior to periph_init() to allow use of DEBUG() there */ stdio_init(); diff --git a/cpu/saml21/cpu.c b/cpu/saml21/cpu.c index fd36e6e81f..71e54cb3a9 100644 --- a/cpu/saml21/cpu.c +++ b/cpu/saml21/cpu.c @@ -64,6 +64,24 @@ static void _xosc32k_setup(void) #endif } +void sam0_gclk_enable(uint8_t id) +{ + (void) id; + /* clocks are always running */ +} + +uint32_t sam0_gclk_freq(uint8_t id) +{ + switch (id) { + case 0: + return CLOCK_CORECLOCK; + case 1: + return 32768; + default: + return 0; + } +} + /** * @brief Initialize the CPU, set IRQ priorities, clocks */ @@ -109,6 +127,11 @@ void cpu_init(void) /* Setup GCLK generators */ _gclk_setup(0, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M); +#if EXTERNAL_OSC32_SOURCE + _gclk_setup(1, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K); +#else + _gclk_setup(1, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K); +#endif #ifdef MODULE_PERIPH_PM PM->CTRLA.reg = PM_CTRLA_MASK & (~PM_CTRLA_IORET);