diff --git a/cpu/sam3/cpu.c b/cpu/sam3/cpu.c index 1fc4683ca8..aaa18578b6 100644 --- a/cpu/sam3/cpu.c +++ b/cpu/sam3/cpu.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014 Freie Universität Berlin + * Copyright (C) 2014-2016 Freie Universität Berlin * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level @@ -18,6 +18,25 @@ */ #include "cpu.h" +#include "periph_conf.h" + +/** + * @brief Keys needed for editing certain PMC registers + * @{ + */ +#define WPKEY (0x504D43) +#define MORKEY (0x37) +/** @} */ + +/** + * @brief Start-up time for external crystal (will be multiplied by 8) + */ +#define XTAL_STARTUP (8U) + +/** + * @brief PLL is incremented to this value until considered stable + */ +#define PLL_CNT (64U) /** * @brief Initialize the CPU, set IRQ priorities @@ -28,4 +47,45 @@ void cpu_init(void) WDT->WDT_MR |= WDT_MR_WDDIS; /* initialize the Cortex-M core */ cortexm_init(); + + /* setup the flash wait states */ + EFC0->EEFC_FMR = EEFC_FMR_FWS(CLOCK_FWS); + EFC1->EEFC_FMR = EEFC_FMR_FWS(CLOCK_FWS); + + /* unlock write protect register for PMC module */ + PMC->PMC_WPMR = PMC_WPMR_WPKEY(WPKEY); + + /* activate the external crystal */ + PMC->CKGR_MOR = (CKGR_MOR_KEY(MORKEY) | + CKGR_MOR_MOSCXTST(XTAL_STARTUP) | + CKGR_MOR_MOSCXTEN | + CKGR_MOR_MOSCRCEN); + /* wait for crystal to be stable */ + while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)); + + /* select crystal to clock the main clock */ + PMC->CKGR_MOR = (CKGR_MOR_KEY(MORKEY) | + CKGR_MOR_MOSCXTST(XTAL_STARTUP) | + CKGR_MOR_MOSCXTEN | + CKGR_MOR_MOSCRCEN | + CKGR_MOR_MOSCSEL); + /* wait for main oscillator selection to be complete */ + while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)); + + /* setup PLLA */ + PMC->CKGR_PLLAR = (CKGR_PLLAR_ONE | + CKGR_PLLAR_PLLACOUNT(PLL_CNT) | + CKGR_PLLAR_MULA(CLOCK_PLL_MUL) | + CKGR_PLLAR_DIVA(CLOCK_PLL_DIV)); + /* wait for PLL to lock */ + while (!(PMC->PMC_SR & PMC_SR_LOCKA)); + + /* before switching to PLLA, we need to switch to main clock */ + PMC->PMC_MCKR = PMC_MCKR_CSS_MAIN_CLK; + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); + + /* use PLLA as main clock source */ + PMC->PMC_MCKR = PMC_MCKR_CSS_PLLA_CLK; + /* wait for master clock to be ready */ + while (!(PMC->PMC_SR & PMC_SR_MCKRDY)); }