Merge pull request #3779 from haukepetersen/add_lpc2387_timer
cpu/lpc2387: added periph timer implementationdev/timer
commit
ea4fb69f9d
@ -1,4 +1,5 @@
|
||||
FEATURES_PROVIDED += periph_gpio
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
FEATURES_MCU_GROUP = arm7
|
||||
|
@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 INRIA
|
||||
*
|
||||
* 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 msba2
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief msba2 benchmark functions
|
||||
*
|
||||
* @author Heiko Will <heiko.will@fu-berlin.de>
|
||||
* @author Zakaria Kasmi <zkasmi@inf.fu-berlin.de>
|
||||
* @author Kaspar Schleiser <kaspar@schleiser.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "lpc2387.h"
|
||||
|
||||
void benchmark_init(void)
|
||||
{
|
||||
PCLKSEL1 = (PCLKSEL1 & ~(BIT14|BIT15)) | (1 << 14); // CCLK to PCLK divider
|
||||
PCONP |= PCTIM3;
|
||||
T3TCR = 0; // disable timer
|
||||
T3MCR = 0; // disable interrupt
|
||||
T3CCR = 0; // capture is disabled.
|
||||
T3EMR = 0; // no external match output.
|
||||
T3PR = 0; // set prescaler
|
||||
T3TC = 0; // reset counter
|
||||
}
|
||||
|
||||
void benchmark_reset_start(void)
|
||||
{
|
||||
T3TCR = 0; // disable timer
|
||||
T3TC = 0; // reset counter
|
||||
T3TCR = BIT0;
|
||||
}
|
||||
|
||||
unsigned int benchmark_read_stop(void)
|
||||
{
|
||||
T3TCR = 0; // disable timer
|
||||
return T3TC;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
FEATURES_PROVIDED += periph_gpio
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
FEATURES_MCU_GROUP = arm7
|
||||
|
@ -1,206 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 INRIA
|
||||
*
|
||||
* 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
|
||||
* @file
|
||||
* @internal
|
||||
* @brief ARM kernel timer CPU dependent functions implementation
|
||||
*
|
||||
* @author Thomas Hillebrandt <hillebra@inf.fu-berlin.de>
|
||||
* @author Heiko Will <hwill@inf.fu-berlin.de>
|
||||
* @author Oliver Hahm <oliver.hahm@inria.fr>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "cpu.h"
|
||||
#include "bitarithm.h"
|
||||
#include "hwtimer_cpu.h"
|
||||
#include "arch/hwtimer_arch.h"
|
||||
#include "irq.h"
|
||||
|
||||
#define VULP(x) ((volatile unsigned long*) (x))
|
||||
|
||||
/* High level interrupt handler */
|
||||
static void (*int_handler)(int);
|
||||
|
||||
/* Timer 0-3 interrupt handler */
|
||||
static void timer_irq(void) __attribute__((interrupt("IRQ")));
|
||||
|
||||
inline static unsigned long get_base_address(short timer)
|
||||
{
|
||||
return (volatile unsigned long)(TMR0_BASE_ADDR + (timer / 8) * 0x6C000 + (timer / 4 - (timer / 8) * 2) * 0x4000);
|
||||
}
|
||||
|
||||
static void timer_irq(void)
|
||||
{
|
||||
short timer = 0;
|
||||
|
||||
if (T0IR) {
|
||||
timer = 0;
|
||||
}
|
||||
else if (T1IR) {
|
||||
timer = 4;
|
||||
}
|
||||
else if (T2IR) {
|
||||
timer = 8;
|
||||
}
|
||||
|
||||
volatile unsigned long base = get_base_address(timer);
|
||||
|
||||
if (*VULP(base + TXIR) & BIT0) {
|
||||
*VULP(base + TXMCR) &= ~BIT0;
|
||||
*VULP(base + TXIR) = BIT0;
|
||||
int_handler(timer);
|
||||
}
|
||||
|
||||
if (*VULP(base + TXIR) & BIT1) {
|
||||
*VULP(base + TXMCR) &= ~BIT3;
|
||||
*VULP(base + TXIR) = BIT1;
|
||||
int_handler(timer + 1);
|
||||
}
|
||||
|
||||
if (*VULP(base + TXIR) & BIT2) {
|
||||
*VULP(base + TXMCR) &= ~BIT6;
|
||||
*VULP(base + TXIR) = BIT2;
|
||||
int_handler(timer + 2);
|
||||
}
|
||||
|
||||
if (*VULP(base + TXIR) & BIT3) {
|
||||
*VULP(base + TXMCR) &= ~BIT9;
|
||||
*VULP(base + TXIR) = BIT3;
|
||||
int_handler(timer + 3);
|
||||
}
|
||||
|
||||
VICVectAddr = 0; /* acknowledge interrupt (if using VIC IRQ) */
|
||||
}
|
||||
|
||||
static void timer0_init(uint32_t cpsr)
|
||||
{
|
||||
PCONP |= PCTIM0; /* power up timer */
|
||||
T0TCR = 2; /* disable and reset timer */
|
||||
T0MCR = 0; /* disable compare */
|
||||
T0CCR = 0; /* capture is disabled */
|
||||
T0EMR = 0; /* no external match output */
|
||||
T0PR = cpsr; /* set prescaler */
|
||||
install_irq(TIMER0_INT, &timer_irq, 1);
|
||||
T0TCR = 1; /* reset counter */
|
||||
}
|
||||
|
||||
static void timer1_init(uint32_t cpsr)
|
||||
{
|
||||
PCONP |= PCTIM1; /* power up timer */
|
||||
T1TCR = 2; /* disable and reset timer */
|
||||
T1MCR = 0; /* disable compare */
|
||||
T1CCR = 0; /* capture is disabled */
|
||||
T1EMR = 0; /* no external match output */
|
||||
T1PR = cpsr; /* set prescaler */
|
||||
install_irq(TIMER1_INT, &timer_irq, 1);
|
||||
T1TCR = 1; /* reset counter */
|
||||
}
|
||||
|
||||
static void timer2_init(uint32_t cpsr)
|
||||
{
|
||||
PCONP |= PCTIM2; /* power up timer */
|
||||
T2TCR = 2; /* disable and reset timer */
|
||||
T2MCR = 0; /* disable compare */
|
||||
T2CCR = 0; /* capture is disabled */
|
||||
T2EMR = 0; /* no external match output */
|
||||
T2PR = cpsr; /* set prescaler */
|
||||
install_irq(TIMER2_INT, &timer_irq, 1);
|
||||
T2TCR = 1; /* reset counter */
|
||||
}
|
||||
|
||||
void hwtimer_arch_init(void (*handler)(int), uint32_t fcpu)
|
||||
{
|
||||
uint32_t cpsr;
|
||||
int_handler = handler;
|
||||
cpu_clock_scale(fcpu, HWTIMER_SPEED, &cpsr);
|
||||
timer0_init(cpsr);
|
||||
timer1_init(cpsr);
|
||||
timer2_init(cpsr);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void hwtimer_arch_enable_interrupt(void)
|
||||
{
|
||||
VICIntEnable = 1 << TIMER0_INT; /* Enable Interrupt */
|
||||
VICIntEnable = 1 << TIMER1_INT; /* Enable Interrupt */
|
||||
VICIntEnable = 1 << TIMER2_INT; /* Enable Interrupt */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void hwtimer_arch_disable_interrupt(void)
|
||||
{
|
||||
VICIntEnClr = 1 << TIMER0_INT; /* Disable Interrupt */
|
||||
VICIntEnClr = 1 << TIMER1_INT; /* Disable Interrupt */
|
||||
VICIntEnClr = 1 << TIMER2_INT; /* Disable Interrupt */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void hwtimer_arch_set(unsigned long offset, short timer)
|
||||
{
|
||||
/* Calculate base address of timer register */
|
||||
/* Timer 0-3 are matched to TIMER0 */
|
||||
/* Timer 4-7 are matched to TIMER1 */
|
||||
/* Timer 8-11 are matched to TIMER2 */
|
||||
volatile unsigned long base = get_base_address(timer);
|
||||
/* Calculate match register address of corresponding timer */
|
||||
timer %= 4;
|
||||
unsigned long cpsr = disableIRQ();
|
||||
volatile unsigned long *addr = VULP(base + TXMR0 + 4 * timer);
|
||||
/* Calculate match register value */
|
||||
unsigned long value = *VULP(base + TXTC) + offset;
|
||||
*addr = value; /* set match register */
|
||||
*VULP(base + TXIR) = 0x01 << timer; /* reset interrupt register value for corresponding match register */
|
||||
*VULP(base + TXMCR) &= ~(7 << (3 * timer)); /* Clear all bits */
|
||||
*VULP(base + TXMCR) |= (MR0I << (3 * timer)); /* enable interrupt for match register */
|
||||
restoreIRQ(cpsr);
|
||||
}
|
||||
|
||||
void hwtimer_arch_set_absolute(unsigned long value, short timer)
|
||||
{
|
||||
/* Calculate base address of timer register */
|
||||
/* Timer 0-3 are matched to TIMER0 */
|
||||
/* Timer 4-7 are matched to TIMER1 */
|
||||
/* Timer 8-11 are matched to TIMER2 */
|
||||
volatile unsigned long base = get_base_address(timer);
|
||||
/* Calculate match register address of corresponding timer */
|
||||
timer %= 4;
|
||||
volatile unsigned long *addr = VULP(base + TXMR0 + 4 * timer);
|
||||
/* Calculate match register value */
|
||||
*addr = value; /* set match register */
|
||||
*VULP(base + TXIR) = 0x01 << timer; /* reset interrupt register value for corresponding match register */
|
||||
*VULP(base + TXMCR) &= ~(7 << (3 * timer)); /* Clear all bits */
|
||||
*VULP(base + TXMCR) |= (MR0I << (3 * timer)); /* enable interrupt for match register */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
void hwtimer_arch_unset(short timer)
|
||||
{
|
||||
volatile unsigned long base = get_base_address(timer);
|
||||
timer %= 4;
|
||||
*VULP(base + TXMCR) &= ~(MR0I << (3 * timer)); /* disable interrupt for match register */
|
||||
*VULP(base + TXIR) = 0x01 << timer; /* reset interrupt register value for corresponding match register */
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
unsigned long hwtimer_arch_now(void)
|
||||
{
|
||||
return T0TC;
|
||||
}
|
||||
|
||||
void hwtimer_arch_setcounter(unsigned int val)
|
||||
{
|
||||
T0TC = val;
|
||||
}
|
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* Copyright (C) 2015 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_lpc2387
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Implementation of the low-level timer driver for the LPC2387
|
||||
*
|
||||
* @author Hauke Petersen <hauke.petersen@fu-berlin.de>
|
||||
* @}
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "periph_conf.h"
|
||||
#include "periph_cpu.h"
|
||||
#include "periph/timer.h"
|
||||
|
||||
/**
|
||||
* @brief Check the board config to make sure we do not exceed max number of
|
||||
* timers
|
||||
*/
|
||||
#if TIMER_NUMOF > 3
|
||||
#error "ERROR in timer configuration: too many timers defined"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Interrupt context information for configured timers
|
||||
*/
|
||||
static timer_isr_ctx_t isr_ctx[TIMER_NUMOF];
|
||||
|
||||
/**
|
||||
* @brief Forward declarations for interrupt functions
|
||||
* @{
|
||||
*/
|
||||
void tim_isr_0(void);
|
||||
void tim_isr_1(void);
|
||||
void tim_isr_2(void);
|
||||
void tim_isr_3(void);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @brief Get the base pointer of a timer
|
||||
*/
|
||||
static inline lpc23xx_timer_t *get_dev(tim_t tim)
|
||||
{
|
||||
switch (tim) {
|
||||
case 0:
|
||||
return TMR0;
|
||||
#if TIMER_NUMOF > 1
|
||||
case 1:
|
||||
return TMR1;
|
||||
#endif
|
||||
#if TIMER_NUMOF > 2
|
||||
case 2:
|
||||
return TMR2;
|
||||
#endif
|
||||
#if TIMER_NUMOF > 3
|
||||
case 3:
|
||||
return TMR3;
|
||||
#endif
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void pwr_clk_and_isr(tim_t tim)
|
||||
{
|
||||
switch (tim) {
|
||||
case 0:
|
||||
PCONP |= (1 << 1);
|
||||
PCLKSEL0 &= ~(0x03 << 2);
|
||||
PCLKSEL0 |= (0x01 << 2);
|
||||
install_irq(TIMER0_INT, &tim_isr_0, 1);
|
||||
break;
|
||||
#if TIMER_NUMOF > 1
|
||||
case 1:
|
||||
PCONP |= (1 << 2);
|
||||
PCLKSEL0 &= ~(0x03 << 4);
|
||||
PCLKSEL0 |= (0x01 << 4);
|
||||
install_irq(TIMER1_INT, &tim_isr_1, 1);
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_NUMOF > 2
|
||||
case 2:
|
||||
PCONP |= (1 << 22);
|
||||
PCLKSEL1 &= ~(0x03 << 12);
|
||||
PCLKSEL1 |= (0x01 << 12);
|
||||
install_irq(TIMER2_INT, &tim_isr_2, 1);
|
||||
break;
|
||||
#endif
|
||||
#if TIMER_NUMOF > 3
|
||||
case 3:
|
||||
PCONP |= (1 << 23);
|
||||
PCLKSEL1 &= ~(0x03 << 14);
|
||||
PCLKSEL1 |= (0x01 << 14);
|
||||
install_irq(TIMER3_INT, &tim_isr_3, 1);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int timer_init(tim_t tim, unsigned int us_per_tick, void (*callback)(int))
|
||||
{
|
||||
/* get the timers base register */
|
||||
lpc23xx_timer_t *dev = get_dev(tim);
|
||||
|
||||
/* make sure the timer device is valid */
|
||||
if (dev == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* save the callback */
|
||||
isr_ctx[tim].cb = callback;
|
||||
/* enable power, config periph clock and install ISR vector */
|
||||
pwr_clk_and_isr(tim);
|
||||
/* reset timer configuration (sets the timer to timer mode) */
|
||||
dev->TCR = 0;
|
||||
dev->CTCR = 0;
|
||||
/* configure the prescaler */
|
||||
dev->PR = (us_per_tick * ((CLOCK_PCLK / 1000000) - 1));
|
||||
/* enable timer */
|
||||
dev->TCR = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_set(tim_t tim, int channel, unsigned int timeout)
|
||||
{
|
||||
unsigned int now = timer_read(tim);
|
||||
return timer_set_absolute(tim, channel, (timeout + now));
|
||||
}
|
||||
|
||||
int timer_set_absolute(tim_t tim, int channel, unsigned int value)
|
||||
{
|
||||
if (tim >= TIMER_NUMOF || channel >= TIMER_CHAN_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
lpc23xx_timer_t *dev = get_dev(tim);
|
||||
dev->MR[channel] = value;
|
||||
dev->MCR |= (1 << (channel * 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int timer_clear(tim_t tim, int channel)
|
||||
{
|
||||
if (tim >= TIMER_NUMOF || channel >= TIMER_CHAN_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
get_dev(tim)->MCR &= ~(1 << (channel * 3));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int timer_read(tim_t tim)
|
||||
{
|
||||
return (unsigned int)(get_dev(tim)->TC);
|
||||
}
|
||||
|
||||
void timer_start(tim_t tim)
|
||||
{
|
||||
get_dev(tim)->TCR = 1;
|
||||
}
|
||||
|
||||
void timer_stop(tim_t tim)
|
||||
{
|
||||
get_dev(tim)->TCR = 0;
|
||||
}
|
||||
|
||||
void timer_reset(tim_t tim)
|
||||
{
|
||||
lpc23xx_timer_t *dev = get_dev(tim);
|
||||
dev->TCR |= 2;
|
||||
asm("nop");
|
||||
dev->TCR &= ~(2);
|
||||
}
|
||||
|
||||
void timer_irq_enable(tim_t tim)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
void timer_irq_disable(tim_t tim)
|
||||
{
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
static inline void isr_handler(lpc23xx_timer_t *dev, int tim_num)
|
||||
{
|
||||
for (int i = 0; i < TIMER_CHAN_NUMOF; i++) {
|
||||
if (dev->IR & (1 << i)) {
|
||||
dev->IR |= (1 << i);
|
||||
dev->MCR &= ~(1 << (i * 3));
|
||||
isr_ctx[tim_num].cb(i);
|
||||
}
|
||||
}
|
||||
/* we must not forget to acknowledge the handling of the interrupt */
|
||||
VICVectAddr = 0;
|
||||
}
|
||||
|
||||
void __attribute__((interrupt("IRQ"))) tim_isr_0(void)
|
||||
{
|
||||
isr_handler(TMR0, 0);
|
||||
}
|
||||
|
||||
#if TIMER_NUMOF > 1
|
||||
void __attribute__((interrupt("IRQ"))) tim_isr_1(void)
|
||||
{
|
||||
isr_handler(TMR1, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TIMER_NUMOF > 2
|
||||
void __attribute__((interrupt("IRQ"))) tim_isr_2(void)
|
||||
{
|
||||
isr_handler(TMR2, 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TIMER_NUMOF > 3
|
||||
void __attribute__((interrupt("IRQ"))) tim_isr_3(void)
|
||||
{
|
||||
isr_handler(TMR3, 3);
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue