Merge pull request #10075 from dylad/saml21_dfll_support

cpu/saml21: add DFLL support
This commit is contained in:
Alexandre Abadie 2020-03-27 10:24:59 +01:00 committed by GitHub
commit c86dcd4611
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 13 deletions

View File

@ -32,7 +32,7 @@ extern "C" {
/**
* @brief GCLK reference speed
*/
#define CLOCK_CORECLOCK (16000000U)
#define CLOCK_CORECLOCK (48000000U)
/**
* @name Timer peripheral configuration
@ -45,8 +45,8 @@ static const tc32_conf_t timer_config[] = {
.mclk = &MCLK->APBCMASK.reg,
.mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1,
.gclk_id = TC0_GCLK_ID,
.gclk_src = SAM0_GCLK_MAIN,
.prescaler = TC_CTRLA_PRESCALER(4),
.gclk_src = SAM0_GCLK_8MHZ,
.prescaler = TC_CTRLA_PRESCALER(3),
.flags = TC_CTRLA_MODE_COUNT32,
}
};

View File

@ -28,7 +28,7 @@ extern "C" {
/**
* @brief GCLK reference speed
*/
#define CLOCK_CORECLOCK (16000000U)
#define CLOCK_CORECLOCK (48000000U)
/**
* @name Timer peripheral configuration
@ -41,8 +41,8 @@ static const tc32_conf_t timer_config[] = {
.mclk = &MCLK->APBCMASK.reg,
.mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1,
.gclk_id = TC0_GCLK_ID,
.gclk_src = SAM0_GCLK_MAIN,
.prescaler = TC_CTRLA_PRESCALER(4),
.gclk_src = SAM0_GCLK_8MHZ,
.prescaler = TC_CTRLA_PRESCALER(3),
.flags = TC_CTRLA_MODE_COUNT32,
}
};

View File

@ -29,7 +29,7 @@ extern "C" {
/**
* @brief GCLK reference speed
*/
#define CLOCK_CORECLOCK (16000000U)
#define CLOCK_CORECLOCK (48000000U)
/**
* @name Timer peripheral configuration
@ -42,8 +42,8 @@ static const tc32_conf_t timer_config[] = {
.mclk = &MCLK->APBCMASK.reg,
.mclk_mask = MCLK_APBCMASK_TC0 | MCLK_APBCMASK_TC1,
.gclk_id = TC0_GCLK_ID,
.gclk_src = SAM0_GCLK_MAIN,
.prescaler = TC_CTRLA_PRESCALER(4),
.gclk_src = SAM0_GCLK_8MHZ,
.prescaler = TC_CTRLA_PRESCALER(3),
.flags = TC_CTRLA_MODE_COUNT32,
}
};

View File

@ -75,6 +75,8 @@ uint32_t sam0_gclk_freq(uint8_t id)
switch (id) {
case SAM0_GCLK_MAIN:
return CLOCK_CORECLOCK;
case SAM0_GCLK_8MHZ:
return 8000000;
case SAM0_GCLK_32KHZ:
return 32768;
default:
@ -82,6 +84,48 @@ uint32_t sam0_gclk_freq(uint8_t id)
}
}
static void _dfll_setup(void)
{
#if (CLOCK_CORECLOCK == 48000000U) || defined (MODULE_PERIPH_USBDEV)
GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg = GCLK_PCHCTRL_CHEN |
GCLK_PCHCTRL_GEN_GCLK2;
/* wait for sync */
while (!(GCLK->PCHCTRL[OSCCTRL_GCLK_ID_DFLL48].reg & GCLK_PCHCTRL_CHEN)) {}
OSCCTRL->DFLLCTRL.reg = OSCCTRL_DFLLCTRL_ENABLE;
/* Wait for write synchronization */
while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) {}
OSCCTRL->DFLLVAL.reg = OSCCTRL_DFLLVAL_COARSE((*(uint32_t*)NVMCTRL_OTP5)
>> 26) | OSCCTRL_DFLLVAL_FINE(512);
/* Wait for write synchronization */
while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) {}
/* Generate a 48 Mhz clock from the 32KHz */
OSCCTRL->DFLLMUL.reg = OSCCTRL_DFLLMUL_CSTEP(0x08) |
OSCCTRL_DFLLMUL_FSTEP(0x08) |
OSCCTRL_DFLLMUL_MUL((48000000U/32768));
/* Disable DFLL before setting its configuration */
OSCCTRL->DFLLCTRL.reg = 0;
while (!(OSCCTRL->STATUS.reg & OSCCTRL_STATUS_DFLLRDY)) {}
/* Write full configuration to DFLL control register */
OSCCTRL->DFLLCTRL.reg = OSCCTRL_DFLLCTRL_WAITLOCK |
OSCCTRL_DFLLCTRL_MODE |
OSCCTRL_DFLLCTRL_CCDIS |
OSCCTRL_DFLLCTRL_BPLCKC |
OSCCTRL_DFLLCTRL_ENABLE;
/* Ensure COARSE and FINE are locked */
while ((!(OSCCTRL->STATUS.bit.DFLLLCKC)) && (!(OSCCTRL->STATUS.bit.DFLLLCKF))) {}
while (!(OSCCTRL->STATUS.bit.DFLLRDY)) {}
/* Enable NVMCTRL */
MCLK->APBBMASK.reg |= MCLK_APBBMASK_NVMCTRL;
/* Set Wait State to meet requirements */
NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(3);
#endif
}
/**
* @brief Initialize the CPU, set IRQ priorities, clocks
*/
@ -90,6 +134,14 @@ void cpu_init(void)
/* disable the watchdog timer */
WDT->CTRLA.bit.ENABLE = 0;
/* Disable the RTC module to prevent synchronization issues during CPU init
if the RTC was running from a previous boot (e.g wakeup from backup) */
if (RTC->MODE2.CTRLA.bit.ENABLE) {
while (RTC->MODE2.SYNCBUSY.reg) {}
RTC->MODE2.CTRLA.bit.ENABLE = 0;
while (RTC->MODE2.SYNCBUSY.reg) {}
}
/* initialize the Cortex-M core */
cortexm_init();
@ -125,14 +177,36 @@ void cpu_init(void)
_osc32k_setup();
_xosc32k_setup();
/* Setup GCLK generators */
_gclk_setup(SAM0_GCLK_MAIN, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M);
#if EXTERNAL_OSC32_SOURCE
_gclk_setup(SAM0_GCLK_32KHZ, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_XOSC32K);
#else
_gclk_setup(SAM0_GCLK_32KHZ, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSCULP32K);
#endif
_dfll_setup();
/* Setup GCLK generators */
#if (CLOCK_CORECLOCK == 16000000U)
_gclk_setup(SAM0_GCLK_MAIN, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M);
#elif (CLOCK_CORECLOCK == 48000000U)
_gclk_setup(SAM0_GCLK_MAIN, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_DFLL48M);
#else
#error "Please select a valid CPU frequency"
#endif
/* Ensure APB Backup domain clock is within the 6MHZ limit, BUPDIV value
must be a power of 2 and between 1(2^0) and 128(2^7) */
for (unsigned i = 0; i < 8; i++) {
if (CLOCK_CORECLOCK / (1 << i) <= 6000000) {
MCLK->BUPDIV.reg = (1 << i);
while (!MCLK->INTFLAG.bit.CKRDY) {}
break;
}
}
/* clock used by timers */
_gclk_setup(SAM0_GCLK_8MHZ, GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC16M
| GCLK_GENCTRL_DIV(2));
#ifdef MODULE_PERIPH_PM
PM->CTRLA.reg = PM_CTRLA_MASK & (~PM_CTRLA_IORET);

View File

@ -36,8 +36,9 @@ extern "C" {
* @{
*/
enum {
SAM0_GCLK_MAIN = 0, /**< 16 MHz main clock */
SAM0_GCLK_32KHZ, /**< 32 kHz clock */
SAM0_GCLK_MAIN = 0, /**< Main clock */
SAM0_GCLK_8MHZ = 1, /**< 8MHz clock */
SAM0_GCLK_32KHZ = 2, /**< 32 kHz clock */
};
/** @} */