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:
parent
a51d167a43
commit
1496149bba
@ -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
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
/** @} */
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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,
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user