cc2538: Allow for configuration of processor speed

This commit is contained in:
Ulf Knoblich 2015-05-12 14:06:40 +02:00
parent 730bda2001
commit d8efa8428c
7 changed files with 107 additions and 38 deletions

View file

@ -37,12 +37,12 @@
* Implementation of the clock module for the cc2538 * Implementation of the clock module for the cc2538
* *
* To implement the clock functionality, we use the SysTick peripheral on the * 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 * cortex-M3. We run the system clock at a configurable speed and set the
* us 128 interrupts / sec. However, the Sleep Timer counter value is used for * SysTick to give us 128 interrupts / sec. However, the Sleep Timer counter
* the number of elapsed ticks in order to avoid a significant time drift caused * value is used for the number of elapsed ticks in order to avoid a
* by PM1/2. Contrary to the Sleep Timer, the SysTick peripheral is indeed * significant time drift caused by PM1/2. Contrary to the Sleep Timer, the
* frozen during PM1/2, so adjusting upon wake-up a tick counter based on this * SysTick peripheral is indeed frozen during PM1/2, so adjusting upon wake-up
* peripheral would hardly be accurate. * a tick counter based on this peripheral would hardly be accurate.
* @{ * @{
* *
* \file * \file
@ -62,7 +62,19 @@
#include <stdint.h> #include <stdint.h>
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
#define RTIMER_CLOCK_TICK_RATIO (RTIMER_SECOND / CLOCK_SECOND) #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; 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 also initialise GPT0:Timer A, which is used by clock_delay_usec().
* We use 16-bit range (individual), count-down, one-shot, no interrupts. * 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. * The prescaler is computed according to the system clock in order to get 1
* Prescaled by 16 gives us a very convenient 1 tick per usec * tick per usec.
*/ */
void void
clock_init(void) clock_init(void)
@ -98,15 +110,14 @@ clock_init(void)
/* Make sure GPT0 is off */ /* Make sure GPT0 is off */
REG(GPT_0_BASE + GPTIMER_CTL) = 0; REG(GPT_0_BASE + GPTIMER_CTL) = 0;
/* 16-bit */ /* 16-bit */
REG(GPT_0_BASE + GPTIMER_CFG) = 0x04; REG(GPT_0_BASE + GPTIMER_CFG) = 0x04;
/* One-Shot, Count Down, No Interrupts */ /* One-Shot, Count Down, No Interrupts */
REG(GPT_0_BASE + GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT; REG(GPT_0_BASE + GPTIMER_TAMR) = GPTIMER_TAMR_TAMR_ONE_SHOT;
/* Prescale by 16 (thus, value 15 in TAPR) */ /* Prescale depending on system clock used */
REG(GPT_0_BASE + GPTIMER_TAPR) = 0x0F; REG(GPT_0_BASE + GPTIMER_TAPR) = PRESCALER_VALUE;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
CCIF clock_time_t CCIF clock_time_t

View file

@ -43,15 +43,7 @@
#include <stdint.h> #include <stdint.h>
#include "clock.h" #include "clock.h"
/*---------------------------------------------------------------------------*/ #include "sys-ctrl.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));
}
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
void void
i2c_init(uint8_t port_sda, uint8_t pin_sda, uint8_t port_scl, uint8_t pin_scl, 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) i2c_set_frequency(uint32_t freq)
{ {
/* Peripheral clock setting, using the system clock */ /* 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; (2 * 10 * freq)) - 1;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View file

@ -226,8 +226,8 @@ spix_init(uint8_t spi)
/* Start by disabling the peripheral before configuring it */ /* Start by disabling the peripheral before configuring it */
REG(regs->base + SSI_CR1) = 0; REG(regs->base + SSI_CR1) = 0;
/* Set the IO clock as the SSI clock */ /* Set the system clock as the SSI clock */
REG(regs->base + SSI_CC) = 1; REG(regs->base + SSI_CC) = 0;
/* Set the mux correctly to connect the SSI pins to the correct GPIO pins */ /* Set the mux correctly to connect the SSI pins to the correct GPIO pins */
ioc_set_sel(regs->clk.port, ioc_set_sel(regs->clk.port,

View file

@ -70,17 +70,18 @@ sys_ctrl_init()
* 32KHz source: RC or crystal, according to SYS_CTRL_OSC32K_USE_XTAL * 32KHz source: RC or crystal, according to SYS_CTRL_OSC32K_USE_XTAL
* System Clock: 32 MHz * System Clock: 32 MHz
* Power Down Unused * Power Down Unused
* I/O Div: 16MHz * I/O Div: according to SYS_CTRL_IO_DIV
* Sys Div: 16MHz * Sys Div: according to SYS_CTRL_SYS_DIV
* Rest: Don't care * Rest: Don't care
*/ */
val = SYS_CTRL_OSCS | SYS_CTRL_CLOCK_CTRL_OSC_PD 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; REG(SYS_CTRL_CLOCK_CTRL) = val;
while((REG(SYS_CTRL_CLOCK_STA) & (SYS_CTRL_CLOCK_STA_OSC32K | while((REG(SYS_CTRL_CLOCK_STA)
SYS_CTRL_CLOCK_STA_OSC)) != SYS_CTRL_OSCS); & (SYS_CTRL_CLOCK_STA_OSC32K | SYS_CTRL_CLOCK_STA_OSC))
!= SYS_CTRL_OSCS);
#if SYS_CTRL_OSC32K_USE_XTAL #if SYS_CTRL_OSC32K_USE_XTAL
/* Wait for the 32-kHz crystal oscillator to stabilize */ /* 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; 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);
}
/** /**
* @} * @}
* @} * @}

View file

@ -42,6 +42,8 @@
*/ */
#ifndef SYS_CTRL_H_ #ifndef SYS_CTRL_H_
#define SYS_CTRL_H_ #define SYS_CTRL_H_
#include <stdint.h>
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/** \name SysCtrl Constants, used by the SYS_DIV and IO_DIV bits of the /** \name SysCtrl Constants, used by the SYS_DIV and IO_DIV bits of the
* SYS_CTRL_CLOCK_CTRL register * SYS_CTRL_CLOCK_CTRL register
@ -242,6 +244,33 @@
#endif #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 /** \name SysCtrl functions
* @{ * @{
*/ */
@ -253,6 +282,12 @@ void sys_ctrl_init();
/** \brief Generates a warm reset through the SYS_CTRL_PWRDBG register */ /** \brief Generates a warm reset through the SYS_CTRL_PWRDBG register */
void sys_ctrl_reset(); 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_ */ #endif /* SYS_CTRL_H_ */

View file

@ -136,7 +136,7 @@
* Baud rate defines used in uart_init() to set the values of UART_IBRD and * 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. * 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_HSE_VALUE 0
#define UART_CTL_VALUE (UART_CTL_RXE | UART_CTL_TXE | (UART_CTL_HSE_VALUE << 5)) #define UART_CTL_VALUE (UART_CTL_RXE | UART_CTL_TXE | (UART_CTL_HSE_VALUE << 5))

View file

@ -78,8 +78,8 @@ static unsigned long irq_energest = 0;
#if LPM_CONF_STATS #if LPM_CONF_STATS
rtimer_clock_t lpm_stats[3]; rtimer_clock_t lpm_stats[3];
#define LPM_STATS_INIT() do { memset(lpm_stats, 0, sizeof(lpm_stats)); \ #define LPM_STATS_INIT() \
} while(0) do { memset(lpm_stats, 0, sizeof(lpm_stats)); } while(0)
#define LPM_STATS_ADD(pm, val) do { lpm_stats[pm] += val; } while(0) #define LPM_STATS_ADD(pm, val) do { lpm_stats[pm] += val; } while(0)
#else #else
#define LPM_STATS_INIT() #define LPM_STATS_INIT()
@ -154,7 +154,7 @@ enter_pm0(void)
static void static void
select_32_mhz_xosc(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); 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. */ /* 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 */ /* Wait for the switch to take place */
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_OSC) != 0); while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_OSC) != 0);
/* Power down the unused oscillator. */ /* Power down the unused oscillator and restore divisors (silicon errata) */
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
#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 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 * 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 */ /*First, make sure there is no ongoing clock source change */
while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0); while((REG(SYS_CTRL_CLOCK_STA) & SYS_CTRL_CLOCK_STA_SOURCE_CHANGE) != 0);