1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-17 05:32:45 +01:00

cpu/lm4f120: Update timer macros to timer_config_t

This commit is contained in:
MrKevinWeiss 2020-09-09 14:35:29 +02:00
parent db6355fb13
commit 7c3082a7a3
3 changed files with 120 additions and 237 deletions

View File

@ -40,35 +40,32 @@ extern "C" {
/** @} */
/**
* @name Timer configuration
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (2U)
#define TIMER_0_EN 1
#define TIMER_1_EN 1
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
{
.dev = WTIMER0_BASE,
.max = 0xffffffff,
.irqn = Timer0A_IRQn,
.sysctl = SYSCTL_PERIPH_WTIMER0,
.intbase = INT_WTIMER0A,
.channels = 1
},
{
.dev = WTIMER1_BASE,
.max = 0xffffffff,
.irqn = Timer1A_IRQn,
.sysctl = SYSCTL_PERIPH_WTIMER1,
.intbase = INT_WTIMER1A,
.channels = 1
},
};
#define TIMER_NUMOF ARRAY_SIZE(timer_config)
/* Timer 0 configuration
*
* WTIMER0 is a 32/64bits timer.
* We use timer_a as TIMER_0
*/
#define TIMER_0_CHANNELS 1
#define TIMER_0_MAX_VALUE (0xffffffff)
#define TIMER_0_ISR isr_wtimer0a
#define TIMER_0_IRQ_CHAN Timer0A_IRQn
/* Timer 1 configuration
*
* WTIMER1 is a 32/64bits timer.
* We use timer_a as TIMER_1
*/
#define TIMER_1_CHANNELS 1
#define TIMER_1_MAX_VALUE (0xffffffff)
#define TIMER_1_ISR isr_wtimer1a
#define TIMER_1_IRQ_CHAN Timer1A_IRQn
/** @} */
/**
* @name UART configuration

View File

@ -21,7 +21,6 @@
#ifndef PERIPH_CPU_H
#define PERIPH_CPU_H
#include "cpu.h"
#ifdef __cplusplus
@ -34,7 +33,7 @@ extern "C" {
*/
#define HAVE_GPIO_T
typedef uint32_t gpio_t;
#define GPIO_PIN(x,y) ((gpio_t)((x<<4) | y))
#define GPIO_PIN(x, y) ((gpio_t)((x<<4) | y))
/** @} */
#ifndef DOXYGEN
@ -106,6 +105,18 @@ typedef enum {
} adc_res_t;
#endif /* ndef DOXYGEN */
/**
* @brief Define timer configuration values
*/
typedef struct {
uint32_t dev; /**< Address of timer base */
uint32_t max; /**< Max tick value of timer */
int irqn; /**< Number of the higher timer IRQ channel */
uint32_t sysctl; /**< Address of timer system control */
uint32_t intbase; /**< Interrupt base of timer */
int channels; /**< Number of channels for the timer */
} timer_conf_t;
/**
* @brief Override SPI hardware chip select macro
*

View File

@ -30,315 +30,190 @@
#include "debug.h"
/**
* @brief Struct holding the configuration data
* @brief Interrupt context for each configured timer
* @{
*/
typedef struct {
timer_cb_t cb; /**< timeout callback */
void *arg; /**< argument to the callback */
unsigned int divisor; /**< software clock divisor */
} timer_conf_t;
static timer_conf_t config[TIMER_NUMOF];
static timer_isr_ctx_t isr_ctx[TIMER_NUMOF];
static uint32_t isr_divisor[TIMER_NUMOF];
/**@}*/
#include "hw_timer.h"
/* enable timer interrupts */
static inline void _irq_enable(tim_t dev);
static inline void _irq_enable(tim_t tim);
/* Missing from driverlib */
static inline unsigned long
PRIV_TimerPrescaleSnapshotGet(unsigned long ulbase, unsigned long ultimer) {
return((ultimer == TIMER_A) ? HWREG(ulbase + TIMER_O_TAPS) :
HWREG(ulbase + TIMER_O_TBPS));
return ((ultimer == TIMER_A) ? HWREG(ulbase + TIMER_O_TAPS) :
HWREG(ulbase + TIMER_O_TBPS));
}
static inline unsigned long long _scaled_to_ll_value(unsigned int uncorrected, unsigned int divisor)
static inline uint64_t _scaled_to_ll_value(uint32_t uncorrected,
uint32_t divisor)
{
const unsigned long long scaledv = (unsigned long long) uncorrected * divisor;
const uint64_t scaledv = (uint64_t) uncorrected * divisor;
return scaledv;
}
static inline unsigned int _llvalue_to_scaled_value(unsigned long long corrected, unsigned int divisor)
static inline uint32_t _llvalue_to_scaled_value(uint64_t corrected,
uint32_t divisor)
{
const unsigned long long scaledv = corrected / divisor;
const uint64_t scaledv = corrected / divisor;
return scaledv;
}
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
{
if (dev >= TIMER_NUMOF){
if (tim >= TIMER_NUMOF){
return -1;
}
const timer_conf_t *cfg = &timer_config[tim];
config[dev].cb = cb;
config[dev].arg = arg;
config[dev].divisor = ROM_SysCtlClockGet() / freq;
isr_ctx[tim].cb = cb;
isr_ctx[tim].arg = arg;
isr_divisor[tim] = ROM_SysCtlClockGet() / freq;
unsigned int sysctl_timer;
unsigned int timer_base;
unsigned int timer_side = TIMER_A;
unsigned int timer_cfg = TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP | TIMER_TAMR_TAMIE;
unsigned int timer_max_val = 0;
unsigned int timer_cfg = TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_PERIODIC_UP |
TIMER_TAMR_TAMIE;
unsigned int timer_intbit = TIMER_TIMA_TIMEOUT | TIMER_TIMA_MATCH;
switch(dev){
#if TIMER_0_EN
case TIMER_0:
sysctl_timer = SYSCTL_PERIPH_WTIMER0;
timer_base = WTIMER0_BASE;
timer_max_val = TIMER_0_MAX_VALUE;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
sysctl_timer = SYSCTL_PERIPH_WTIMER1;
timer_base = WTIMER1_BASE;
timer_max_val = TIMER_1_MAX_VALUE;
break;
#endif
default:
return -1; /* unreachable */
}
ROM_SysCtlPeripheralEnable(cfg->sysctl);
ROM_TimerDisable(cfg->dev, timer_side);
ROM_TimerConfigure(cfg->dev, timer_cfg);
ROM_SysCtlPeripheralEnable(sysctl_timer);
uint64_t val_max = _scaled_to_ll_value(cfg->max, isr_divisor[tim]);
ROM_TimerDisable(timer_base, timer_side);
ROM_TimerConfigure(timer_base, timer_cfg);
ROM_TimerPrescaleSet(cfg->dev, timer_side, val_max >> 32);
ROM_TimerLoadSet(cfg->dev, timer_side, val_max & 0xFFFFFFFF);
ROM_TimerIntClear(cfg->dev, timer_intbit);
unsigned long long lltimer_val_max = _scaled_to_ll_value(timer_max_val, config[dev].divisor);
ROM_TimerIntEnable(cfg->dev, timer_intbit);
ROM_TimerPrescaleSet(timer_base, timer_side, lltimer_val_max >> 32);
ROM_TimerLoadSet(timer_base, timer_side, lltimer_val_max & 0xFFFFFFFF);
ROM_TimerIntClear(timer_base, timer_intbit);
ROM_TimerIntEnable(timer_base, timer_intbit);
_irq_enable(dev);
timer_start(dev);
_irq_enable(tim);
timer_start(tim);
return 0;
}
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
{
(void) channel;
if (tim >= TIMER_NUMOF || channel >= timer_config[tim].channels) {
return -1;
}
const timer_conf_t *cfg = &timer_config[tim];
unsigned int timer_base;
unsigned int timer_side = TIMER_A;
unsigned long long scaledv;
if (dev >= TIMER_NUMOF){
return -1;
}
ROM_TimerDisable(cfg->dev, timer_side);
switch(dev){
#if TIMER_0_EN
case TIMER_0:
timer_base = WTIMER0_BASE;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
timer_base = WTIMER1_BASE;
break;
#endif
default:
return -1; /* unreachable */
break;
}
ROM_TimerDisable(timer_base, timer_side);
scaledv = _scaled_to_ll_value(value, config[dev].divisor);
scaledv = _scaled_to_ll_value(value, isr_divisor[tim]);
if (scaledv>>32){
ROM_TimerPrescaleMatchSet(timer_base, timer_side, scaledv >> 32);
ROM_TimerPrescaleMatchSet(cfg->dev, timer_side, scaledv >> 32);
}
else {
ROM_TimerPrescaleMatchSet(timer_base, timer_side, 0);
ROM_TimerPrescaleMatchSet(cfg->dev, timer_side, 0);
}
ROM_TimerMatchSet(timer_base, timer_side, (unsigned long) (scaledv & 0xFFFFFFFF));
ROM_TimerEnable(timer_base, timer_side);
ROM_TimerMatchSet(cfg->dev, timer_side, (uint32_t) (scaledv & 0xFFFFFFFF));
ROM_TimerEnable(cfg->dev, timer_side);
return 0;
}
int timer_clear(tim_t dev, int channel)
int timer_clear(tim_t tim, int channel)
{
(void) channel;
unsigned int timer_intbit = TIMER_TIMA_TIMEOUT;
unsigned int timer_base;
if (dev >= TIMER_NUMOF){
if (tim >= TIMER_NUMOF || channel >= timer_config[tim].channels) {
return -1;
}
switch(dev){
#if TIMER_0_EN
case TIMER_0:
timer_base = WTIMER0_BASE;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
timer_base = WTIMER1_BASE;
break;
#endif
default:
return -1; /* unreachable */
break;
}
ROM_TimerIntClear(timer_base, timer_intbit);
ROM_TimerIntClear(timer_config[tim].dev, TIMER_TIMA_TIMEOUT);
return 0;
}
unsigned int timer_read(tim_t dev)
unsigned int timer_read(tim_t tim)
{
unsigned int timer_base;
unsigned int timer_side = TIMER_A;
unsigned long long high_bits, high_bits_dup;
unsigned long long low_bits;
unsigned long long total;
unsigned int scaled_value;
if (dev >= TIMER_NUMOF){
if (tim >= TIMER_NUMOF){
return -1;
}
switch(dev){
#if TIMER_0_EN
case TIMER_0:
timer_base = WTIMER0_BASE;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
timer_base = WTIMER1_BASE;
break;
#endif
default:
return -1; /* unreachable */
break;
}
const timer_conf_t *cfg = &timer_config[tim];
/* handle overflow happening between the 2 register reads */
do {
high_bits = ((unsigned long long)PRIV_TimerPrescaleSnapshotGet(timer_base, timer_side)) << 32;
low_bits = (unsigned long long)ROM_TimerValueGet(timer_base, timer_side);
high_bits_dup = ((unsigned long long)PRIV_TimerPrescaleSnapshotGet(timer_base, timer_side)) << 32;
high_bits = ((uint64_t)PRIV_TimerPrescaleSnapshotGet(cfg->dev,
timer_side)) << 32;
low_bits = (uint64_t)ROM_TimerValueGet(cfg->dev, timer_side);
high_bits_dup = ((uint64_t)PRIV_TimerPrescaleSnapshotGet(cfg->dev,
timer_side)) << 32;
} while (high_bits != high_bits_dup);
total = high_bits + low_bits;
DEBUG("Combined %lx:%lx\n", (unsigned long) (total>>32), (unsigned long) (total & 0xFFFFFFFF));
DEBUG("Combined %lx:%lx\n", (uint32_t)(total>>32),
(uint32_t)(total & 0xFFFFFFFF));
scaled_value = _llvalue_to_scaled_value(total, config[dev].divisor);
scaled_value = _llvalue_to_scaled_value(total, isr_divisor[tim]);
return scaled_value;
}
void timer_start(tim_t dev)
void timer_start(tim_t tim)
{
unsigned int timer_base;
unsigned int timer_side = TIMER_A;
if (dev >= TIMER_NUMOF){
return ;
}
switch(dev){
#if TIMER_0_EN
case TIMER_0:
timer_base = WTIMER0_BASE;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
timer_base = WTIMER1_BASE;
break;
#endif
default:
return; /* unreachable */
}
ROM_TimerEnable(timer_base, timer_side);
}
void timer_stop(tim_t dev)
{
unsigned int timer_base;
unsigned int timer_side = TIMER_A;
if (dev >= TIMER_NUMOF){
if (tim >= TIMER_NUMOF){
return;
}
switch(dev){
#if TIMER_0_EN
case TIMER_0:
timer_base = WTIMER0_BASE;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
timer_base = WTIMER1_BASE;
break;
#endif
default:
return; /* unreachable */
}
ROM_TimerDisable(timer_base, timer_side);
ROM_TimerEnable(timer_config[tim].dev, TIMER_A);
}
static inline void _irq_enable(tim_t dev)
void timer_stop(tim_t tim)
{
unsigned int timer_intbase;
if (dev >= TIMER_NUMOF){
if (tim >= TIMER_NUMOF){
return;
}
switch(dev){
#if TIMER_0_EN
case TIMER_0:
timer_intbase = INT_WTIMER0A;
break;
#endif
#if TIMER_1_EN
case TIMER_1:
timer_intbase = INT_WTIMER1A;
break;
#endif
default:
return; /* unreachable */
}
ROM_IntPrioritySet(timer_intbase, 32);
ROM_IntEnable(timer_intbase);
ROM_TimerDisable(timer_config[tim].dev, TIMER_A);
}
#if TIMER_0_EN
void isr_wtimer0a(void)
static inline void _irq_enable(tim_t tim)
{
if (tim >= TIMER_NUMOF){
return;
}
ROM_IntPrioritySet(timer_config[tim].intbase, 32);
ROM_IntEnable(timer_config[tim].intbase);
}
void _isr_timer(tim_t tim)
{
/* Clears both IT */
ROM_TimerIntClear(WTIMER0_BASE, TIMER_TIMA_TIMEOUT | TIMER_TIMA_MATCH);
config[TIMER_0].cb(config[TIMER_0].arg, 0);
ROM_TimerIntClear(timer_config[tim].dev,
TIMER_TIMA_TIMEOUT | TIMER_TIMA_MATCH);
isr_ctx[tim].cb(isr_ctx[tim].arg, 0);
cortexm_isr_end();
}
#endif /* TIMER_0_EN */
#if TIMER_1_EN
void isr_wtimer1a(void)
#ifdef TIMER_0_ISR
void TIMER_0_ISR(void)
{
ROM_TimerIntClear(WTIMER1_BASE, TIMER_TIMA_TIMEOUT | TIMER_TIMA_MATCH);
config[TIMER_1].cb(config[TIMER_0].arg, 0);
cortexm_isr_end();
_isr_timer(0);
}
#endif /* TIMER_1_EN */
#endif /* TIMER_0_ISR */
#ifdef TIMER_1_ISR
void TIMER_1_ISR(void)
{
_isr_timer(1);
}
#endif /* TIMER_1_ISR */
/** @} */