Skip to content
Snippets Groups Projects
Unverified Commit a05e2f22 authored by Peter Kietzmann's avatar Peter Kietzmann Committed by GitHub
Browse files

Merge pull request #9693 from smlng/pr/cc2538/timer

cc2538: cleanup and optimisation of periph timer
parents e2d2a479 7ff2e448
No related branches found
No related tags found
No related merge requests found
/*
* Copyright (C) 2014 Loci Controls Inc.
* 2018 HAW Hamburg
*
* 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 +16,7 @@
* @brief CC2538 General Purpose Timer (GPTIMER) driver
*
* @author Ian Martin <ian@locicontrols.com>
* @author Sebastian Meiling <s@mlng.net>
*/
#ifndef CC2538_GPTIMER_H
......@@ -28,15 +30,18 @@
extern "C" {
#endif
#define GPTIMER_NUMOF 4 /**< The CC2538 has four general-purpose timer units. */
#define NUM_CHANNELS_PER_GPTIMER 2 /**< Each G.P. timer unit has two channels: A and B. */
/**
* @brief Timer modes
*/
enum {
GPTIMER_ONE_SHOT_MODE = 1, /**< GPTIMER one-shot mode */
GPTIMER_PERIODIC_MODE = 2, /**< GPTIMER periodic mode */
GPTIMER_CAPTURE_MODE = 3, /**< GPTIMER capture mode */
};
/**
* @brief Timer width configuration
*/
enum {
GPTMCFG_32_BIT_TIMER = 0, /**< 32-bit timer configuration */
GPTMCFG_32_BIT_REAL_TIME_CLOCK = 1, /**< 32-bit real-time clock */
......@@ -48,95 +53,12 @@ enum {
*/
typedef struct {
cc2538_reg_t CFG; /**< GPTIMER Configuration */
/**
* @brief Timer A
*/
union {
cc2538_reg_t TAMR; /**< GPTIMER Timer A mode */
struct {
cc2538_reg_t TAMR2 : 2; /**< GPTM Timer A mode */
cc2538_reg_t TACMR : 1; /**< GPTM Timer A capture mode */
cc2538_reg_t TAAMS : 1; /**< GPTM Timer A alternate mode */
cc2538_reg_t TACDIR : 1; /**< GPTM Timer A count direction */
cc2538_reg_t TAMIE : 1; /**< GPTM Timer A match interrupt enable */
cc2538_reg_t TAWOT : 1; /**< GPTM Timer A wait-on-trigger */
cc2538_reg_t TASNAPS : 1; /**< GPTM Timer A snap shot mode */
cc2538_reg_t TAILD : 1; /**< GPTM Timer A interval load write */
cc2538_reg_t TAPWMIE : 1; /**< GPTM Timer A PWM interrupt enable */
cc2538_reg_t TAMRSU : 1; /**< Timer A match register update mode */
cc2538_reg_t TAPLO : 1; /**< Legacy PWM operation */
cc2538_reg_t RESERVED5 : 20; /**< Reserved bits */
} TAMRbits;
} cc2538_gptimer_tamr;
/**
* @brief Timer B
*/
union {
cc2538_reg_t TBMR; /**< GPTIMER Timer B mode */
struct {
cc2538_reg_t TBMR2 : 2; /**< GPTM Timer B mode */
cc2538_reg_t TBCMR : 1; /**< GPTM Timer B capture mode */
cc2538_reg_t TBAMS : 1; /**< GPTM Timer B alternate mode */
cc2538_reg_t TBCDIR : 1; /**< GPTM Timer B count direction */
cc2538_reg_t TBMIE : 1; /**< GPTM Timer B match interrupt enable */
cc2538_reg_t TBWOT : 1; /**< GPTM Timer B wait-on-trigger */
cc2538_reg_t TBSNAPS : 1; /**< GPTM Timer B snap shot mode */
cc2538_reg_t TBILD : 1; /**< GPTM Timer B interval load write */
cc2538_reg_t TBPWMIE : 1; /**< GPTM Timer B PWM interrupt enable */
cc2538_reg_t TBMRSU : 1; /**< Timer B match register update mode */
cc2538_reg_t TBPLO : 1; /**< Legacy PWM operation */
cc2538_reg_t RESERVED6 : 20; /**< Reserved bits */
} TBMRbits;
} cc2538_gptimer_tbmr;
/**
* @brief Timer Control
*/
union {
cc2538_reg_t CTL; /**< GPTIMER Control */
struct {
cc2538_reg_t TAEN : 1; /**< GPTM Timer A enable */
cc2538_reg_t TASTALL : 1; /**< GPTM Timer A stall enable */
cc2538_reg_t TAEVENT : 1; /**< GPTM Timer A event mode */
cc2538_reg_t RESERVED1 : 1; /**< Reserved bits */
cc2538_reg_t TAOTE : 1; /**< GPTM Timer A PWM output trigger enable */
cc2538_reg_t TAPWML : 1; /**< GPTM Timer A PWM output level */
cc2538_reg_t RESERVED2 : 1; /**< Reserved bits */
cc2538_reg_t TBEN : 1; /**< GPTM Timer B enable */
cc2538_reg_t TBSTALL : 1; /**< GPTM Timer B stall enable */
cc2538_reg_t TBEVENT : 1; /**< GPTM Timer B event mode */
cc2538_reg_t RESERVED3 : 1; /**< Reserved bits */
cc2538_reg_t TBOTE : 1; /**< GPTM Timer B PWM output trigger enable */
cc2538_reg_t TBPWML : 1; /**< GPTM Timer B PWM output level */
cc2538_reg_t RESERVED4 : 17; /**< Reserved bits */
} CTLbits;
} cc2538_gptimer_ctl;
cc2538_reg_t TAMR; /**< GPTIMER Timer A mode */
cc2538_reg_t TBMR; /**< GPTIMER Timer B mode */
cc2538_reg_t CTL; /**< GPTIMER Control */
cc2538_reg_t SYNC; /**< GPTIMER Synchronize */
cc2538_reg_t RESERVED2; /**< Reserved word */
/**
* @brief Interrupt mask control
*/
union {
cc2538_reg_t IMR; /**< GPTIMER Interrupt Mask */
struct {
cc2538_reg_t TATOIM : 1; /**< GPTM Timer A time-out interrupt mask */
cc2538_reg_t CAMIM : 1; /**< GPTM Timer A capture match interrupt mask */
cc2538_reg_t CAEIM : 1; /**< GPTM Timer A capture event interrupt mask */
cc2538_reg_t RESERVED1 : 1; /**< Reserved bits */
cc2538_reg_t TAMIM : 1; /**< GPTM Timer A match interrupt mask */
cc2538_reg_t RESERVED2 : 3; /**< Reserved bits */
cc2538_reg_t TBTOIM : 1; /**< GPTM Timer B time-out interrupt mask */
cc2538_reg_t CBMIM : 1; /**< GPTM Timer B capture match interrupt mask */
cc2538_reg_t CBEIM : 1; /**< GPTM Timer B capture event interrupt mask */
cc2538_reg_t TBMIM : 1; /**< GPTM Timer B match interrupt mask */
cc2538_reg_t RESERVED3 : 20; /**< Reserved bits */
} IMRbits;
} cc2538_gptimer_imr;
cc2538_reg_t IMR; /**< GPTIMER Interrupt Mask */
cc2538_reg_t RIS; /**< GPTIMER Raw Interrupt Status */
cc2538_reg_t MIS; /**< GPTIMER Masked Interrupt Status */
cc2538_reg_t ICR; /**< GPTIMER Interrupt Clear */
......@@ -162,25 +84,6 @@ typedef struct {
cc2538_reg_t RESERVED4[15]; /**< Reserved */
} cc2538_gptimer_t;
/**
* @brief Base address of general-purpose timers (GPT)
*/
#define GPTIMER_BASE (0x40030000)
#define GPTIMER0 ( (cc2538_gptimer_t*)0x40030000 ) /**< GPTIMER0 Instance */
#define GPTIMER1 ( (cc2538_gptimer_t*)0x40031000 ) /**< GPTIMER1 Instance */
#define GPTIMER2 ( (cc2538_gptimer_t*)0x40032000 ) /**< GPTIMER2 Instance */
#define GPTIMER3 ( (cc2538_gptimer_t*)0x40033000 ) /**< GPTIMER3 Instance */
void isr_timer0_chan0(void); /**< RIOT Timer 0 Channel 0 Interrupt Service Routine */
void isr_timer0_chan1(void); /**< RIOT Timer 0 Channel 1 Interrupt Service Routine */
void isr_timer1_chan0(void); /**< RIOT Timer 1 Channel 0 Interrupt Service Routine */
void isr_timer1_chan1(void); /**< RIOT Timer 1 Channel 1 Interrupt Service Routine */
void isr_timer2_chan0(void); /**< RIOT Timer 2 Channel 0 Interrupt Service Routine */
void isr_timer2_chan1(void); /**< RIOT Timer 2 Channel 1 Interrupt Service Routine */
void isr_timer3_chan0(void); /**< RIOT Timer 3 Channel 0 Interrupt Service Routine */
void isr_timer3_chan1(void); /**< RIOT Timer 3 Channel 1 Interrupt Service Routine */
#ifdef __cplusplus
} /* end extern "C" */
#endif
......
......@@ -22,6 +22,9 @@
#include <assert.h>
#include <stdint.h>
#include "vendor/hw_gptimer.h"
#include "vendor/hw_memmap.h"
#include "board.h"
#include "cpu.h"
#include "periph/timer.h"
......@@ -30,24 +33,18 @@
#define ENABLE_DEBUG (0)
#include "debug.h"
#define LOAD_VALUE (0xffff)
#define TIMER_A_IRQ_MASK (0x000000ff)
#define TIMER_B_IRQ_MASK (0x0000ff00)
#define BIT(n) ( 1UL << (n) )
#define LOAD_VALUE (0xffff)
/* GPTIMER_CTL Bits: */
#define TBEN BIT(8)
#define TAEN BIT(0)
#define TIMER_A_IRQ_MASK (0x000000ff)
#define TIMER_B_IRQ_MASK (0x0000ff00)
/* GPTIMER_TnMR Bits: */
#define TnCMIE BIT(5)
#define TnCDIR BIT(4)
/* GPTIMER_CTL Bits */
#define TBEN GPTIMER_CTL_TBEN
#define TAEN GPTIMER_CTL_TAEN
/* GPTIMER_IMR Bits: */
#define TBMIM BIT(11)
#define TAMIM BIT(4)
/* GPTIMER_TnMR Bits */
#define TNMIE GPTIMER_TAMR_TAMIE
#define TNCDIR GPTIMER_TAMR_TACDIR
typedef struct {
uint16_t mask;
......@@ -55,15 +52,8 @@ typedef struct {
} _isr_cfg_t;
static const _isr_cfg_t chn_isr_cfg[] = {
{ .mask = TIMER_A_IRQ_MASK, .flag = TAMIM },
{ .mask = TIMER_B_IRQ_MASK, .flag = TBMIM }
};
static const int irqn_cfg[] = {
GPTIMER_0A_IRQn,
GPTIMER_1A_IRQn,
GPTIMER_2A_IRQn,
GPTIMER_3A_IRQn
{ .mask = TIMER_A_IRQ_MASK, .flag = GPTIMER_IMR_TAMIM },
{ .mask = TIMER_B_IRQ_MASK, .flag = GPTIMER_IMR_TBMIM }
};
/**
......@@ -77,7 +67,7 @@ static inline void _irq_enable(tim_t tim)
DEBUG("%s(%u)\n", __FUNCTION__, tim);
if (tim < TIMER_NUMOF) {
IRQn_Type irqn = irqn_cfg[tim];
IRQn_Type irqn = GPTIMER_0A_IRQn + (2 * tim);
NVIC_SetPriority(irqn, TIMER_IRQ_PRIO);
NVIC_EnableIRQ(irqn);
......@@ -94,7 +84,7 @@ static inline cc2538_gptimer_t *dev(tim_t tim)
{
assert(tim < TIMER_NUMOF);
return ((cc2538_gptimer_t *)(GPTIMER_BASE | (((uint32_t)tim) << 12)));
return ((cc2538_gptimer_t *)(GPTIMER0_BASE | (((uint32_t)tim) << 12)));
}
/**
......@@ -110,21 +100,20 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
}
/* Save the callback function: */
assert(tim < TIMER_NUMOF);
isr_ctx[tim].cb = cb;
isr_ctx[tim].arg = arg;
/* Enable the clock for this timer: */
SYS_CTRL_RCGCGPT |= (1 << tim);
SYS_CTRL->RCGCGPT |= (1 << tim);
/* Disable this timer before configuring it: */
dev(tim)->cc2538_gptimer_ctl.CTL = 0;
dev(tim)->CTL = 0;
uint32_t prescaler = 0;
uint32_t chan_mode = TnCMIE | GPTIMER_PERIODIC_MODE;
uint32_t chan_mode = TNMIE | GPTIMER_PERIODIC_MODE;
if (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) {
/* Count up in periodic mode */
chan_mode |= TnCDIR ;
chan_mode |= TNCDIR ;
if (timer_config[tim].chn > 1) {
DEBUG("Invalid timer_config. Multiple channels are available only in 16-bit mode.");
......@@ -153,15 +142,15 @@ int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
}
dev(tim)->CFG = timer_config[tim].cfg;
dev(tim)->cc2538_gptimer_ctl.CTL = TAEN;
dev(tim)->cc2538_gptimer_tamr.TAMR = chan_mode;
dev(tim)->CTL = TAEN;
dev(tim)->TAMR = chan_mode;
if (timer_config[tim].chn > 1) {
dev(tim)->cc2538_gptimer_tbmr.TBMR = chan_mode;
dev(tim)->TBMR = chan_mode;
dev(tim)->TBPR = prescaler;
dev(tim)->TBILR = LOAD_VALUE;
/* Enable the timer: */
dev(tim)->cc2538_gptimer_ctl.CTL = TBEN | TAEN;
dev(tim)->CTL = TBEN | TAEN;
}
/* Enable interrupts for given timer: */
......@@ -186,7 +175,7 @@ int timer_set_absolute(tim_t tim, int channel, unsigned int value)
else {
dev(tim)->TBMATCHR = (LOAD_VALUE - value);
}
dev(tim)->cc2538_gptimer_imr.IMR |= chn_isr_cfg[channel].flag;
dev(tim)->IMR |= chn_isr_cfg[channel].flag;
return 1;
}
......@@ -199,7 +188,7 @@ int timer_clear(tim_t tim, int channel)
return -1;
}
/* clear interupt flags */
dev(tim)->cc2538_gptimer_imr.IMR &= ~(chn_isr_cfg[channel].flag);
dev(tim)->IMR &= ~(chn_isr_cfg[channel].flag);
return 1;
}
......@@ -232,7 +221,7 @@ void timer_stop(tim_t tim)
DEBUG("%s(%u)\n", __FUNCTION__, tim);
if (tim < TIMER_NUMOF) {
dev(tim)->cc2538_gptimer_ctl.CTL = 0;
dev(tim)->CTL = 0;
}
}
......@@ -242,10 +231,10 @@ void timer_start(tim_t tim)
if (tim < TIMER_NUMOF) {
if (timer_config[tim].chn == 1) {
dev(tim)->cc2538_gptimer_ctl.CTL = TAEN;
dev(tim)->CTL = TAEN;
}
else if (timer_config[tim].chn == 2) {
dev(tim)->cc2538_gptimer_ctl.CTL = TBEN | TAEN;
dev(tim)->CTL = TBEN | TAEN;
}
}
}
......@@ -270,7 +259,7 @@ static void irq_handler(tim_t tim, int channel)
if (mis & chn_isr_cfg[channel].flag) {
/* Disable further match interrupts for this timer/channel */
dev(tim)->cc2538_gptimer_imr.IMR &= ~chn_isr_cfg[channel].flag;
dev(tim)->IMR &= ~chn_isr_cfg[channel].flag;
/* Invoke the callback function */
isr_ctx[tim].cb(isr_ctx[tim].arg, channel);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment