cpu/samd21: added cpu clock configuration
- choosable between PLL and internal 8MHz osciallator - configurable to a wide range of frequencies
This commit is contained in:
parent
acb06d8fe8
commit
164721657d
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2015 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
|
||||
@ -14,22 +14,80 @@
|
||||
* @brief Implementation of the CPU initialization
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
void clk_init(void);
|
||||
#include "periph_conf.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize the CPU, set IRQ priorities
|
||||
* @brief Configure clock sources and the cpu frequency
|
||||
*/
|
||||
static void clk_init(void)
|
||||
{
|
||||
/* enable clocks for the power, sysctrl and gclk modules */
|
||||
PM->APBAMASK.reg = (PM_APBAMASK_PM | PM_APBAMASK_SYSCTRL |
|
||||
PM_APBAMASK_GCLK);
|
||||
|
||||
/* adjust NVM wait states, see table 42.30 (p. 1070) in the datasheet */
|
||||
#if (CLOCK_CORECLOCK > 24000000)
|
||||
PM->APBAMASK.reg |= PM_AHBMASK_NVMCTRL;
|
||||
NVMCTRL->CTRLB.reg |= NVMCTRL_CTRLB_RWS(1);
|
||||
PM->APBAMASK.reg &= ~PM_AHBMASK_NVMCTRL;
|
||||
#endif
|
||||
|
||||
/* configure internal 8MHz oscillator to run without prescaler */
|
||||
SYSCTRL->OSC8M.bit.PRESC = 0;
|
||||
SYSCTRL->OSC8M.bit.ONDEMAND = 0;
|
||||
SYSCTRL->OSC8M.bit.RUNSTDBY = 0;
|
||||
SYSCTRL->OSC8M.bit.ENABLE = 1;
|
||||
while (!(SYSCTRL->PCLKSR.reg & SYSCTRL_PCLKSR_OSC8MRDY));
|
||||
|
||||
#if CLOCK_USE_PLL
|
||||
/* 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 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);
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||
|
||||
/* 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 &
|
||||
(SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK)) ==
|
||||
(SYSCTRL_DPLLSTATUS_CLKRDY | SYSCTRL_DPLLSTATUS_LOCK));
|
||||
|
||||
/* 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 |
|
||||
GCLK_GENCTRL_SRC_FDPLL96M |
|
||||
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 */
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||
}
|
||||
|
||||
void cpu_init(void)
|
||||
{
|
||||
/* pm clk enable */
|
||||
PM->APBAMASK.reg = PM_APBAMASK_PM;
|
||||
/* port clk enable */
|
||||
PM->APBBMASK.reg |= PM_APBBMASK_PORT;
|
||||
/* disable the watchdog timer */
|
||||
WDT->CTRL.bit.ENABLE = 0;
|
||||
/* initialize the Cortex-M core */
|
||||
@ -37,28 +95,3 @@ void cpu_init(void)
|
||||
/* Initialise clock sources and generic clocks */
|
||||
clk_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Initialise clock sources and generic clocks
|
||||
*/
|
||||
void clk_init(void)
|
||||
{
|
||||
PM->APBAMASK.reg |= PM_APBAMASK_SYSCTRL;
|
||||
PM->APBAMASK.reg |= PM_APBAMASK_GCLK;
|
||||
|
||||
SYSCTRL->OSC8M.bit.PRESC = 0;
|
||||
SYSCTRL->OSC8M.bit.ONDEMAND = 1;
|
||||
SYSCTRL->OSC8M.bit.RUNSTDBY = 0;
|
||||
SYSCTRL->OSC8M.bit.ENABLE = 1;
|
||||
|
||||
/* Software reset the module to ensure it is re-initialized correctly */
|
||||
GCLK->CTRL.reg = GCLK_CTRL_SWRST;
|
||||
while (GCLK->CTRL.reg & GCLK_CTRL_SWRST);
|
||||
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||
/* Select the correct generator */
|
||||
*((uint8_t*)&GCLK->GENDIV.reg) = 0;
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||
GCLK->GENCTRL.reg = (GCLK_GENCTRL_GENEN | GCLK_GENCTRL_SRC_OSC8M | GCLK_CLKCTRL_GEN_GCLK0);
|
||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY);
|
||||
}
|
||||
|
||||
@ -176,6 +176,7 @@ typedef union {
|
||||
#define GCLK_GENCTRL_SRC_XOSC32K_Val 0x5u /**< \brief (GCLK_GENCTRL) XOSC32K oscillator output */
|
||||
#define GCLK_GENCTRL_SRC_OSC8M_Val 0x6u /**< \brief (GCLK_GENCTRL) OSC8M oscillator output */
|
||||
#define GCLK_GENCTRL_SRC_DFLL48M_Val 0x7u /**< \brief (GCLK_GENCTRL) DFLL48M output */
|
||||
#define GCLK_GENCTRL_SRC_FDPLL96M_Val 0x8u /**< \brief (GCLK_GENCTRL) FDPLL96M output */
|
||||
#define GCLK_GENCTRL_SRC_XOSC (GCLK_GENCTRL_SRC_XOSC_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
#define GCLK_GENCTRL_SRC_GCLKIN (GCLK_GENCTRL_SRC_GCLKIN_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
#define GCLK_GENCTRL_SRC_GCLKGEN1 (GCLK_GENCTRL_SRC_GCLKGEN1_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
@ -184,6 +185,7 @@ typedef union {
|
||||
#define GCLK_GENCTRL_SRC_XOSC32K (GCLK_GENCTRL_SRC_XOSC32K_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
#define GCLK_GENCTRL_SRC_OSC8M (GCLK_GENCTRL_SRC_OSC8M_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
#define GCLK_GENCTRL_SRC_DFLL48M (GCLK_GENCTRL_SRC_DFLL48M_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
#define GCLK_GENCTRL_SRC_FDPLL96M (GCLK_GENCTRL_SRC_FDPLL96M_Val << GCLK_GENCTRL_SRC_Pos)
|
||||
#define GCLK_GENCTRL_GENEN_Pos 16 /**< \brief (GCLK_GENCTRL) Generic Clock Generator Enable */
|
||||
#define GCLK_GENCTRL_GENEN (0x1u << GCLK_GENCTRL_GENEN_Pos)
|
||||
#define GCLK_GENCTRL_IDC_Pos 17 /**< \brief (GCLK_GENCTRL) Improve Duty Cycle */
|
||||
|
||||
@ -82,7 +82,7 @@ int i2c_init_master(i2c_t dev, i2c_speed_t speed)
|
||||
pin_scl = I2C_SDA;
|
||||
pin_sda = I2C_SCL;
|
||||
i2c_pins = I2C_0_PINS;
|
||||
clock_source_speed = I2C_0_REF_F;
|
||||
clock_source_speed = CLOCK_CORECLOCK;
|
||||
sercom_core = SERCOM3_GCLK_ID_CORE;
|
||||
sercom_gclk_id_slow = SERCOM3_GCLK_ID_SLOW ;
|
||||
break;
|
||||
|
||||
@ -66,9 +66,19 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
||||
f_baud = 1000000;
|
||||
break;
|
||||
case SPI_SPEED_5MHZ:
|
||||
#if CLOCK_CORECLOCK >= 5000000
|
||||
f_baud = 5000000;
|
||||
break;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
case SPI_SPEED_10MHZ:
|
||||
#if CLOCK_CORECLOCK >= 10000000
|
||||
f_baud = 10000000;
|
||||
break;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
switch(conf)
|
||||
{
|
||||
@ -172,7 +182,9 @@ int spi_init_master(spi_t dev, spi_conf_t conf, spi_speed_t speed)
|
||||
spi_dev->CTRLA.reg |= SERCOM_SPI_CTRLA_MODE_SPI_MASTER;
|
||||
while (spi_dev->SYNCBUSY.reg);
|
||||
|
||||
spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t) SPI_0_F_REF) / (2 * f_baud) - 1); /* Syncronous mode*/
|
||||
spi_dev->BAUD.bit.BAUD = (uint8_t) (((uint32_t)CLOCK_CORECLOCK) / (2 * f_baud) - 1); /* Syncronous mode*/
|
||||
|
||||
|
||||
spi_dev->CTRLA.reg |= (SERCOM_SPI_CTRLA_DOPO(dopo))
|
||||
| (SERCOM_SPI_CTRLA_DIPO(dipo))
|
||||
| (cpha << SERCOM_SPI_CTRLA_CPHA_Pos)
|
||||
|
||||
@ -48,13 +48,27 @@ timer_conf_t config[TIMER_NUMOF];
|
||||
*/
|
||||
int timer_init(tim_t dev, unsigned int us_per_ticks, void (*callback)(int))
|
||||
{
|
||||
/* configure GCLK0 to feed TC3, TC4 and TC5 */;
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (TC3_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
/* at the moment, the timer can only run at 1MHz */
|
||||
if (us_per_ticks != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 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
|
||||
/* configure GCLK1 (configured to 1MHz) 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 */
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK1 | (TC4_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
#else
|
||||
/* configure GCLK0 to feed TC3, TC4 and TC5 */;
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (TC3_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
/* TC4 and TC5 share the same channel */
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (TC4_GCLK_ID << GCLK_CLKCTRL_ID_Pos)));
|
||||
#endif
|
||||
while (GCLK->STATUS.bit.SYNCBUSY);
|
||||
/* select the timer and enable the timer specific peripheral clocks */
|
||||
|
||||
switch (dev) {
|
||||
#if TIMER_0_EN
|
||||
@ -68,8 +82,13 @@ int timer_init(tim_t dev, unsigned int us_per_ticks, void (*callback)(int))
|
||||
while (TIMER_0_DEV.CTRLA.bit.SWRST);
|
||||
/* choosing 16 bit mode */
|
||||
TIMER_0_DEV.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT16_Val;
|
||||
/* sourced by 8MHz with Presc 64 results in 125kHz clk */
|
||||
TIMER_0_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV64_Val;
|
||||
#if CLOCK_USE_PLL
|
||||
/* sourced by 1MHz with prescaler 1 results in... you know it :-) */
|
||||
TIMER_0_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV1_Val;
|
||||
#else
|
||||
/* sourced by 8MHz with Presc 8 results in 1MHz clk */
|
||||
TIMER_0_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV8_Val;
|
||||
#endif
|
||||
/* choose normal frequency operation */
|
||||
TIMER_0_DEV.CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val;
|
||||
break;
|
||||
@ -87,8 +106,13 @@ int timer_init(tim_t dev, unsigned int us_per_ticks, void (*callback)(int))
|
||||
|
||||
|
||||
TIMER_1_DEV.CTRLA.bit.MODE = TC_CTRLA_MODE_COUNT32_Val;
|
||||
#if CLOCK_USE_PLL
|
||||
/* 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 */
|
||||
TIMER_1_DEV.CTRLA.bit.PRESCALER = TC_CTRLA_PRESCALER_DIV8_Val;
|
||||
#endif
|
||||
/* choose normal frequency operation */
|
||||
TIMER_1_DEV.CTRLA.bit.WAVEGEN = TC_CTRLA_WAVEGEN_NFRQ_Val;
|
||||
break;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Freie Universität Berlin
|
||||
* Copyright (C) 2015 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
|
||||
@ -15,6 +15,7 @@
|
||||
*
|
||||
* @author Thomas Eichinger <thomas.eichinger@fu-berlin.de>
|
||||
* @author Troels Hoffmeyer <troels.d.hoffmeyer@gmail.com>
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
*
|
||||
* @}
|
||||
*/
|
||||
@ -53,8 +54,6 @@ static inline void irq_handler(uart_t uartnum, SercomUsart *uart);
|
||||
*/
|
||||
static uart_conf_t uart_config[UART_NUMOF];
|
||||
|
||||
static uint64_t _long_division(uint64_t n, uint64_t d);
|
||||
|
||||
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, uart_tx_cb_t tx_cb, void *arg)
|
||||
{
|
||||
/* initialize basic functionality */
|
||||
@ -81,11 +80,7 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, uart_tx_cb_t t
|
||||
|
||||
int uart_init_blocking(uart_t uart, uint32_t baudrate)
|
||||
{
|
||||
/* Calculate the BAUD value */
|
||||
uint64_t temp1 = ((16 * ((uint64_t)baudrate)) << 32);
|
||||
uint64_t ratio = _long_division(temp1 , UART_0_REF_F);
|
||||
uint64_t scale = ((uint64_t)1 << 32) - ratio;
|
||||
uint64_t baud_calculated = (65536 * scale) >> 32;
|
||||
uint32_t baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16);
|
||||
|
||||
switch (uart) {
|
||||
#if UART_0_EN
|
||||
@ -97,9 +92,6 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate)
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM0_GCLK_ID_CORE << GCLK_CLKCTRL_ID_Pos)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY);
|
||||
|
||||
GCLK->CLKCTRL.reg = (uint16_t)((GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM0_GCLK_ID_SLOW << GCLK_CLKCTRL_ID_Pos)));
|
||||
while (GCLK->STATUS.bit.SYNCBUSY);
|
||||
|
||||
/* configure PINS to input/output*/
|
||||
UART_0_PORT.DIRSET.reg = (1 << UART_0_TX_PIN); /* tx's direction is output */
|
||||
UART_0_PORT.PINCFG[UART_0_RX_PIN % 32].bit.INEN = true; /* buffer rx pin's value */
|
||||
@ -117,20 +109,17 @@ int uart_init_blocking(uart_t uart, uint32_t baudrate)
|
||||
/* set to LSB, asynchronous mode without parity, PAD0 Tx, PAD1 Rx,
|
||||
* 16x over-sampling, internal clk */
|
||||
UART_0_DEV.CTRLA.reg = SERCOM_USART_CTRLA_DORD \
|
||||
| SERCOM_USART_CTRLA_FORM(0x0) \
|
||||
| SERCOM_USART_CTRLA_SAMPA(0x0) \
|
||||
| SERCOM_USART_CTRLA_TXPO(0x0) \
|
||||
| SERCOM_USART_CTRLA_RXPO(0x1) \
|
||||
| SERCOM_USART_CTRLA_SAMPR(0x0) \
|
||||
| SERCOM_USART_CTRLA_SAMPR(0x1) \
|
||||
| SERCOM_USART_CTRLA_MODE_USART_INT_CLK;
|
||||
|
||||
/* Set baud rate */
|
||||
UART_0_DEV.BAUD.bit.BAUD = baud_calculated;
|
||||
|
||||
UART_0_DEV.BAUD.FRAC.FP = (baud % 10);
|
||||
UART_0_DEV.BAUD.FRAC.BAUD = (baud / 10);
|
||||
|
||||
/* enable receiver and transmitter, one stop bit*/
|
||||
UART_0_DEV.CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN);
|
||||
while(UART_0_DEV.SYNCBUSY.bit.CTRLB);
|
||||
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
@ -226,29 +215,4 @@ static inline void irq_handler(uint8_t uartnum, SercomUsart *dev)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static uint64_t _long_division(uint64_t n, uint64_t d)
|
||||
{
|
||||
int32_t i;
|
||||
uint64_t q = 0, r = 0, bit_shift;
|
||||
for (i = 63; i >= 0; i--) {
|
||||
bit_shift = (uint64_t)1 << i;
|
||||
|
||||
r = r << 1;
|
||||
|
||||
if (n & bit_shift) {
|
||||
r |= 0x01;
|
||||
}
|
||||
|
||||
if (r >= d) {
|
||||
r = r - d;
|
||||
q |= bit_shift;
|
||||
}
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
#endif /* UART_NUMOF */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user