2014-09-09 11:12:39 +02:00
|
|
|
/*
|
2015-05-19 18:12:40 +02:00
|
|
|
* Copyright (C) 2015 Freie Universität Berlin
|
2014-09-09 11:12:39 +02:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* directory for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ingroup cpu_samd21
|
|
|
|
* @{
|
|
|
|
*
|
2015-05-22 07:34:41 +02:00
|
|
|
* @file
|
2014-09-09 11:12:39 +02:00
|
|
|
* @brief Implementation of the CPU initialization
|
|
|
|
*
|
|
|
|
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
2015-05-19 18:12:40 +02:00
|
|
|
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
2014-09-09 11:12:39 +02:00
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "cpu.h"
|
2015-05-19 18:12:40 +02:00
|
|
|
#include "periph_conf.h"
|
2017-01-20 11:18:38 +01:00
|
|
|
#include "periph/init.h"
|
2014-09-09 11:12:39 +02:00
|
|
|
|
|
|
|
/**
|
2015-05-19 18:12:40 +02:00
|
|
|
* @brief Configure clock sources and the cpu frequency
|
2014-09-09 11:12:39 +02:00
|
|
|
*/
|
2015-05-19 18:12:40 +02:00
|
|
|
static void clk_init(void)
|
2014-09-09 11:12:39 +02:00
|
|
|
{
|
2015-05-19 18:12:40 +02:00
|
|
|
/* enable clocks for the power, sysctrl and gclk modules */
|
|
|
|
PM->APBAMASK.reg = (PM_APBAMASK_PM | PM_APBAMASK_SYSCTRL |
|
|
|
|
PM_APBAMASK_GCLK);
|
2014-09-09 11:12:39 +02:00
|
|
|
|
2015-05-19 18:12:40 +02:00
|
|
|
/* adjust NVM wait states, see table 42.30 (p. 1070) in the datasheet */
|
|
|
|
#if (CLOCK_CORECLOCK > 24000000)
|
2017-04-08 21:07:22 +02:00
|
|
|
PM->APBBMASK.reg |= PM_APBBMASK_NVMCTRL;
|
2015-05-19 18:12:40 +02:00
|
|
|
NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(1);
|
2017-04-08 21:07:22 +02:00
|
|
|
PM->APBBMASK.reg &= ~PM_APBBMASK_NVMCTRL;
|
2015-05-19 18:12:40 +02:00
|
|
|
#endif
|
2014-09-09 11:12:39 +02:00
|
|
|
|
2015-05-19 18:12:40 +02:00
|
|
|
/* configure internal 8MHz oscillator to run without prescaler */
|
2014-09-09 11:12:39 +02:00
|
|
|
SYSCTRL->OSC8M.bit.PRESC = 0;
|
2017-01-09 18:13:04 +01:00
|
|
|
SYSCTRL->OSC8M.bit.ONDEMAND = 1;
|
2014-09-09 11:12:39 +02:00
|
|
|
SYSCTRL->OSC8M.bit.RUNSTDBY = 0;
|
|
|
|
SYSCTRL->OSC8M.bit.ENABLE = 1;
|
2016-02-11 14:25:02 +01:00
|
|
|
while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY)) {}
|
2014-09-09 11:12:39 +02:00
|
|
|
|
2015-05-19 18:12:40 +02:00
|
|
|
#if CLOCK_USE_PLL
|
|
|
|
/* reset the GCLK module so it is in a known state */
|
2014-09-09 11:12:39 +02:00
|
|
|
GCLK->CTRL.reg = GCLK_CTRL_SWRST;
|
2016-02-11 14:25:02 +01:00
|
|
|
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
2015-05-19 18:12:40 +02:00
|
|
|
|
|
|
|
/* setup generic clock 1 to feed DPLL with 1MHz */
|
|
|
|
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));
|
|
|
|
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_GEN(1) |
|
|
|
|
GCLK_CLKCTRL_ID(1) |
|
|
|
|
GCLK_CLKCTRL_CLKEN);
|
2016-02-11 14:25:02 +01:00
|
|
|
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
2015-05-19 18:12:40 +02:00
|
|
|
|
|
|
|
/* enable PLL */
|
|
|
|
SYSCTRL->DPLLRATIO.reg = (SYSCTRL_DPLLRATIO_LDR(CLOCK_PLL_MUL));
|
|
|
|
SYSCTRL->DPLLCTRLB.reg = (SYSCTRL_DPLLCTRLB_REFCLK_GCLK);
|
|
|
|
SYSCTRL->DPLLCTRLA.reg = (SYSCTRL_DPLLCTRLA_ENABLE);
|
|
|
|
while(!(SYSCTRL->DPLLSTATUS.reg &
|
2016-02-11 14:25:02 +01:00
|
|
|
(SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK))) {}
|
2015-05-19 18:12:40 +02:00
|
|
|
|
|
|
|
/* select the PLL as source for clock generator 0 (CPU core clock) */
|
|
|
|
GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_PLL_DIV) |
|
|
|
|
GCLK_GENDIV_ID(0));
|
|
|
|
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN |
|
2016-07-31 20:57:04 +02:00
|
|
|
GCLK_GENCTRL_SRC_FDPLL |
|
2015-05-19 18:12:40 +02:00
|
|
|
GCLK_GENCTRL_ID(0));
|
|
|
|
#else /* do not use PLL, use internal 8MHz oscillator directly */
|
|
|
|
GCLK->GENDIV.reg = (GCLK_GENDIV_DIV(CLOCK_DIV) |
|
|
|
|
GCLK_GENDIV_ID(0));
|
|
|
|
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN |
|
|
|
|
GCLK_GENCTRL_SRC_OSC8M |
|
|
|
|
GCLK_GENCTRL_ID(0));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* make sure we synchronize clock generator 0 before we go on */
|
2016-02-11 14:25:02 +01:00
|
|
|
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
2015-09-17 15:57:51 +02:00
|
|
|
|
2017-01-09 18:13:04 +01:00
|
|
|
/* 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 |
|
|
|
|
GCLK_GENCTRL_RUNSTDBY |
|
|
|
|
GCLK_GENCTRL_SRC_OSCULP32K);
|
|
|
|
|
|
|
|
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
|
|
|
|
2015-09-17 15:57:51 +02:00
|
|
|
/* redirect all peripherals to a disabled clock generator (7) by default */
|
|
|
|
for (int i = 0x3; i <= 0x22; i++) {
|
|
|
|
GCLK->CLKCTRL.reg = ( GCLK_CLKCTRL_ID(i) | GCLK_CLKCTRL_GEN_GCLK7 );
|
2016-02-11 14:25:02 +01:00
|
|
|
while (GCLK->STATUS.bit.SYNCBUSY) {}
|
2015-09-17 15:57:51 +02:00
|
|
|
}
|
2014-09-09 11:12:39 +02:00
|
|
|
}
|
2015-05-19 18:12:40 +02:00
|
|
|
|
|
|
|
void cpu_init(void)
|
|
|
|
{
|
|
|
|
/* disable the watchdog timer */
|
|
|
|
WDT->CTRL.bit.ENABLE = 0;
|
|
|
|
/* initialize the Cortex-M core */
|
|
|
|
cortexm_init();
|
|
|
|
/* Initialise clock sources and generic clocks */
|
|
|
|
clk_init();
|
2016-11-08 18:26:58 +01:00
|
|
|
/* trigger static peripheral initialization */
|
|
|
|
periph_init();
|
2015-05-19 18:12:40 +02:00
|
|
|
}
|