1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 04:52:59 +01:00

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.
This commit is contained in:
Benjamin Valentin 2019-12-16 19:40:23 +01:00 committed by Benjamin Valentin
parent a51d167a43
commit 1496149bba
17 changed files with 144 additions and 30 deletions

View File

@ -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
}
};
/** @} */

View File

@ -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
}
};
/** @} */

View File

@ -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
}
};
/** @} */

View File

@ -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
}
};
/** @} */

View File

@ -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
}
};

View File

@ -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
}
};
/** @} */

View File

@ -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
}
};
/** @} */

View File

@ -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 */

View File

@ -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));

View File

@ -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,
*

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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
*/

View File

@ -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 */

View File

@ -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();

View File

@ -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);