Merge pull request #1065 from uknoblic/cc2538_speed
CC2538: Allow for configuration of processor clocks
This commit is contained in:
commit
a6c5a49a88
|
@ -37,12 +37,12 @@
|
|||
* Implementation of the clock module for the cc2538
|
||||
*
|
||||
* To implement the clock functionality, we use the SysTick peripheral on the
|
||||
* cortex-M3. We run the system clock at 16 MHz and we set the SysTick to give
|
||||
* us 128 interrupts / sec. However, the Sleep Timer counter value is used for
|
||||
* the number of elapsed ticks in order to avoid a significant time drift caused
|
||||
* by PM1/2. Contrary to the Sleep Timer, the SysTick peripheral is indeed
|
||||
* frozen during PM1/2, so adjusting upon wake-up a tick counter based on this
|
||||
* peripheral would hardly be accurate.
|
||||
* cortex-M3. We run the system clock at a configurable speed and set the
|
||||
* SysTick to give us 128 interrupts / sec. However, the Sleep Timer counter
|
||||
* value is used for the number of elapsed ticks in order to avoid a
|
||||
* significant time drift caused by PM1/2. Contrary to the Sleep Timer, the
|
||||
* SysTick peripheral is indeed frozen during PM1/2, so adjusting upon wake-up
|
||||
* a tick counter based on this peripheral would hardly be accurate.
|
||||
* @{
|
||||
*
|
||||
* \file
|
||||
|
@ -62,7 +62,19 @@
|
|||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
#define RTIMER_CLOCK_TICK_RATIO (RTIMER_SECOND / CLOCK_SECOND)
|
||||
#define RELOAD_VALUE (125000 - 1) /** Fire 128 times / sec */
|
||||
|
||||
/* Prescaler for GPT0:Timer A used for clock_delay_usec(). */
|
||||
#if SYS_CTRL_SYS_CLOCK < SYS_CTRL_1MHZ
|
||||
#error System clock speeds below 1MHz are not supported
|
||||
#endif
|
||||
#define PRESCALER_VALUE (SYS_CTRL_SYS_CLOCK / SYS_CTRL_1MHZ - 1)
|
||||
|
||||
/* Reload value for SysTick counter */
|
||||
#if SYS_CTRL_SYS_CLOCK % CLOCK_SECOND
|
||||
/* Too low clock speeds will lead to reduced accurracy */
|
||||
#error System clock speed too slow for CLOCK_SECOND, accuracy reduced
|
||||
#endif
|
||||
#define RELOAD_VALUE (SYS_CTRL_SYS_CLOCK / CLOCK_SECOND - 1)
|
||||
|
||||
static volatile uint64_t rt_ticks_startup = 0, rt_ticks_epoch = 0;
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
@ -74,8 +86,8 @@ static volatile uint64_t rt_ticks_startup = 0, rt_ticks_epoch = 0;
|
|||
*
|
||||
* We also initialise GPT0:Timer A, which is used by clock_delay_usec().
|
||||
* We use 16-bit range (individual), count-down, one-shot, no interrupts.
|
||||
* The system clock is at 16MHz giving us 62.5 nano sec ticks for Timer A.
|
||||
* Prescaled by 16 gives us a very convenient 1 tick per usec
|
||||
* The prescaler is computed according to the system clock in order to get 1
|
||||
* tick per usec.
|
||||
*/
|
||||
void
|
||||
clock_init(void)
|
||||
|
@ -98,15 +110,14 @@ clock_init(void)
|
|||
/* Make sure GPT0 is off */
|
||||
REG(GPT_0_BASE + GPTIMER_CTL) = 0;
|
||||
|
||||
|
||||
/* 16-bit */
|
||||
REG(GPT_0_BASE + GPTIMER_CFG) = 0x04;
|
||||
|
||||
/* One-Shot, Count Down, No Interrupts */
|
||||
REG(GPT_0_BASE + GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
|
||||
|
||||
/* Prescale by 16 (thus, value 15 in TAPR) */
|
||||
REG(GPT_0_BASE + GPTIMER_TAPR) = 0x0F;
|
||||
/* Prescale depending on system clock used */
|
||||
REG(GPT_0_BASE + GPTIMER_TAPR) = PRESCALER_VALUE;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
CCIF clock_time_t
|
||||
|
|
|
@ -43,15 +43,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include "clock.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/* Additional functions */
|
||||
static uint32_t
|
||||
get_sys_clock(void)
|
||||
{
|
||||
/* Get the clock status diviser */
|
||||
return SYS_CTRL_32MHZ /
|
||||
(1 << (REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SYS_DIV));
|
||||
}
|
||||
#include "sys-ctrl.h"
|
||||
/*---------------------------------------------------------------------------*/
|
||||
void
|
||||
i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl,
|
||||
|
@ -111,7 +103,7 @@ void
|
|||
i2c_set_frequency(uint32_t freq)
|
||||
{
|
||||
/* Peripheral clock setting, using the system clock */
|
||||
REG(I2CM_TPR) = ((get_sys_clock() + (2 * 10 * freq) - 1) /
|
||||
REG(I2CM_TPR) = ((SYS_CTRL_SYS_CLOCK + (2 * 10 * freq) - 1) /
|
||||
(2 * 10 * freq)) - 1;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
|
|
@ -226,8 +226,8 @@ spix_init(uint8_t spi)
|
|||
/* Start by disabling the peripheral before configuring it */
|
||||
REG(regs->base + SSI_CR1) = 0;
|
||||
|
||||
/* Set the IO clock as the SSI clock */
|
||||
REG(regs->base + SSI_CC) = 1;
|
||||
/* Set the system clock as the SSI clock */
|
||||
REG(regs->base + SSI_CC) = 0;
|
||||
|
||||
/* Set the mux correctly to connect the SSI pins to the correct GPIO pins */
|
||||
ioc_set_sel(regs->clk.port,
|
||||
|
|
|
@ -70,17 +70,18 @@ sys_ctrl_init()
|
|||
* 32KHz source: RC or crystal, according to SYS_CTRL_OSC32K_USE_XTAL
|
||||
* System Clock: 32 MHz
|
||||
* Power Down Unused
|
||||
* I/O Div: 16MHz
|
||||
* Sys Div: 16MHz
|
||||
* I/O Div: according to SYS_CTRL_IO_DIV
|
||||
* Sys Div: according to SYS_CTRL_SYS_DIV
|
||||
* Rest: Don't care
|
||||
*/
|
||||
|
||||
val = SYS_CTRL_OSCS | SYS_CTRL_CLOCK_CTRL_OSC_PD
|
||||
| SYS_CTRL_CLOCK_CTRL_IO_DIV_16MHZ | SYS_CTRL_CLOCK_CTRL_SYS_DIV_16MHZ;
|
||||
| SYS_CTRL_IO_DIV | SYS_CTRL_SYS_DIV;
|
||||
REG(SYS_CTRL_CLOCK_CTRL) = val;
|
||||
|
||||
while((REG(SYS_CTRL_CLOCK_STA) & (SYS_CTRL_CLOCK_STA_OSC32K |
|
||||
SYS_CTRL_CLOCK_STA_OSC)) != SYS_CTRL_OSCS);
|
||||
while((REG(SYS_CTRL_CLOCK_STA)
|
||||
& (SYS_CTRL_CLOCK_STA_OSC32K | SYS_CTRL_CLOCK_STA_OSC))
|
||||
!= SYS_CTRL_OSCS);
|
||||
|
||||
#if SYS_CTRL_OSC32K_USE_XTAL
|
||||
/* Wait for the 32-kHz crystal oscillator to stabilize */
|
||||
|
@ -94,7 +95,20 @@ sys_ctrl_reset()
|
|||
{
|
||||
REG(SYS_CTRL_PWRDBG) = SYS_CTRL_PWRDBG_FORCE_WARM_RESET;
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint32_t
|
||||
sys_ctrl_get_sys_clock(void)
|
||||
{
|
||||
return SYS_CTRL_32MHZ >> (REG(SYS_CTRL_CLOCK_STA) &
|
||||
SYS_CTRL_CLOCK_STA_SYS_DIV);
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
uint32_t
|
||||
sys_ctrl_get_io_clock(void)
|
||||
{
|
||||
return SYS_CTRL_32MHZ >> ((REG(SYS_CTRL_CLOCK_STA) &
|
||||
SYS_CTRL_CLOCK_STA_IO_DIV) >> 8);
|
||||
}
|
||||
/**
|
||||
* @}
|
||||
* @}
|
||||
|
|
|
@ -42,6 +42,8 @@
|
|||
*/
|
||||
#ifndef SYS_CTRL_H_
|
||||
#define SYS_CTRL_H_
|
||||
|
||||
#include <stdint.h>
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \name SysCtrl Constants, used by the SYS_DIV and IO_DIV bits of the
|
||||
* SYS_CTRL_CLOCK_CTRL register
|
||||
|
@ -242,6 +244,33 @@
|
|||
#endif
|
||||
/** @} */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \name System clock divisor selection
|
||||
* @{
|
||||
*/
|
||||
#ifdef SYS_CTRL_CONF_SYS_DIV
|
||||
#if SYS_CTRL_CONF_SYS_DIV & ~SYS_CTRL_CLOCK_CTRL_SYS_DIV
|
||||
#error Invalid system clock divisor
|
||||
#endif
|
||||
#define SYS_CTRL_SYS_DIV SYS_CTRL_CONF_SYS_DIV
|
||||
#else
|
||||
#define SYS_CTRL_SYS_DIV SYS_CTRL_CLOCK_CTRL_SYS_DIV_16MHZ
|
||||
#endif
|
||||
|
||||
#ifdef SYS_CTRL_CONF_IO_DIV
|
||||
#if SYS_CTRL_CONF_IO_DIV & ~SYS_CTRL_CLOCK_CTRL_IO_DIV
|
||||
#error Invalid I/O clock divisor
|
||||
#endif
|
||||
#define SYS_CTRL_IO_DIV SYS_CTRL_CONF_IO_DIV
|
||||
#else
|
||||
#define SYS_CTRL_IO_DIV SYS_CTRL_CLOCK_CTRL_IO_DIV_16MHZ
|
||||
#endif
|
||||
|
||||
/* Returns actual system clock in Hz */
|
||||
#define SYS_CTRL_SYS_CLOCK (SYS_CTRL_32MHZ >> SYS_CTRL_SYS_DIV)
|
||||
/* Returns actual I/O clock in Hz */
|
||||
#define SYS_CTRL_IO_CLOCK (SYS_CTRL_32MHZ >> (SYS_CTRL_IO_DIV >> 8))
|
||||
/** @} */
|
||||
/*---------------------------------------------------------------------------*/
|
||||
/** \name SysCtrl functions
|
||||
* @{
|
||||
*/
|
||||
|
@ -253,6 +282,12 @@ void sys_ctrl_init();
|
|||
/** \brief Generates a warm reset through the SYS_CTRL_PWRDBG register */
|
||||
void sys_ctrl_reset();
|
||||
|
||||
/** \brief Returns the actual system clock in Hz */
|
||||
uint32_t sys_ctrl_get_sys_clock();
|
||||
|
||||
/** \brief Returns the actual io clock in Hz */
|
||||
uint32_t sys_ctrl_get_io_clock();
|
||||
|
||||
/** @} */
|
||||
|
||||
#endif /* SYS_CTRL_H_ */
|
||||
|
|
|
@ -136,7 +136,7 @@
|
|||
* Baud rate defines used in uart_init() to set the values of UART_IBRD and
|
||||
* UART_FBRD in order to achieve the configured baud rates.
|
||||
*/
|
||||
#define UART_CLOCK_RATE 16000000 /* 16 MHz */
|
||||
#define UART_CLOCK_RATE SYS_CTRL_SYS_CLOCK
|
||||
#define UART_CTL_HSE_VALUE 0
|
||||
#define UART_CTL_VALUE (UART_CTL_RXE | UART_CTL_TXE | (UART_CTL_HSE_VALUE << 5))
|
||||
|
||||
|
|
|
@ -78,8 +78,8 @@ static unsigned long irq_energest = 0;
|
|||
#if LPM_CONF_STATS
|
||||
rtimer_clock_t lpm_stats[3];
|
||||
|
||||
#define LPM_STATS_INIT() do { memset(lpm_stats, 0, sizeof(lpm_stats)); \
|
||||
} while(0)
|
||||
#define LPM_STATS_INIT() \
|
||||
do { memset(lpm_stats, 0, sizeof(lpm_stats)); } while(0)
|
||||
#define LPM_STATS_ADD(pm, val) do { lpm_stats[pm] += val; } while(0)
|
||||
#else
|
||||
#define LPM_STATS_INIT()
|
||||
|
@ -154,7 +154,7 @@ enter_pm0(void)
|
|||
static void
|
||||
select_32_mhz_xosc(void)
|
||||
{
|
||||
/*First, make sure there is no ongoing clock source change */
|
||||
/* First, make sure there is no ongoing clock source change */
|
||||
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0);
|
||||
|
||||
/* Turn on the 32 MHz XOSC and source the system clock on it. */
|
||||
|
@ -163,8 +163,15 @@ select_32_mhz_xosc(void)
|
|||
/* Wait for the switch to take place */
|
||||
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_OSC) != 0);
|
||||
|
||||
/* Power down the unused oscillator. */
|
||||
REG(SYS_CTRL_CLOCK_CTRL) |= SYS_CTRL_CLOCK_CTRL_OSC_PD;
|
||||
/* Power down the unused oscillator and restore divisors (silicon errata) */
|
||||
REG(SYS_CTRL_CLOCK_CTRL) = (REG(SYS_CTRL_CLOCK_CTRL)
|
||||
#if SYS_CTRL_SYS_DIV == SYS_CTRL_CLOCK_CTRL_SYS_DIV_32MHZ
|
||||
& ~SYS_CTRL_CLOCK_CTRL_SYS_DIV
|
||||
#endif
|
||||
#if SYS_CTRL_IO_DIV == SYS_CTRL_CLOCK_CTRL_IO_DIV_32MHZ
|
||||
& ~SYS_CTRL_CLOCK_CTRL_IO_DIV
|
||||
#endif
|
||||
) | SYS_CTRL_CLOCK_CTRL_OSC_PD;
|
||||
}
|
||||
/*---------------------------------------------------------------------------*/
|
||||
static void
|
||||
|
@ -172,9 +179,19 @@ select_16_mhz_rcosc(void)
|
|||
{
|
||||
/*
|
||||
* Power up both oscillators in order to speed up the transition to the 32-MHz
|
||||
* XOSC after wake up.
|
||||
* XOSC after wake up. In addition, consider CC2538 silicon errata:
|
||||
* "Possible Incorrect Value of Clock Dividers after PM2 and PM3" and
|
||||
* set system clock divisor / I/O clock divisor to 16 MHz in case they run
|
||||
* at full speed (=32 MHz)
|
||||
*/
|
||||
REG(SYS_CTRL_CLOCK_CTRL) &= ~SYS_CTRL_CLOCK_CTRL_OSC_PD;
|
||||
REG(SYS_CTRL_CLOCK_CTRL) = (REG(SYS_CTRL_CLOCK_CTRL)
|
||||
#if SYS_CTRL_SYS_DIV == SYS_CTRL_CLOCK_CTRL_SYS_DIV_32MHZ
|
||||
| SYS_CTRL_CLOCK_CTRL_SYS_DIV_16MHZ
|
||||
#endif
|
||||
#if SYS_CTRL_IO_DIV == SYS_CTRL_CLOCK_CTRL_IO_DIV_32MHZ
|
||||
| SYS_CTRL_CLOCK_CTRL_IO_DIV_16MHZ
|
||||
#endif
|
||||
) & ~SYS_CTRL_CLOCK_CTRL_OSC_PD;
|
||||
|
||||
/*First, make sure there is no ongoing clock source change */
|
||||
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0);
|
||||
|
|
Loading…
Reference in a new issue