From 1496149bbaa27316fb7ce558c946b005ceeb6c6a Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Mon, 16 Dec 2019 19:40:23 +0100 Subject: [PATCH] cpu/sam0: don't hard-code peripheral clocks Instead of hard-coding the peripheral clocks to CLOCK_CORECLOCK introduce helper functions to return the frequency of the individual GCLKs and use those for baud-rate calculations. This requires the GCLK to be part of the peripheral's config struct. While this is already the case for most peripherals, this also adds it for those where it wasn't used before. As it defaults to 0 (CLOCK_CORECLOCK) no change is to be expected. --- boards/arduino-zero/include/periph_conf.h | 1 + .../arduino-mkr/include/periph_conf_common.h | 1 + .../common/sodaq/include/cfg_usbdev_default.h | 1 + boards/feather-m0/include/periph_conf.h | 1 + boards/same54-xpro/include/periph_conf.h | 1 + boards/samr21-xpro/include/periph_conf.h | 1 + boards/sensebox_samd21/include/periph_conf.h | 1 + cpu/sam0_common/include/periph_cpu_common.h | 18 ++++++++ cpu/sam0_common/periph/i2c.c | 2 +- cpu/sam0_common/periph/spi.c | 8 +--- cpu/sam0_common/periph/timer.c | 1 + cpu/sam0_common/periph/uart.c | 2 +- cpu/sam0_common/periph/usbdev.c | 21 ++++----- cpu/samd21/cpu.c | 24 ++++++++++ cpu/samd5x/cpu.c | 45 ++++++++++++++----- cpu/saml1x/cpu.c | 23 ++++++++++ cpu/saml21/cpu.c | 23 ++++++++++ 17 files changed, 144 insertions(+), 30 deletions(-) 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);