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

cpu/lpc2387: added low-level timer implementation

This commit is contained in:
Hauke Petersen 2015-09-03 23:47:59 +02:00
parent 128d9db0a5
commit 342d292889
3 changed files with 270 additions and 4 deletions

View File

@ -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 */

View File

@ -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

232
cpu/lpc2387/periph/timer.c Normal file
View File

@ -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