2014-10-13 15:29:49 +02:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2014 Loci Controls Inc.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* directory for more details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
2017-06-22 15:43:17 +02:00
|
|
|
* @ingroup cpu_cc2538
|
|
|
|
* @ingroup drivers_periph_timer
|
2014-10-13 15:29:49 +02:00
|
|
|
* @{
|
|
|
|
*
|
2015-05-22 07:34:41 +02:00
|
|
|
* @file
|
2014-10-13 15:29:49 +02:00
|
|
|
* @brief Low-level timer driver implementation for the CC2538 CPU
|
|
|
|
*
|
|
|
|
* @author Ian Martin <ian@locicontrols.com>
|
|
|
|
*
|
|
|
|
* @}
|
|
|
|
*/
|
|
|
|
|
2016-08-16 21:07:26 +02:00
|
|
|
#include <assert.h>
|
|
|
|
#include <stdint.h>
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2018-08-03 09:36:50 +02:00
|
|
|
#include "vendor/hw_gptimer.h"
|
|
|
|
#include "vendor/hw_memmap.h"
|
|
|
|
|
2014-10-13 15:29:49 +02:00
|
|
|
#include "board.h"
|
|
|
|
#include "cpu.h"
|
|
|
|
#include "periph/timer.h"
|
|
|
|
#include "periph_conf.h"
|
|
|
|
|
2020-10-22 11:34:00 +02:00
|
|
|
#define ENABLE_DEBUG 0
|
2016-08-16 21:07:26 +02:00
|
|
|
#include "debug.h"
|
2016-02-22 20:20:14 +01:00
|
|
|
|
2020-08-12 10:07:11 +02:00
|
|
|
#define LOAD_VALUE_16_BIT (UINT16_MAX)
|
|
|
|
#define LOAD_VALUE_32_BIT (UINT32_MAX)
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2018-08-03 09:36:50 +02:00
|
|
|
#define TIMER_A_IRQ_MASK (0x000000ff)
|
|
|
|
#define TIMER_B_IRQ_MASK (0x0000ff00)
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2018-08-03 09:36:50 +02:00
|
|
|
/* GPTIMER_TnMR Bits */
|
2020-03-19 15:39:29 +01:00
|
|
|
#define GPTIMER_TnMR_TnMIE GPTIMER_TAMR_TAMIE
|
|
|
|
#define GPTIMER_TnMR_TnCDIR GPTIMER_TAMR_TACDIR
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
typedef struct {
|
|
|
|
uint16_t mask;
|
|
|
|
uint16_t flag;
|
|
|
|
} _isr_cfg_t;
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
static const _isr_cfg_t chn_isr_cfg[] = {
|
2018-08-03 09:36:50 +02:00
|
|
|
{ .mask = TIMER_A_IRQ_MASK, .flag = GPTIMER_IMR_TAMIM },
|
|
|
|
{ .mask = TIMER_B_IRQ_MASK, .flag = GPTIMER_IMR_TBMIM }
|
2016-08-16 21:07:26 +02:00
|
|
|
};
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
/**
|
|
|
|
* @brief Timer state memory
|
|
|
|
*/
|
|
|
|
static timer_isr_ctx_t isr_ctx[TIMER_NUMOF];
|
|
|
|
|
2020-03-18 17:57:13 +01:00
|
|
|
/* pending timer compare values TxMATCHR */
|
|
|
|
static union {
|
|
|
|
uint16_t u16[2]; /* TIMERA, TIMERB 16bit mode */
|
|
|
|
uint32_t u32; /* extended TIMERA 32bit mode */
|
|
|
|
} _set_values[TIMER_NUMOF];
|
|
|
|
|
|
|
|
/* 2 channels per timer, TIMER_NUMOF <= 4 */
|
|
|
|
static uint8_t _set_timers;
|
|
|
|
|
|
|
|
static void _set_absolute_disabled(tim_t tim, int chan, unsigned int value)
|
|
|
|
{
|
|
|
|
/* each timer can have two channels*/
|
|
|
|
_set_timers |= ((chan + 1) << (2 * tim));
|
|
|
|
|
|
|
|
if (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) {
|
|
|
|
_set_values[tim].u32 = value;
|
|
|
|
} else {
|
|
|
|
_set_values[tim].u16[chan] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _set_pending(tim_t tim)
|
|
|
|
{
|
|
|
|
/* create mask to get set channels of the current timer */
|
|
|
|
const unsigned ch1_msk = (1 << (2 * tim));
|
|
|
|
const unsigned ch2_msk = (2 << (2 * tim));
|
|
|
|
|
|
|
|
if (_set_timers & ch1_msk) {
|
|
|
|
_set_timers &= ~ch1_msk;
|
|
|
|
|
|
|
|
if (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) {
|
|
|
|
timer_set_absolute(tim, 0, _set_values[tim].u32);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
timer_set_absolute(tim, 0, _set_values[tim].u16[0]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_set_timers & ch2_msk) {
|
|
|
|
_set_timers &= ~ch2_msk;
|
|
|
|
timer_set_absolute(tim, 1, _set_values[tim].u16[1]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-14 15:34:53 +01:00
|
|
|
/* enable timer interrupts */
|
2017-07-13 23:32:13 +02:00
|
|
|
static inline void _irq_enable(tim_t tim)
|
|
|
|
{
|
|
|
|
DEBUG("%s(%u)\n", __FUNCTION__, tim);
|
|
|
|
|
|
|
|
if (tim < TIMER_NUMOF) {
|
2020-03-19 16:17:17 +01:00
|
|
|
IRQn_Type irqn;
|
|
|
|
switch (tim) {
|
|
|
|
case 0:
|
|
|
|
irqn = GPTIMER_0A_IRQn;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
irqn = GPTIMER_1A_IRQn;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
irqn = GPTIMER_2A_IRQn;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
irqn = GPTIMER_3A_IRQn;
|
|
|
|
break;
|
|
|
|
}
|
2017-07-13 23:32:13 +02:00
|
|
|
NVIC_SetPriority(irqn, TIMER_IRQ_PRIO);
|
|
|
|
NVIC_EnableIRQ(irqn);
|
|
|
|
|
|
|
|
if (timer_config[tim].chn == 2) {
|
|
|
|
irqn++;
|
|
|
|
NVIC_SetPriority(irqn, TIMER_IRQ_PRIO);
|
|
|
|
NVIC_EnableIRQ(irqn);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-18 17:50:15 +01:00
|
|
|
static inline void _timer_clock_enable(tim_t tim)
|
|
|
|
{
|
|
|
|
DEBUG("%s\n", __FUNCTION__);
|
|
|
|
|
2020-03-18 17:57:13 +01:00
|
|
|
/* enable GPT(tim) clock in active mode */
|
2020-03-18 17:50:15 +01:00
|
|
|
SYS_CTRL->RCGCGPT |= (1UL << tim);
|
2020-03-18 17:57:13 +01:00
|
|
|
/* enable GPT(tim) clock in sleep mode */
|
2020-03-18 17:50:15 +01:00
|
|
|
SYS_CTRL->SCGCGPT |= (1UL << tim);
|
2020-03-18 17:57:13 +01:00
|
|
|
/* enable GPT(tim) clock in PM0 (system clock always powered down
|
|
|
|
in PM1-3) */
|
2020-03-18 17:50:15 +01:00
|
|
|
SYS_CTRL->DCGCGPT |= (1UL << tim);
|
2020-03-18 17:57:13 +01:00
|
|
|
/* wait for the clock enabling to take effect */
|
2020-03-25 20:16:23 +01:00
|
|
|
while (!(SYS_CTRL->RCGCGPT & (1UL << tim)) || \
|
|
|
|
!(SYS_CTRL->SCGCGPT & (1UL << tim)) || \
|
|
|
|
!(SYS_CTRL->DCGCGPT & (1UL << tim))
|
2020-03-18 17:50:15 +01:00
|
|
|
) {}
|
2020-03-18 17:57:13 +01:00
|
|
|
|
|
|
|
/* set pending timers */
|
|
|
|
_set_pending(tim);
|
2020-03-18 17:50:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void _timer_clock_disable(tim_t tim)
|
|
|
|
{
|
|
|
|
DEBUG("%s\n", __FUNCTION__);
|
|
|
|
|
2020-03-18 17:57:13 +01:00
|
|
|
/* gate GPT(tim) clock in active mode */
|
2020-03-18 17:50:15 +01:00
|
|
|
SYS_CTRL->RCGCGPT &= ~(1UL << tim);
|
2020-03-18 17:57:13 +01:00
|
|
|
/* gate GPT(tim) clock in sleep mode */
|
2020-03-18 17:50:15 +01:00
|
|
|
SYS_CTRL->SCGCGPT &= ~(1UL << tim);
|
2020-03-18 17:57:13 +01:00
|
|
|
/* gate GPT(tim) clock in PM0 (system clock always powered down
|
|
|
|
in PM1-3) */
|
2020-03-18 17:50:15 +01:00
|
|
|
SYS_CTRL->DCGCGPT &= ~(1UL << tim);
|
|
|
|
/* Wait for the clock gating to take effect */
|
2020-03-25 20:16:23 +01:00
|
|
|
while ((SYS_CTRL->RCGCGPT & (1UL << tim)) || \
|
|
|
|
(SYS_CTRL->SCGCGPT & (1UL << tim)) || \
|
|
|
|
(SYS_CTRL->DCGCGPT & (1UL << tim))
|
2020-03-18 17:50:15 +01:00
|
|
|
) {}
|
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
static inline cc2538_gptimer_t *dev(tim_t tim)
|
|
|
|
{
|
|
|
|
assert(tim < TIMER_NUMOF);
|
|
|
|
|
2018-08-03 09:36:50 +02:00
|
|
|
return ((cc2538_gptimer_t *)(GPTIMER0_BASE | (((uint32_t)tim) << 12)));
|
2017-07-13 23:32:13 +02:00
|
|
|
}
|
2017-01-14 15:34:53 +01:00
|
|
|
|
2014-10-13 15:29:49 +02:00
|
|
|
/**
|
|
|
|
* @brief Setup the given timer
|
|
|
|
*
|
|
|
|
*/
|
2020-10-30 12:14:35 +01:00
|
|
|
int timer_init(tim_t tim, uint32_t freq, timer_cb_t cb, void *arg)
|
2014-10-13 15:29:49 +02:00
|
|
|
{
|
2017-07-13 23:32:13 +02:00
|
|
|
DEBUG("%s(%u, %lu, %p, %p)\n", __FUNCTION__, tim, freq, cb, arg);
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
if (tim >= TIMER_NUMOF) {
|
2016-08-16 21:07:26 +02:00
|
|
|
return -1;
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Save the callback function: */
|
2020-03-19 15:39:29 +01:00
|
|
|
isr_ctx[tim].cb = cb;
|
2017-07-13 23:32:13 +02:00
|
|
|
isr_ctx[tim].arg = arg;
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2020-03-18 17:57:13 +01:00
|
|
|
/* enable timer clock in active, sleep or PM0 */
|
2020-03-18 17:50:15 +01:00
|
|
|
_timer_clock_enable(tim);
|
2014-10-13 15:29:49 +02:00
|
|
|
|
|
|
|
/* Disable this timer before configuring it: */
|
2018-08-03 09:43:45 +02:00
|
|
|
dev(tim)->CTL = 0;
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
uint32_t prescaler = 0;
|
2020-03-19 15:39:29 +01:00
|
|
|
uint32_t chan_mode = GPTIMER_TnMR_TnMIE | GPTIMER_PERIODIC_MODE;
|
|
|
|
/* Count down in GPTMCFG_16_BIT_TIMER so prescaler is a true prescaler */
|
|
|
|
/* Count up in GPTMCFG_32_BIT_TIMER since prescaler is irrelevant */
|
2017-07-13 23:32:13 +02:00
|
|
|
if (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) {
|
2020-03-19 15:39:29 +01:00
|
|
|
chan_mode |= GPTIMER_TnMR_TnCDIR;
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
if (timer_config[tim].chn > 1) {
|
2020-03-19 15:39:29 +01:00
|
|
|
DEBUG("Invalid timer_config. Multiple channels are available only \
|
|
|
|
in 16-bit mode.");
|
2016-08-16 21:07:26 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (freq != sys_clock_freq()) {
|
2020-03-19 15:39:29 +01:00
|
|
|
DEBUG("In 32-bit mode, the GPTimer frequency must equal the system \
|
|
|
|
clock frequency (%u).\n", (unsigned)sys_clock_freq());
|
2016-08-16 21:07:26 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2017-07-13 23:32:13 +02:00
|
|
|
}
|
|
|
|
else if (timer_config[tim].cfg == GPTMCFG_16_BIT_TIMER) {
|
|
|
|
prescaler = sys_clock_freq();
|
|
|
|
prescaler += freq / 2;
|
|
|
|
prescaler /= freq;
|
2020-03-19 15:39:29 +01:00
|
|
|
if (prescaler > 0) {
|
|
|
|
prescaler--;
|
|
|
|
}
|
|
|
|
if (prescaler > 255) {
|
|
|
|
prescaler = 255;
|
|
|
|
}
|
2017-07-13 23:32:13 +02:00
|
|
|
dev(tim)->TAPR = prescaler;
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->TBPR = prescaler;
|
2017-07-13 23:32:13 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
DEBUG("timer_init: invalid timer config must be 16 or 32Bit mode!\n");
|
|
|
|
return -1;
|
2016-08-16 21:07:26 +02:00
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
dev(tim)->CFG = timer_config[tim].cfg;
|
2020-03-19 15:39:29 +01:00
|
|
|
/* enable and configure GPTM(tim) timer A */
|
2018-08-03 09:43:45 +02:00
|
|
|
dev(tim)->TAMR = chan_mode;
|
2020-08-12 10:07:11 +02:00
|
|
|
dev(tim)->TAILR = (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) ?
|
|
|
|
LOAD_VALUE_32_BIT : LOAD_VALUE_16_BIT;
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->CTL |= GPTIMER_CTL_TAEN;
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
if (timer_config[tim].chn > 1) {
|
2020-03-19 15:39:29 +01:00
|
|
|
/* Enable and configure GPTM(tim) timer B */
|
2018-08-03 09:43:45 +02:00
|
|
|
dev(tim)->TBMR = chan_mode;
|
2020-08-12 10:07:11 +02:00
|
|
|
dev(tim)->TBILR = LOAD_VALUE_16_BIT;
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->CTL |= GPTIMER_CTL_TBEN;
|
2016-08-16 21:07:26 +02:00
|
|
|
}
|
2014-10-13 15:29:49 +02:00
|
|
|
|
|
|
|
/* Enable interrupts for given timer: */
|
2017-07-13 23:32:13 +02:00
|
|
|
_irq_enable(tim);
|
2014-10-13 15:29:49 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
2014-10-13 15:29:49 +02:00
|
|
|
{
|
2017-07-13 23:32:13 +02:00
|
|
|
DEBUG("%s(%u, %u, %u)\n", __FUNCTION__, tim, channel, value);
|
2016-08-16 21:07:26 +02:00
|
|
|
|
make: fix sign-compare errors
cpu, nrf5x_common: fix sign-compare in periph/flashpage
drivers, periph_common: fix sign-compare in flashpage
cpu, sam0_common: fix sign-compare error in periph/gpio
cpu, cc2538: fix sign-compare in periph/timer
cpu, sam3: fix sign-compare in periph/gpio
cpu, stm32_common: fix sign-compare in periph/pwm
cpu, stm32_common: fix sign-compare in periph/timer
cpu, stm32_common: fix sign-compare in periph/flashpage
cpu, nrf5x_common: fix sign-compare in radio/nrfmin
cpu, samd21: fix sign-compare in periph/pwm
cpu, ezr32wg: fix sign-compare in periph/gpio
cpu, ezr32wg: fix sign-compare in periph/timer
drivers, ethos: fix sign-compare
sys, net: fix sign-compare
cpu, atmega_common: fix sign-compare error
cpu, msp430fxyz: fix sign-compare in periph/gpio
boards, msb-430-common: fix sign-compare in board_init
driver, cc2420: fix sign-compared
sys/net: fix sign-compare in gnrc_tftp
driver, pcd8544: fix sign-compare
driver, pn532: fix sign-compare
driver, sdcard_spi: fix sign-compare
tests: fix sign_compare
sys/net, lwmac: fix sign_compare
pkg, lwip: fix sign-compare
boards, waspmote: make CORECLOCK unsigned long to fix sign_compare error
tests, sock_ip: fix sign compare
tests, msg_avail: fix sign compare
tests, sock_udp: fix sign compare
boards: fix sign-compare for calliope and microbit matrix
2017-10-31 11:57:40 +01:00
|
|
|
if ((tim >= TIMER_NUMOF) || (channel >= (int)timer_config[tim].chn) ) {
|
2016-02-22 20:20:14 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2020-03-18 17:57:13 +01:00
|
|
|
|
2020-03-19 15:39:29 +01:00
|
|
|
/* GPT timer needs to be gated to write to registers, no need to
|
|
|
|
check all xCGCGPT since they are set and unset at the same time */
|
2020-03-18 17:57:13 +01:00
|
|
|
bool timer_on = (SYS_CTRL->RCGCGPT & (1UL << tim));
|
|
|
|
/* if timer is stopped then set the desired timer compare values (TxMARCHR)
|
|
|
|
the next time the timer is started */
|
|
|
|
if (!timer_on) {
|
|
|
|
_set_absolute_disabled(tim, channel, value);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
/* clear any pending match interrupts */
|
|
|
|
dev(tim)->ICR = chn_isr_cfg[channel].flag;
|
|
|
|
if (channel == 0) {
|
|
|
|
dev(tim)->TAMATCHR = (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) ?
|
2020-08-12 10:07:11 +02:00
|
|
|
value : (LOAD_VALUE_16_BIT - value);
|
2016-08-16 21:07:26 +02:00
|
|
|
}
|
2017-07-13 23:32:13 +02:00
|
|
|
else {
|
2020-08-12 10:07:11 +02:00
|
|
|
dev(tim)->TBMATCHR = (LOAD_VALUE_16_BIT - value);
|
2017-07-13 23:32:13 +02:00
|
|
|
}
|
2018-08-03 09:43:45 +02:00
|
|
|
dev(tim)->IMR |= chn_isr_cfg[channel].flag;
|
2016-02-22 20:20:14 +01:00
|
|
|
|
2019-09-11 13:44:46 +02:00
|
|
|
return 0;
|
2016-02-22 20:20:14 +01:00
|
|
|
}
|
|
|
|
|
2020-03-18 17:57:13 +01:00
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
int timer_clear(tim_t tim, int channel)
|
2016-02-22 20:20:14 +01:00
|
|
|
{
|
2017-07-13 23:32:13 +02:00
|
|
|
DEBUG("%s(%u, %u)\n", __FUNCTION__, tim, channel);
|
2016-02-22 20:20:14 +01:00
|
|
|
|
2020-03-19 15:39:29 +01:00
|
|
|
if ((tim >= TIMER_NUMOF) || (channel >= (int)timer_config[tim].chn)) {
|
2016-02-22 20:20:14 +01:00
|
|
|
return -1;
|
|
|
|
}
|
2019-09-14 15:47:10 +02:00
|
|
|
/* clear interrupt flags */
|
2018-08-03 09:43:45 +02:00
|
|
|
dev(tim)->IMR &= ~(chn_isr_cfg[channel].flag);
|
2016-02-22 20:20:14 +01:00
|
|
|
|
2019-09-11 13:44:46 +02:00
|
|
|
return 0;
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The timer channels 1 and 2 are configured to run with the same speed and
|
|
|
|
* have the same value (they run in parallel), so only on of them is returned.
|
|
|
|
*/
|
2017-07-13 23:32:13 +02:00
|
|
|
unsigned int timer_read(tim_t tim)
|
2014-10-13 15:29:49 +02:00
|
|
|
{
|
2017-07-13 23:32:13 +02:00
|
|
|
DEBUG("%s(%u)\n", __FUNCTION__, tim);
|
|
|
|
|
|
|
|
if (tim >= TIMER_NUMOF) {
|
2016-08-16 21:07:26 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
if (timer_config[tim].cfg == GPTMCFG_32_BIT_TIMER) {
|
|
|
|
return dev(tim)->TAV;
|
2016-08-16 21:07:26 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-08-12 10:07:11 +02:00
|
|
|
return LOAD_VALUE_16_BIT - (dev(tim)->TAV & 0xffff);
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For stopping the counting of all channels.
|
|
|
|
*/
|
2017-07-13 23:32:13 +02:00
|
|
|
void timer_stop(tim_t tim)
|
2014-10-13 15:29:49 +02:00
|
|
|
{
|
2017-07-13 23:32:13 +02:00
|
|
|
DEBUG("%s(%u)\n", __FUNCTION__, tim);
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2020-03-18 17:50:15 +01:00
|
|
|
_timer_clock_disable(tim);
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
if (tim < TIMER_NUMOF) {
|
2020-03-18 17:50:15 +01:00
|
|
|
if (timer_config[tim].chn == 1) {
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->CTL &= ~GPTIMER_CTL_TAEN;
|
2020-03-18 17:50:15 +01:00
|
|
|
}
|
|
|
|
else if (timer_config[tim].chn == 2) {
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->CTL &= ~(GPTIMER_CTL_TBEN | GPTIMER_CTL_TAEN);
|
2020-03-18 17:50:15 +01:00
|
|
|
}
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
2020-03-18 17:50:15 +01:00
|
|
|
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
void timer_start(tim_t tim)
|
2014-10-13 15:29:49 +02:00
|
|
|
{
|
2017-07-13 23:32:13 +02:00
|
|
|
DEBUG("%s(%u)\n", __FUNCTION__, tim);
|
2016-08-16 21:07:26 +02:00
|
|
|
|
2020-03-18 17:50:15 +01:00
|
|
|
_timer_clock_enable(tim);
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
if (tim < TIMER_NUMOF) {
|
|
|
|
if (timer_config[tim].chn == 1) {
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->CTL |= GPTIMER_CTL_TAEN;
|
2016-08-16 21:07:26 +02:00
|
|
|
}
|
2017-07-13 23:32:13 +02:00
|
|
|
else if (timer_config[tim].chn == 2) {
|
2020-03-19 15:39:29 +01:00
|
|
|
dev(tim)->CTL |= GPTIMER_CTL_TBEN | GPTIMER_CTL_TAEN;
|
2016-08-16 21:07:26 +02:00
|
|
|
}
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-13 23:32:13 +02:00
|
|
|
/**
|
|
|
|
* @brief timer interrupt handler
|
|
|
|
*
|
|
|
|
* @param[in] num GPT instance number
|
|
|
|
* @param[in] chn channel number (0=A, 1=B)
|
|
|
|
*/
|
|
|
|
static void irq_handler(tim_t tim, int channel)
|
|
|
|
{
|
2020-03-19 15:39:29 +01:00
|
|
|
DEBUG("%s(%u,%d)\n", __FUNCTION__, tim, channel);
|
|
|
|
assert(tim < TIMER_NUMOF);
|
|
|
|
assert(channel < (int)timer_config[tim].chn);
|
|
|
|
|
|
|
|
uint32_t mis;
|
|
|
|
/* Latch the active interrupt flags */
|
|
|
|
mis = dev(tim)->MIS & chn_isr_cfg[channel].mask;
|
|
|
|
/* Clear the latched interrupt flags */
|
|
|
|
dev(tim)->ICR = mis;
|
|
|
|
|
|
|
|
if (mis & chn_isr_cfg[channel].flag) {
|
|
|
|
/* Disable further match interrupts for this timer/channel */
|
|
|
|
dev(tim)->IMR &= ~chn_isr_cfg[channel].flag;
|
|
|
|
/* Invoke the callback function */
|
|
|
|
isr_ctx[tim].cb(isr_ctx[tim].arg, channel);
|
|
|
|
}
|
2014-10-13 15:29:49 +02:00
|
|
|
|
2016-11-30 18:26:05 +01:00
|
|
|
cortexm_isr_end();
|
2014-10-13 15:29:49 +02:00
|
|
|
}
|
|
|
|
|
2020-03-19 15:39:29 +01:00
|
|
|
void isr_timer0_chan0(void)
|
|
|
|
{
|
|
|
|
irq_handler(0, 0);
|
|
|
|
}
|
|
|
|
void isr_timer0_chan1(void)
|
|
|
|
{
|
|
|
|
irq_handler(0, 1);
|
|
|
|
}
|
|
|
|
void isr_timer1_chan0(void)
|
|
|
|
{
|
|
|
|
irq_handler(1, 0);
|
|
|
|
}
|
|
|
|
void isr_timer1_chan1(void)
|
|
|
|
{
|
|
|
|
irq_handler(1, 1);
|
|
|
|
}
|
|
|
|
void isr_timer2_chan0(void)
|
|
|
|
{
|
|
|
|
irq_handler(2, 0);
|
|
|
|
}
|
|
|
|
void isr_timer2_chan1(void)
|
|
|
|
{
|
|
|
|
irq_handler(2, 1);
|
|
|
|
}
|
|
|
|
void isr_timer3_chan0(void)
|
|
|
|
{
|
|
|
|
irq_handler(3, 0);
|
|
|
|
}
|
|
|
|
void isr_timer3_chan1(void)
|
|
|
|
{
|
|
|
|
irq_handler(3, 1);
|
|
|
|
}
|