mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
samd21/clock: add xosc32/DFLL option
This commit is contained in:
parent
c76fdf567d
commit
08224bd85a
@ -34,8 +34,9 @@ extern "C" {
|
||||
/**
|
||||
* @name External oscillator and clock configuration
|
||||
*
|
||||
* There are two choices for selection of CORECLOCK:
|
||||
* There are three choices for selection of CORECLOCK:
|
||||
*
|
||||
* - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz
|
||||
* - usage of the PLL fed by the internal 8MHz oscillator divided by 8
|
||||
* - usage of the internal 8MHz oscillator directly, divided by N if needed
|
||||
*
|
||||
@ -70,6 +71,12 @@ extern "C" {
|
||||
#define CLOCK_PLL_DIV (1U) /* adjust to your needs */
|
||||
/* generate the actual used core clock frequency */
|
||||
#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV)
|
||||
#elif CLOCK_USE_XOSC32_DFLL
|
||||
/* Settings for 32 kHz external oscillator and 48 MHz DFLL */
|
||||
#define CLOCK_CORECLOCK (48000000U)
|
||||
#define CLOCK_XOSC32K (32768UL)
|
||||
#define CLOCK_8MHZ (1)
|
||||
#define GEN2_ULP32K (1)
|
||||
#else
|
||||
/* edit this value to your needs */
|
||||
#define CLOCK_DIV (1U)
|
||||
|
@ -32,16 +32,17 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name External oscillator and clock configuration
|
||||
* @name External oscillator and clock configuration
|
||||
*
|
||||
* For selection of the used CORECLOCK, we have implemented two choices:
|
||||
* There are three choices for selection of CORECLOCK:
|
||||
*
|
||||
* - usage of the 48 MHz DFLL fed by external oscillator running at 32 kHz
|
||||
* - usage of the PLL fed by the internal 8MHz oscillator divided by 8
|
||||
* - usage of the internal 8MHz oscillator directly, divided by N if needed
|
||||
*
|
||||
*
|
||||
* The PLL option allows for the usage of a wider frequency range and a more
|
||||
* stable clock with less jitter. This is why we use this option as default.
|
||||
* stable clock with less jitter. This is why this option is default.
|
||||
*
|
||||
* The target frequency is computed from the PLL multiplier and the PLL divisor.
|
||||
* Use the following formula to compute your values:
|
||||
@ -70,6 +71,12 @@ extern "C" {
|
||||
#define CLOCK_PLL_DIV (1U) /* adjust to your needs */
|
||||
/* generate the actual used core clock frequency */
|
||||
#define CLOCK_CORECLOCK (((CLOCK_PLL_MUL + 1) * 1000000U) / CLOCK_PLL_DIV)
|
||||
#elif CLOCK_USE_XOSC32_DFLL
|
||||
/* Settings for 32 kHz external oscillator and 48 MHz DFLL */
|
||||
#define CLOCK_CORECLOCK (48000000U)
|
||||
#define CLOCK_XOSC32K (32768UL)
|
||||
#define CLOCK_8MHZ (1)
|
||||
#define GEN2_ULP32K (1)
|
||||
#else
|
||||
/* edit this value to your needs */
|
||||
#define CLOCK_DIV (1U)
|
||||
|
@ -22,6 +22,14 @@
|
||||
#include "periph_conf.h"
|
||||
#include "periph/init.h"
|
||||
|
||||
#ifndef CLOCK_8MHZ
|
||||
#define CLOCK_8MHZ 1
|
||||
#endif
|
||||
|
||||
#ifndef GEN2_ULP32K
|
||||
#define GEN2_ULP32K 1
|
||||
#endif
|
||||
|
||||
#ifndef VDD
|
||||
/**
|
||||
* @brief Set system voltage level in mV (determines flash wait states)
|
||||
@ -54,12 +62,14 @@ static void clk_init(void)
|
||||
NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(WAITSTATES);
|
||||
PM->APBBMASK.reg &= ~PM_APBBMASK_NVMCTRL;
|
||||
|
||||
#if CLOCK_8MHZ
|
||||
/* configure internal 8MHz oscillator to run without prescaler */
|
||||
SYSCTRL->OSC8M.bit.PRESC = 0;
|
||||
SYSCTRL->OSC8M.bit.ONDEMAND = 1;
|
||||
SYSCTRL->OSC8M.bit.RUNSTDBY = 0;
|
||||
SYSCTRL->OSC8M.bit.ENABLE = 1;
|
||||
while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {}
|
||||
#endif
|
||||
|
||||
#if CLOCK_USE_PLL
|
||||
/* reset the GCLK module so it is in a known state */
|
||||
@ -90,6 +100,83 @@ static void clk_init(void)
|
||||
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN |
|
||||
GCLK_GENCTRL_SRC_FDPLL |
|
||||
GCLK_GENCTRL_ID(0));
|
||||
#elif CLOCK_USE_XOSC32_DFLL
|
||||
/* Use External 32.768KHz Oscillator */
|
||||
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_ONDEMAND |
|
||||
SYSCTRL_XOSC32K_EN32K |
|
||||
SYSCTRL_XOSC32K_XTALEN |
|
||||
SYSCTRL_XOSC32K_STARTUP(6) |
|
||||
SYSCTRL_XOSC32K_RUNSTDBY;
|
||||
|
||||
/* Enable with Seperate Call */
|
||||
SYSCTRL->XOSC32K.bit.ENABLE = 1;
|
||||
|
||||
/* reset the GCLK module so it is in a known state */
|
||||
GCLK->CTRL.reg = GCLK_CTRL_SWRST;
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
|
||||
/* setup generic clock 1 as 1MHz for timer.c */
|
||||
GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(8) |
|
||||
GCLK_GENDIV_ID(1));
|
||||
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN |
|
||||
GCLK_GENCTRL_SRC_OSC8M |
|
||||
GCLK_GENCTRL_ID(1));
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
|
||||
/* Setup clock GCLK3 with divider 1 */
|
||||
GCLK->GENDIV.reg = GCLK_GENDIV_ID(3) | GCLK_GENDIV_DIV(1);
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
|
||||
/* Enable GCLK3 with XOSC32K as source */
|
||||
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(3) |
|
||||
GCLK_GENCTRL_GENEN |
|
||||
GCLK_GENCTRL_RUNSTDBY |
|
||||
GCLK_GENCTRL_SRC_XOSC32K;
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
|
||||
/* set GCLK3 as source for DFLL */
|
||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN_GCLK3 |
|
||||
GCLK_CLKCTRL_ID_DFLL48 |
|
||||
GCLK_CLKCTRL_CLKEN);
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
|
||||
/* Disable ONDEMAND mode while writing configurations */
|
||||
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 0;
|
||||
while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0) {
|
||||
/* Wait for DFLL sync */
|
||||
}
|
||||
|
||||
/* get the coarse and fine values stored in NVM (Section 9.3) */
|
||||
uint32_t coarse = (*(uint32_t *)(0x806024) >> 26); /* Bits 63:58 */
|
||||
uint32_t fine = (*(uint32_t *)(0x806028) & 0x3FF); /* Bits 73:64 */
|
||||
|
||||
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(coarse >> 1) |
|
||||
SYSCTRL_DFLLMUL_FSTEP(fine >> 1) |
|
||||
SYSCTRL_DFLLMUL_MUL(CLOCK_CORECLOCK / CLOCK_XOSC32K);
|
||||
SYSCTRL->DFLLVAL.reg = SYSCTRL_DFLLVAL_COARSE(coarse) |
|
||||
SYSCTRL_DFLLVAL_FINE(fine);
|
||||
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_MODE;
|
||||
while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0) {
|
||||
/* Wait for DFLL sync */
|
||||
}
|
||||
|
||||
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
|
||||
while ((SYSCTRL->PCLKSR.reg & (SYSCTRL_PCLKSR_DFLLRDY |
|
||||
SYSCTRL_PCLKSR_DFLLLCKF |
|
||||
SYSCTRL_PCLKSR_DFLLLCKC)) == 0) {
|
||||
/* Wait for DFLLLXXX sync */
|
||||
}
|
||||
|
||||
/* select the DFLL as source for clock generator 0 (CPU core clock) */
|
||||
GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(1U) | GCLK_GENDIV_ID(0));
|
||||
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M | GCLK_GENCTRL_ID(0));
|
||||
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0;
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
||||
|
||||
SYSCTRL->DFLLCTRL.bit.ONDEMAND = 1;
|
||||
while ((SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_DFLLRDY) == 0) {
|
||||
/* Wait for DFLL sync */
|
||||
}
|
||||
#else /* do not use PLL, use internal 8MHz oscillator directly */
|
||||
GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_DIV) |
|
||||
GCLK_GENDIV_ID(0));
|
||||
@ -101,6 +188,7 @@ 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 |
|
||||
@ -108,6 +196,7 @@ static void clk_init(void)
|
||||
GCLK_GENCTRL_SRC_OSCULP32K);
|
||||
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
#endif
|
||||
|
||||
/* redirect all peripherals to a disabled clock generator (7) by default */
|
||||
for (int i = 0x3; i <= 0x22; i++) {
|
||||
|
@ -52,8 +52,9 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
/* select the clock generator depending on the main clock source:
|
||||
* GCLK0 (1MHz) if we use the internal 8MHz oscillator
|
||||
* GCLK1 (8MHz) if we use the PLL */
|
||||
#if CLOCK_USE_PLL
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
/* configure GCLK1 (configured to 1MHz) to feed TC3, TC4 and TC5 */;
|
||||
/* configure GCLK1 to feed TC3, TC4 and TC5 */;
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (TC3_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
||||
/* TC4 and TC5 share the same channel */
|
||||
@ -78,8 +79,8 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
while (TIMER_0_DEV.CTRLA.bit.SWRST) {}
|
||||
/* choosing 16 bit mode */
|
||||
TIMER_0_DEV.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val;
|
||||
#if CLOCK_USE_PLL
|
||||
/* sourced by 1MHz with prescaler 1 results in... you know it :-) */
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
/* PLL/DFLL: sourced by 1MHz and prescaler 1 to reach 1MHz */
|
||||
TIMER_0_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
|
||||
#else
|
||||
/* sourced by 8MHz with Presc 8 results in 1MHz clk */
|
||||
@ -102,8 +103,8 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
|
||||
|
||||
|
||||
TIMER_1_DEV.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT32_Val;
|
||||
#if CLOCK_USE_PLL
|
||||
/* sourced by 1MHz and prescaler 1 to reach 1MHz */
|
||||
#if CLOCK_USE_PLL || CLOCK_USE_XOSC32_DFLL
|
||||
/* PLL/DFLL: sourced by 1MHz and prescaler 1 to reach 1MHz */
|
||||
TIMER_1_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
|
||||
#else
|
||||
/* sourced by 8MHz with Presc 8 results in 1Mhz clk */
|
||||
|
Loading…
Reference in New Issue
Block a user