1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

Merge pull request #4839 from haukepetersen/opt_nrf_timer

cpu/nrf5x: unified and reworked timer driver
This commit is contained in:
Peter Kietzmann 2016-03-03 09:10:53 +01:00
commit 3f99028b19
11 changed files with 251 additions and 864 deletions

View File

@ -20,6 +20,8 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -41,35 +43,14 @@
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
#define TIMER_1_EN 0
#define TIMER_2_EN 0
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_24Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_24Bit /* only possible value for TIMER0 */
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
/* Timer 1 configuration */
#define TIMER_1_DEV NRF_TIMER1
#define TIMER_1_CHANNELS 3
#define TIMER_1_MAX_VALUE (0xffff)
#define TIMER_1_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_1_ISR isr_timer1
#define TIMER_1_IRQ TIMER1_IRQn
/* Timer 2 configuration */
#define TIMER_2_DEV NRF_TIMER2
#define TIMER_2_CHANNELS 3
#define TIMER_2_MAX_VALUE (0xffff)
#define TIMER_2_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_2_ISR isr_timer2
#define TIMER_2_IRQ TIMER2_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -19,6 +19,8 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -40,35 +42,14 @@ extern "C" {
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
#define TIMER_1_EN 0
#define TIMER_2_EN 0
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_24Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_24Bit
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
/* Timer 1 configuration */
#define TIMER_1_DEV NRF_TIMER1
#define TIMER_1_CHANNELS 3
#define TIMER_1_MAX_VALUE (0xffff)
#define TIMER_1_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_1_ISR isr_timer1
#define TIMER_1_IRQ TIMER1_IRQn
/* Timer 2 configuration */
#define TIMER_2_DEV NRF_TIMER2
#define TIMER_2_CHANNELS 3
#define TIMER_2_MAX_VALUE (0xffff)
#define TIMER_2_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_2_ISR isr_timer2
#define TIMER_2_IRQ TIMER2_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -20,6 +20,8 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -40,16 +42,14 @@ extern "C" {
* @brief Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width, IRQn */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_32Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_32Bit
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -22,6 +22,8 @@
#ifndef PERIPH_CONF_H
#define PERIPH_CONF_H
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -43,35 +45,14 @@ extern "C" {
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
#define TIMER_1_EN 0
#define TIMER_2_EN 0
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_24Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_24Bit
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
/* Timer 1 configuration */
#define TIMER_1_DEV NRF_TIMER1
#define TIMER_1_CHANNELS 3
#define TIMER_1_MAX_VALUE (0xffff)
#define TIMER_1_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_1_ISR isr_timer1
#define TIMER_1_IRQ TIMER1_IRQn
/* Timer 2 configuration */
#define TIMER_2_DEV NRF_TIMER2
#define TIMER_2_CHANNELS 3
#define TIMER_2_MAX_VALUE (0xffff)
#define TIMER_2_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_2_ISR isr_timer2
#define TIMER_2_IRQ TIMER2_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -21,6 +21,8 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -42,35 +44,14 @@ extern "C" {
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
#define TIMER_1_EN 0
#define TIMER_2_EN 0
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_24Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_24Bit
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
/* Timer 1 configuration */
#define TIMER_1_DEV NRF_TIMER1
#define TIMER_1_CHANNELS 3
#define TIMER_1_MAX_VALUE (0xffff)
#define TIMER_1_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_1_ISR isr_timer1
#define TIMER_1_IRQ TIMER1_IRQn
/* Timer 2 configuration */
#define TIMER_2_DEV NRF_TIMER2
#define TIMER_2_CHANNELS 3
#define TIMER_2_MAX_VALUE (0xffff)
#define TIMER_2_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_2_ISR isr_timer2
#define TIMER_2_IRQ TIMER2_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -21,6 +21,8 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -42,35 +44,14 @@ extern "C" {
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
#define TIMER_1_EN 0
#define TIMER_2_EN 0
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_24Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_24Bit
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
/* Timer 1 configuration */
#define TIMER_1_DEV NRF_TIMER1
#define TIMER_1_CHANNELS 3
#define TIMER_1_MAX_VALUE (0xffff)
#define TIMER_1_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_1_ISR isr_timer1
#define TIMER_1_IRQ TIMER1_IRQn
/* Timer 2 configuration */
#define TIMER_2_DEV NRF_TIMER2
#define TIMER_2_CHANNELS 3
#define TIMER_2_MAX_VALUE (0xffff)
#define TIMER_2_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_2_ISR isr_timer2
#define TIMER_2_IRQ TIMER2_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -19,6 +19,8 @@
#ifndef PERIPH_CONF_H_
#define PERIPH_CONF_H_
#include "periph_cpu.h"
#ifdef __cplusplus
extern "C" {
#endif
@ -40,35 +42,14 @@ extern "C" {
* @name Timer configuration
* @{
*/
#define TIMER_NUMOF (1U)
#define TIMER_0_EN 1
#define TIMER_1_EN 0
#define TIMER_2_EN 0
#define TIMER_IRQ_PRIO 1
static const timer_conf_t timer_config[] = {
/* dev, channels, width */
{ NRF_TIMER0, 3, TIMER_BITMODE_BITMODE_24Bit, TIMER0_IRQn }
};
/* Timer 0 configuration */
#define TIMER_0_DEV NRF_TIMER0
#define TIMER_0_CHANNELS 3
#define TIMER_0_MAX_VALUE (0xffffff)
#define TIMER_0_BITMODE TIMER_BITMODE_BITMODE_24Bit /* only possible value for TIMER0 */
#define TIMER_0_ISR isr_timer0
#define TIMER_0_IRQ TIMER0_IRQn
/* Timer 1 configuration */
#define TIMER_1_DEV NRF_TIMER1
#define TIMER_1_CHANNELS 3
#define TIMER_1_MAX_VALUE (0xffff)
#define TIMER_1_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_1_ISR isr_timer1
#define TIMER_1_IRQ TIMER1_IRQn
/* Timer 2 configuration */
#define TIMER_2_DEV NRF_TIMER2
#define TIMER_2_CHANNELS 3
#define TIMER_2_MAX_VALUE (0xffff)
#define TIMER_2_BITMODE TIMER_BITMODE_BITMODE_16Bit
#define TIMER_2_ISR isr_timer2
#define TIMER_2_IRQ TIMER2_IRQn
#define TIMER_NUMOF (sizeof(timer_config) / sizeof(timer_config[0]))
/** @} */
/**

View File

@ -1,336 +0,0 @@
/*
* Copyright (C) 2014 Freie Universität Berlin
*
* 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.
*/
/**
* @ingroup cpu_nrf51822
* @{
*
* @file
* @brief Low-level timer driver implementation
*
* @author Christian Kühling <kuehling@zedat.fu-berlin.de>
* @author Timo Ziegler <timo.ziegler@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
*
* @}
*/
#include "cpu.h"
#include "board.h"
#include "sched.h"
#include "thread.h"
#include "periph_conf.h"
#include "periph/timer.h"
/**
* @name Flags to mark active channels
* @{
*/
#define TIMER_CH0 0x01
#define TIMER_CH1 0x02
#define TIMER_CH2 0x04
/** @} */
/**
* @brief struct for keeping track of a timer's state
*/
typedef struct {
timer_cb_t cb;
void *arg;
uint8_t flags;
} timer_conf_t;
/**
* @brief timer state memory
*/
static timer_conf_t timer_config[TIMER_NUMOF];
/**
* @brief static timer mapping
*/
static NRF_TIMER_Type *const timer[] = {
#if TIMER_0_EN
TIMER_0_DEV,
#endif
#if TIMER_1_EN
TIMER_1_DEV,
#endif
#if TIMER_2_EN
TIMER_2_DEV
#endif
};
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
{
if (dev >= TIMER_NUMOF) {
return -1;
}
/* save callback */
timer_config[dev].cb = cb;
timer_config[dev].arg = arg;
/* power on timer */
timer[dev]->POWER = 1;
switch (dev) {
#if TIMER_0_EN
case TIMER_0:
TIMER_0_DEV->BITMODE = TIMER_0_BITMODE;
NVIC_SetPriority(TIMER_0_IRQ, TIMER_IRQ_PRIO);
NVIC_EnableIRQ(TIMER_0_IRQ);
break;
#endif
#if TIMER_1_EN
case TIMER_1:
TIMER_1_DEV->BITMODE = TIMER_1_BITMODE;
NVIC_SetPriority(TIMER_1_IRQ, TIMER_IRQ_PRIO);
NVIC_EnableIRQ(TIMER_1_IRQ);
break;
#endif
#if TIMER_2_EN
case TIMER_2:
TIMER_2_DEV->BITMODE = TIMER_2_BITMODE;
NVIC_SetPriority(TIMER_2_IRQ, TIMER_IRQ_PRIO);
NVIC_EnableIRQ(TIMER_2_IRQ);
break;
#endif
case TIMER_UNDEFINED:
return -1;
}
timer[dev]->TASKS_STOP = 1;
timer[dev]->MODE = TIMER_MODE_MODE_Timer; /* set the timer in Timer Mode. */
timer[dev]->TASKS_CLEAR = 1; /* clear the task first to be usable for later. */
switch (freq) {
case 125000ul:
timer[dev]->PRESCALER = 7;
break;
case 250000ul:
timer[dev]->PRESCALER = 6;
break;
case 500000ul:
timer[dev]->PRESCALER = 5;
break;
case 1000000ul:
timer[dev]->PRESCALER = 4;
break;
case 2000000ul:
timer[dev]->PRESCALER = 3;
break;
case 4000000ul:
timer[dev]->PRESCALER = 2;
break;
case 8000000ul:
timer[dev]->PRESCALER = 1;
break;
case 16000000ul:
timer[dev]->PRESCALER = 0;
break;
default:
return -1;
}
/* reset compare state */
timer[dev]->EVENTS_COMPARE[0] = 0;
timer[dev]->EVENTS_COMPARE[1] = 0;
timer[dev]->EVENTS_COMPARE[2] = 0;
/* start the timer */
timer[dev]->TASKS_START = 1;
return 0;
}
int timer_set(tim_t dev, int channel, unsigned int timeout)
{
uint32_t now = timer_read(dev);
return timer_set_absolute(dev, channel, (now + timeout - 1));
}
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
{
if (dev >= TIMER_NUMOF) {
return -1;
}
switch (channel) {
case 0:
timer[dev]->CC[0] = value;
timer_config[dev].flags |= TIMER_CH0;
timer[dev]->INTENSET |= TIMER_INTENSET_COMPARE0_Msk;
break;
case 1:
timer[dev]->CC[1] = value;
timer_config[dev].flags |= TIMER_CH1;
timer[dev]->INTENSET |= TIMER_INTENSET_COMPARE1_Msk;
break;
case 2:
timer[dev]->CC[2] = value;
timer_config[dev].flags |= TIMER_CH2;
timer[dev]->INTENSET |= TIMER_INTENSET_COMPARE2_Msk;
break;
default:
return -2;
}
return 1;
}
int timer_clear(tim_t dev, int channel)
{
if (dev >= TIMER_NUMOF) {
return -1;
}
/* set timeout value */
switch (channel) {
case 0:
timer_config[dev].flags &= ~TIMER_CH0;
timer[dev]->INTENCLR = TIMER_INTENCLR_COMPARE0_Msk;
break;
case 1:
timer_config[dev].flags &= ~TIMER_CH1;
timer[dev]->INTENCLR = TIMER_INTENCLR_COMPARE1_Msk;
break;
case 2:
timer_config[dev].flags &= ~TIMER_CH2;
timer[dev]->INTENCLR = TIMER_INTENCLR_COMPARE2_Msk;
break;
default:
return -2;
}
return 1;
}
unsigned int timer_read(tim_t dev)
{
if (dev >= TIMER_NUMOF) {
return 0;
}
timer[dev]->TASKS_CAPTURE[3] = 1;
return timer[dev]->CC[3];
}
void timer_start(tim_t dev)
{
if (dev < TIMER_NUMOF) {
timer[dev]->TASKS_START = 1;
}
}
void timer_stop(tim_t dev)
{
if (dev < TIMER_NUMOF) {
timer[dev]->TASKS_STOP = 1;
}
}
void timer_irq_enable(tim_t dev)
{
switch (dev) {
#if TIMER_0_EN
case TIMER_0:
NVIC_EnableIRQ(TIMER_0_IRQ);
break;
#endif
#if TIMER_1_EN
case TIMER_1:
NVIC_EnableIRQ(TIMER_1_IRQ);
break;
#endif
#if TIMER_2_EN
case TIMER_2:
NVIC_EnableIRQ(TIMER_2_IRQ);
break;
#endif
case TIMER_UNDEFINED:
break;
}
}
void timer_irq_disable(tim_t dev)
{
switch (dev) {
#if TIMER_0_EN
case TIMER_0:
NVIC_DisableIRQ(TIMER_0_IRQ);
break;
#endif
#if TIMER_1_EN
case TIMER_1:
NVIC_DisableIRQ(TIMER_1_IRQ);
break;
#endif
#if TIMER_2_EN
case TIMER_2:
NVIC_DisableIRQ(TIMER_2_IRQ);
break;
#endif
case TIMER_UNDEFINED:
break;
}
}
#if TIMER_0_EN
void TIMER_0_ISR(void)
{
for(int i = 0; i < TIMER_0_CHANNELS; i++){
if(TIMER_0_DEV->EVENTS_COMPARE[i] == 1){
TIMER_0_DEV->EVENTS_COMPARE[i] = 0;
if (timer_config[TIMER_0].flags & (1 << i)) {
timer_config[TIMER_0].flags &= ~(1 << i);
TIMER_0_DEV->INTENCLR = (1 << (16 + i));
timer_config[TIMER_0].cb(timer_config[TIMER_0].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#endif
#if TIMER_1_EN
void TIMER_1_ISR(void)
{
for(int i = 0; i < TIMER_1_CHANNELS; i++){
if(TIMER_1_DEV->EVENTS_COMPARE[i] == 1){
TIMER_1_DEV->EVENTS_COMPARE[i] = 0;
if (timer_config[TIMER_1].flags & (1 << i)) {
timer_config[TIMER_1].flags &= ~(1 << i);
TIMER_1_DEV->INTENCLR = (1 << (16 + i));
timer_config[TIMER_1].cb(timer_config[TIMER_1].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#endif
#if TIMER_2_EN
void TIMER_2_ISR(void)
{
for(int i = 0; i < TIMER_2_CHANNELS; i++){
if(TIMER_2_DEV->EVENTS_COMPARE[i] == 1){
TIMER_2_DEV->EVENTS_COMPARE[i] = 0;
if (timer_config[TIMER_2].flags & (1 << i)) {
timer_config[TIMER_2].flags &= ~(1 << i);
TIMER_2_DEV->INTENCLR = (1 << (16 + i));
timer_config[TIMER_2].cb(timer_config[TIMER_2].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#endif

View File

@ -1,364 +0,0 @@
/*
* Copyright (C) 2015 Jan Wagner <mail@jwagner.eu>
* 2016 Freie Universität Berlin
*
* 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.
*/
/**
* @ingroup cpu_nrf52
* @{
*
* @file
* @brief Implementation of the peripheral timer interface
*
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Jan Wagner <mail@jwagner.eu>
*
* @}
*/
#include "cpu.h"
#include "board.h"
#include "sched.h"
#include "thread.h"
#include "periph_conf.h"
#include "periph/timer.h"
/**
* @name Flags to mark active channels
* @{
*/
#define TIMER_CH0 0x01
#define TIMER_CH1 0x02
#define TIMER_CH2 0x04
/** @} */
/**
* @brief struct for keeping track of a timer's state
*/
typedef struct {
timer_cb_t cb;
void *arg;
uint8_t flags;
} timer_conf_t;
/**
* @brief timer state memory
*/
static timer_conf_t timer_config[TIMER_NUMOF];
/**
* @brief static timer mapping
*/
static NRF_TIMER_Type *const timer[] = {
#if TIMER_0_EN
TIMER_0_DEV,
#endif
#if TIMER_1_EN
TIMER_1_DEV,
#endif
#if TIMER_2_EN
TIMER_2_DEV
#endif
};
int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
{
if (dev >= TIMER_NUMOF) {
return -1;
}
/* save callback */
timer_config[dev].cb = cb;
timer_config[dev].arg = arg;
/* power on timer */
/* timer[dev]->POWER = 1; */
switch (dev) {
#if TIMER_0_EN
case TIMER_0:
TIMER_0_DEV->BITMODE = TIMER_0_BITMODE;
NVIC_EnableIRQ(TIMER_0_IRQ);
break;
#endif
#if TIMER_1_EN
case TIMER_1:
TIMER_1_DEV->BITMODE = TIEMR_1_BITMODE;
NVIC_EnableIRQ(TIMER_1_IRQ);
break;
#endif
#if TIMER_2_EN
case TIMER_2:
TIMER_2_DEV->BITMODE = TIMER_2_BITMODE;
NVIC_EnableIRQ(TIMER_2_IRQ);
break;
#endif
case TIMER_UNDEFINED:
return -1;
}
timer[dev]->TASKS_STOP = 1;
timer[dev]->MODE = TIMER_MODE_MODE_Timer; /* set the timer in Timer Mode. */
timer[dev]->TASKS_CLEAR = 1; /* clear the task first to be usable for later. */
switch (freq) {
case 125000ul:
timer[dev]->PRESCALER = 7;
break;
case 250000ul:
timer[dev]->PRESCALER = 6;
break;
case 500000ul:
timer[dev]->PRESCALER = 5;
break;
case 1000000ul:
timer[dev]->PRESCALER = 4;
break;
case 2000000ul:
timer[dev]->PRESCALER = 3;
break;
case 4000000ul:
timer[dev]->PRESCALER = 2;
break;
case 8000000ul:
timer[dev]->PRESCALER = 1;
break;
case 16000000ul:
timer[dev]->PRESCALER = 0;
break;
default:
return -1;
}
/* reset compare state */
timer[dev]->EVENTS_COMPARE[0] = 0;
timer[dev]->EVENTS_COMPARE[1] = 0;
timer[dev]->EVENTS_COMPARE[2] = 0;
/* start the timer */
timer[dev]->TASKS_START = 1;
return 0;
}
int timer_set(tim_t dev, int channel, unsigned int timeout)
{
uint32_t now = timer_read(dev);
return timer_set_absolute(dev, channel, (now + timeout - 1));
}
int timer_set_absolute(tim_t dev, int channel, unsigned int value)
{
if (dev >= TIMER_NUMOF) {
return -1;
}
switch (channel) {
case 0:
timer[dev]->CC[0] = value;
timer_config[dev].flags |= TIMER_CH0;
timer[dev]->INTENSET |= TIMER_INTENSET_COMPARE0_Msk;
break;
case 1:
timer[dev]->CC[1] = value;
timer_config[dev].flags |= TIMER_CH1;
timer[dev]->INTENSET |= TIMER_INTENSET_COMPARE1_Msk;
break;
case 2:
timer[dev]->CC[2] = value;
timer_config[dev].flags |= TIMER_CH2;
timer[dev]->INTENSET |= TIMER_INTENSET_COMPARE2_Msk;
break;
default:
return -2;
}
return 1;
}
int timer_clear(tim_t dev, int channel)
{
if (dev >= TIMER_NUMOF) {
return -1;
}
/* set timeout value */
switch (channel) {
case 0:
timer_config[dev].flags &= ~TIMER_CH0;
timer[dev]->INTENCLR = TIMER_INTENCLR_COMPARE0_Msk;
break;
case 1:
timer_config[dev].flags &= ~TIMER_CH1;
timer[dev]->INTENCLR = TIMER_INTENCLR_COMPARE1_Msk;
break;
case 2:
timer_config[dev].flags &= ~TIMER_CH2;
timer[dev]->INTENCLR = TIMER_INTENCLR_COMPARE2_Msk;
break;
default:
return -2;
}
return 1;
}
unsigned int timer_read(tim_t dev)
{
if (dev >= TIMER_NUMOF) {
return 0;
}
timer[dev]->TASKS_CAPTURE[3] = 1;
return timer[dev]->CC[3];
}
void timer_start(tim_t dev)
{
if (dev < TIMER_NUMOF) {
timer[dev]->TASKS_START = 1;
}
}
void timer_stop(tim_t dev)
{
if (dev < TIMER_NUMOF) {
timer[dev]->TASKS_STOP = 1;
}
}
void timer_irq_enable(tim_t dev)
{
switch (dev) {
#if TIMER_0_EN
case TIMER_0:
NVIC_EnableIRQ(TIMER_0_IRQ);
break;
#endif
#if TIMER_1_EN
case TIMER_1:
NVIC_EnableIRQ(TIMER_1_IRQ);
break;
#endif
#if TIMER_2_EN
case TIMER_2:
NVIC_EnableIRQ(TIMER_2_IRQ);
break;
#endif
case TIMER_UNDEFINED:
break;
}
}
void timer_irq_disable(tim_t dev)
{
switch (dev) {
#if TIMER_0_EN
case TIMER_0:
NVIC_DisableIRQ(TIMER_0_IRQ);
break;
#endif
#if TIMER_1_EN
case TIMER_1:
NVIC_DisableIRQ(TIMER_1_IRQ);
break;
#endif
#if TIMER_2_EN
case TIMER_2:
NVIC_DisableIRQ(TIMER_2_IRQ);
break;
#endif
case TIMER_UNDEFINED:
break;
}
}
void timer_reset(tim_t dev)
{
if (dev < TIMER_NUMOF) {
timer[dev]->TASKS_CLEAR = 1;
}
}
#if TIMER_0_EN
void TIMER_0_ISR(void)
{
for (int i = 0; i < TIMER_0_CHANNELS; i++) {
if (TIMER_0_DEV->EVENTS_COMPARE[i] == 1) {
TIMER_0_DEV->EVENTS_COMPARE[i] = 0;
if (timer_config[TIMER_0].flags & (1 << i)) {
timer_config[TIMER_0].flags &= ~(1 << i);
TIMER_0_DEV->INTENCLR = (1 << (16 + i));
timer_config[TIMER_0].cb(timer_config[TIMER_0].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#endif
#if TIMER_1_EN
void TIMER_1_ISR(void)
{
for (int i = 0; i < TIMER_1_CHANNELS; i++) {
if (TIMER_1_DEV->EVENTS_COMPARE[i] == 1) {
TIMER_1_DEV->EVENTS_COMPARE[i] = 0;
if (timer_config[TIMER_1].flags & (1 << i)) {
timer_config[TIMER_1].flags &= ~(1 << i);
TIMER_1_DEV->INTENCLR = (1 << (16 + i));
timer_config[TIMER_1].cb(timer_config[TIMER_1].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#endif
#if TIMER_2_EN
void TIMER_2_ISR(void)
{
for (int i = 0; i < TIMER_2_CHANNELS; i++) {
if (TIMER_2_DEV->EVENTS_COMPARE[i] == 1) {
TIMER_2_DEV->EVENTS_COMPARE[i] = 0;
if (timer_config[TIMER_2].flags & (1 << i)) {
timer_config[TIMER_2].flags &= ~(1 << i);
TIMER_2_DEV->INTENCLR = (1 << (16 + i));
timer_config[TIMER_2].cb(timer_config[TIMER_2].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#endif

View File

@ -77,6 +77,16 @@ typedef enum {
} gpio_flank_t;
/** @} */
/**
* @brief Timer configuration options
*/
typedef struct {
NRF_TIMER_Type *dev;
uint8_t channels;
uint8_t bitmode;
uint8_t irqn;
} timer_conf_t;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,191 @@
/*
* Copyright (C) 2014-2016 Freie Universität Berlin
* 2015 Jan Wagner <mail@jwagner.eu>
*
* 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.
*/
/**
* @ingroup cpu_nrf5x_common
* @{
*
* @file
* @brief Implementation of the peripheral timer interface
*
* @author Christian Kühling <kuehling@zedat.fu-berlin.de>
* @author Timo Ziegler <timo.ziegler@fu-berlin.de>
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
* @author Jan Wagner <mail@jwagner.eu>
*
* @}
*/
#include "sched.h"
#include "thread.h"
#include "periph/timer.h"
#define F_TIMER (16000000U) /* the timer is clocked at 16MHz */
typedef struct {
timer_cb_t cb;
void *arg;
uint8_t flags;
} tim_ctx_t;
/**
* @brief timer state memory
*/
static tim_ctx_t ctx[TIMER_NUMOF];
static inline NRF_TIMER_Type *dev(tim_t tim)
{
return timer_config[tim].dev;
}
int timer_init(tim_t tim, unsigned long freq, timer_cb_t cb, void *arg)
{
/* make sure the given timer is valid */
if (tim >= TIMER_NUMOF) {
return -1;
}
/* save interrupt context */
ctx[tim].cb = cb;
ctx[tim].arg = arg;
/* power on timer */
#if CPU_FAM_NRF51
dev(tim)->POWER = 1;
#endif
/* reset and configure the timer */
dev(tim)->TASKS_STOP = 1;
dev(tim)->BITMODE = timer_config[tim].bitmode;
dev(tim)->MODE = TIMER_MODE_MODE_Timer;
dev(tim)->TASKS_CLEAR = 1;
/* figure out if desired frequency is available */
int i;
unsigned long cando = F_TIMER;
for (i = 0; i < 10; i++) {
if (freq == cando) {
dev(tim)->PRESCALER = i;
break;
}
cando /= 2;
}
if (i == 10) {
return -1;
}
/* reset compare state */
dev(tim)->EVENTS_COMPARE[0] = 0;
dev(tim)->EVENTS_COMPARE[1] = 0;
dev(tim)->EVENTS_COMPARE[2] = 0;
/* enable interrupts */
timer_irq_enable(tim);
/* start the timer */
dev(tim)->TASKS_START = 1;
return 0;
}
int timer_set(tim_t tim, int chan, unsigned int value)
{
uint32_t now = timer_read(tim);
return timer_set_absolute(tim, chan, (now + value));
}
int timer_set_absolute(tim_t tim, int chan, unsigned int value)
{
/* see if channel is valid */
if (chan >= timer_config[tim].channels) {
return -1;
}
ctx[tim].flags |= (1 << chan);
dev(tim)->CC[chan] = value;
dev(tim)->INTENSET = (TIMER_INTENSET_COMPARE0_Msk << chan);
return 1;
}
int timer_clear(tim_t tim, int chan)
{
/* see if channel is valid */
if (chan >= timer_config[tim].channels) {
return -1;
}
dev(tim)->INTENCLR = (TIMER_INTENSET_COMPARE0_Msk << chan);
ctx[tim].flags &= ~(1 << chan);
return 1;
}
unsigned int timer_read(tim_t tim)
{
dev(tim)->TASKS_CAPTURE[timer_config[tim].channels] = 1;
return dev(tim)->CC[timer_config[tim].channels];
}
void timer_start(tim_t tim)
{
dev(tim)->TASKS_START = 1;
}
void timer_stop(tim_t tim)
{
dev(tim)->TASKS_STOP = 1;
}
void timer_irq_enable(tim_t tim)
{
NVIC_EnableIRQ(timer_config[tim].irqn);
}
void timer_irq_disable(tim_t tim)
{
NVIC_DisableIRQ(timer_config[tim].irqn);
}
static inline void irq_handler(int num)
{
for (unsigned i = 0; i < timer_config[num].channels; i++) {
if (dev(num)->EVENTS_COMPARE[i] == 1) {
dev(num)->EVENTS_COMPARE[i] = 0;
if (ctx[num].flags & (1 << i)) {
ctx[num].flags &= ~(1 << i);
dev(num)->INTENCLR = (TIMER_INTENSET_COMPARE0_Msk << i);
ctx[num].cb(ctx[num].arg, i);
}
}
}
if (sched_context_switch_request) {
thread_yield();
}
}
#ifdef TIMER_0_ISR
void TIMER_0_ISR(void)
{
irq_handler(0);
}
#endif
#ifdef TIMER_1_ISR
void TIMER_1_ISR(void)
{
irq_handler(1);
}
#endif
#ifdef TIMER_2_ISR
void TIMER_2_ISR(void)
{
irq_handler(2);
}
#endif