diff --git a/boards/avsextrem/Makefile.features b/boards/avsextrem/Makefile.features index d88a55619b1cbf4e68235d6180e0503187f0b8e2..a73d270b881cfb9e07978a0d7aec3f591f3fb796 100644 --- a/boards/avsextrem/Makefile.features +++ b/boards/avsextrem/Makefile.features @@ -1,4 +1,5 @@ FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_spi +FEATURES_PROVIDED += periph_timer FEATURES_MCU_GROUP = arm7 diff --git a/boards/avsextrem/include/board.h b/boards/avsextrem/include/board.h index 579f83824f7eda660aa4935d709a5e7c888c362c..3f74a5c9db308d50c4f973d0765ab81a7faeb2cd 100644 --- a/boards/avsextrem/include/board.h +++ b/boards/avsextrem/include/board.h @@ -56,6 +56,11 @@ extern "C" { #define STDIO_RX_BUFSIZE (64U) /** @} */ +/** + * @brief Deprecated HW_TIMER definition (to be removed) + */ +#define HW_TIMER TIMER_DEV(0) + /** * @brief Initialize the board's clock system */ diff --git a/boards/avsextrem/include/periph_conf.h b/boards/avsextrem/include/periph_conf.h index 72e7c89a9f2d9fe7448718b79cbe7f2d7d80db1f..2dc1dc76a9ad5a931ab43d3deef814741b2a15e2 100644 --- a/boards/avsextrem/include/periph_conf.h +++ b/boards/avsextrem/include/periph_conf.h @@ -25,6 +25,22 @@ extern "C" { #endif +/** + * @brief Clock configuration + * @{ + */ +#define CLOCK_CORECLOCK (72000000U) /* this board runs with 72MHz */ + +#define CLOCK_PCLK (CLOCK_CORECLOCK) +/** @} */ + +/** + * @brief Timer configuration, select a number from 1 to 4 + * @{ + */ +#define TIMER_NUMOF (1U) +/** @} */ + /** * @brief PWM device and pinout configuration */ diff --git a/boards/msba2-common/lpc2387-timer3.c b/boards/msba2-common/lpc2387-timer3.c deleted file mode 100644 index 7cbf9e0c8e559c6c3c4f4635049e0a7aee1868ea..0000000000000000000000000000000000000000 --- a/boards/msba2-common/lpc2387-timer3.c +++ /dev/null @@ -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; -} diff --git a/boards/msba2/Makefile.features b/boards/msba2/Makefile.features index f1261a22a43435a04f4ee974424e11fb83609f1d..420a36e116c06f9fbacd89a559539afb1ed7d619 100644 --- a/boards/msba2/Makefile.features +++ b/boards/msba2/Makefile.features @@ -2,6 +2,7 @@ FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_pwm FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_spi +FEATURES_PROVIDED += periph_timer FEATURES_PROVIDED += cpp FEATURES_PROVIDED += config FEATURES_MCU_GROUP = arm7 diff --git a/boards/msba2/include/board.h b/boards/msba2/include/board.h index 8b9d6e09b6ff268733e5c341e7b750f79415a60f..2b1102d0c0057f39fd0c88a1dab2cb3bc70d8b9e 100644 --- a/boards/msba2/include/board.h +++ b/boards/msba2/include/board.h @@ -53,6 +53,11 @@ extern "C" { #define STDIO_RX_BUFSIZE (64U) /** @} */ +/** + * @brief Deprecated HW_TIMER definition (to be removed) + */ +#define HW_TIMER TIMER_DEV(0) + /** * @brief initialize the board's clock system */ diff --git a/boards/msba2/include/periph_conf.h b/boards/msba2/include/periph_conf.h index d5c61c1d792154aa16f4a2941b7d5751a57845f1..8789c55a7859cc8d5b4dddcf99de606dfdbb22ca 100644 --- a/boards/msba2/include/periph_conf.h +++ b/boards/msba2/include/periph_conf.h @@ -25,6 +25,22 @@ extern "C" { #endif +/** + * @brief Clock configuration + * @{ + */ +#define CLOCK_CORECLOCK (72000000U) /* the msba2 runs with 72MHz */ + +#define CLOCK_PCLK (CLOCK_CORECLOCK) +/** @} */ + +/** + * @brief Timer configuration, select a number from 1 to 4 + * @{ + */ +#define TIMER_NUMOF (1U) +/** @} */ + /** * @brief PWM device and pinout configuration */ diff --git a/boards/pttu/Makefile.features b/boards/pttu/Makefile.features index d88a55619b1cbf4e68235d6180e0503187f0b8e2..a73d270b881cfb9e07978a0d7aec3f591f3fb796 100644 --- a/boards/pttu/Makefile.features +++ b/boards/pttu/Makefile.features @@ -1,4 +1,5 @@ FEATURES_PROVIDED += periph_gpio FEATURES_PROVIDED += periph_rtc FEATURES_PROVIDED += periph_spi +FEATURES_PROVIDED += periph_timer FEATURES_MCU_GROUP = arm7 diff --git a/boards/pttu/include/board.h b/boards/pttu/include/board.h index 76e7b7c706c5accdb0590e487b8ab1db114b57af..e9efae4775d1e492cdf71f6ae45c87bae4c4b46a 100644 --- a/boards/pttu/include/board.h +++ b/boards/pttu/include/board.h @@ -59,6 +59,11 @@ void bl_init_clks(void); #define STDIO_RX_BUFSIZE (64U) /** @} */ +/** + * @brief Deprecated HW_TIMER definition (to be removed) + */ +#define HW_TIMER TIMER_DEV(0) + /** * @name dummy-defines for LEDs * @{ diff --git a/boards/pttu/include/periph_conf.h b/boards/pttu/include/periph_conf.h index 1998dd03a72743a52429a0a8bdfb3dd32e8d2f76..bc66266dc4458a4be2373771662ffaa295c460b3 100644 --- a/boards/pttu/include/periph_conf.h +++ b/boards/pttu/include/periph_conf.h @@ -25,6 +25,22 @@ extern "C" { #endif +/** + * @brief Clock configuration + * @{ + */ +#define CLOCK_CORECLOCK (72000000U) /* the msba2 runs with 72MHz */ + +#define CLOCK_PCLK (CLOCK_CORECLOCK) +/** @} */ + +/** + * @brief Timer configuration, select a number from 1 to 4 + * @{ + */ +#define TIMER_NUMOF (1U) +/** @} */ + /** * @brief PWM device and pinout configuration */ diff --git a/cpu/lpc2387/Makefile.include b/cpu/lpc2387/Makefile.include index 438dbb2c882ce33e3c8d674ff01ed6764fea329f..5af6269d11916d39ef8e62475692e7aed658ff0a 100644 --- a/cpu/lpc2387/Makefile.include +++ b/cpu/lpc2387/Makefile.include @@ -2,4 +2,4 @@ INCLUDES += -I$(RIOTCPU)/lpc2387/include include $(RIOTCPU)/arm7_common/Makefile.include -USEMODULE += arm7_common periph periph_common bitfield newlib +USEMODULE += arm7_common periph periph_common bitfield newlib hwtimer_compat diff --git a/cpu/lpc2387/hwtimer_cpu.c b/cpu/lpc2387/hwtimer_cpu.c deleted file mode 100644 index cd137a2cac0dda47e849ac2ee8bb2e498fd1da11..0000000000000000000000000000000000000000 --- a/cpu/lpc2387/hwtimer_cpu.c +++ /dev/null @@ -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; -} diff --git a/cpu/lpc2387/include/lpc23xx.h b/cpu/lpc2387/include/lpc23xx.h index b6de1a990f872c165b9cbae880d39ff328c1ce39..dac007043730aabba916c01e4ae169e6c656ad90 100644 --- a/cpu/lpc2387/include/lpc23xx.h +++ b/cpu/lpc2387/include/lpc23xx.h @@ -12,13 +12,20 @@ * ******************************************************************************/ -#ifndef __LPC23xx_H -#define __LPC23xx_H +#ifndef LPC23XX_H +#define LPC23XX_H + +#include <stdint.h> #ifdef __cplusplus extern "C" { #endif +/** + * @brief Type for 32-bit registers + */ +#define REG32 volatile uint32_t + /* Vectored Interrupt Controller (VIC) */ #define VIC_BASE_ADDR 0xFFFFF000 #define VICIRQStatus (*(volatile unsigned long *)(VIC_BASE_ADDR + 0x000)) @@ -496,8 +503,27 @@ are for LPC24xx only. */ #define EMC_STA_EXT_WAIT (*(volatile unsigned long *)(EMC_BASE_ADDR + 0x880)) +/** + * @brief Generic timer register map + */ +typedef struct { + REG32 IR; /**< interrupt register */ + REG32 TCR; /**< timer control register */ + REG32 TC; /**< timer counter */ + REG32 PR; /**< prescale register */ + REG32 PC; /**< prescale counter */ + REG32 MCR; /**< match control register */ + REG32 MR[4]; /**< match registers 1-4 */ + REG32 CCR; /**< capture control register */ + REG32 CR[4]; /**< capture register 1-4 */ + REG32 EMR; /**< external match register */ + REG32 reserved[12]; /**< reserved */ + REG32 CTCR; /**< count control register */ +} lpc23xx_timer_t; + /* Timer 0 */ #define TMR0_BASE_ADDR 0xE0004000 +#define TMR0 ((lpc23xx_timer_t *)TMR0_BASE_ADDR) #define T0IR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x00)) #define T0TCR (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x04)) #define T0TC (*(volatile unsigned long *)(TMR0_BASE_ADDR + 0x08)) @@ -518,6 +544,7 @@ are for LPC24xx only. */ /* Timer 1 */ #define TMR1_BASE_ADDR 0xE0008000 +#define TMR1 ((lpc23xx_timer_t *)TMR1_BASE_ADDR) #define T1IR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x00)) #define T1TCR (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x04)) #define T1TC (*(volatile unsigned long *)(TMR1_BASE_ADDR + 0x08)) @@ -538,6 +565,7 @@ are for LPC24xx only. */ /* Timer 2 */ #define TMR2_BASE_ADDR 0xE0070000 +#define TMR2 ((lpc23xx_timer_t *)TMR2_BASE_ADDR) #define T2IR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x00)) #define T2TCR (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x04)) #define T2TC (*(volatile unsigned long *)(TMR2_BASE_ADDR + 0x08)) @@ -558,6 +586,7 @@ are for LPC24xx only. */ /* Timer 3 */ #define TMR3_BASE_ADDR 0xE0074000 +#define TMR3 ((lpc23xx_timer_t *)TMR3_BASE_ADDR) #define T3IR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x00)) #define T3TCR (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x04)) #define T3TC (*(volatile unsigned long *)(TMR3_BASE_ADDR + 0x08)) @@ -1134,4 +1163,4 @@ with the spec. update in USB Device Section. */ } #endif -#endif // __LPC23xx_H +#endif /* LPC23XX_H */ diff --git a/cpu/lpc2387/include/periph_cpu.h b/cpu/lpc2387/include/periph_cpu.h index 47a07255fd301ec0c771158f304fcc917d2e02d7..8fccc27687ed8b5725dae9602f3861c2f6860902 100644 --- a/cpu/lpc2387/include/periph_cpu.h +++ b/cpu/lpc2387/include/periph_cpu.h @@ -71,7 +71,12 @@ typedef enum { } gpio_flank_t; /** - * @brief declare needed generic SPI functions + * @brief Number of available timer channels + */ +#define TIMER_CHAN_NUMOF (4U) + +/** + * @brief Declare needed generic SPI functions * @{ */ #define PERIPH_SPI_NEEDS_TRANSFER_BYTES diff --git a/cpu/lpc2387/periph/timer.c b/cpu/lpc2387/periph/timer.c new file mode 100644 index 0000000000000000000000000000000000000000..6b1e783cb9160c9c891c632c1deea24df0b563ef --- /dev/null +++ b/cpu/lpc2387/periph/timer.c @@ -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