Below is the file 'timer.c' from this revision. You can also download the file.

#include "timer.h"
#include "interrupt.h"
#include "uart.h"
#include "event.h"

#define FP0XVAL (*((volatile unsigned int *) 0x3FFFC014))

#define TIMER0BASE  0xE0004000
#define TIMER1BASE  0xE0008000
#define TIMER2BASE  0xE0070000
#define TIMER3BASE  0xE0074000

#define IR    0x00
#define TCR   0x04
#define TC    0x08
#define PR    0x0c
#define PC    0x10
#define MCR   0x14
#define MR0   0x18
#define MR1   0x1C
#define MR2   0x20
#define MR3   0x24
#define CCR   0x28
#define CR0   0x2C
#define CR1   0x30
#define CR2   0x34
#define CR3   0x38
#define EMR   0x3C
#define CTCR  0x70
#define PWM   0x74

#define TREG(x) (((volatile unsigned char *)TIMER0BASE)[x])
#define TWREG(x) (((volatile unsigned int *)TIMER0BASE)[(x)/sizeof(unsigned int)])

#define T1REG(x) (((volatile unsigned char *)TIMER1BASE)[x])
#define T1WREG(x) (((volatile unsigned int *)TIMER1BASE)[(x)/sizeof(unsigned int)])

#define T2REG(x) (((volatile unsigned char *)TIMER2BASE)[x])
#define T2WREG(x) (((volatile unsigned int *)TIMER2BASE)[(x)/sizeof(unsigned int)])

#define T3REG(x) (((volatile unsigned char *)TIMER3BASE)[x])
#define T3WREG(x) (((volatile unsigned int *)TIMER3BASE)[(x)/sizeof(unsigned int)])

#define TCR_ENABLE (1<<0)
#define TCR_RESET  (1<<1)

#define MR0I (1<<0)
#define MR0R (1<<1)
#define MR0S (1<<2)
#define MR1I (1<<3)
#define MR1R (1<<4)
#define MR1S (1<<5)
#define MR2I (1<<6)
#define MR2R (1<<7)
#define MR2S (1<<8)
#define MR3I (1<<9)
#define MR3R (1<<10)
#define MR3S (1<<11)


volatile unsigned int timer1_rising[4];
volatile unsigned int timer1_width[4];

#ifdef TIMER_CPPM
volatile unsigned int timer1_cppm[8];
volatile unsigned int timer1_cppm_chan = 0;
volatile unsigned int timer1_sync_timestamp;
#endif

unsigned int timer_map[] = {0, 1, 2, 3, 4, 5, 6, 7};

void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void);
void __attribute__((interrupt("IRQ"))) timer1_interrupt_handler(void);

void timer_event_handler(void);

void init_timer(void)
{
	TREG(TCR) = TCR_ENABLE | TCR_RESET;

	TREG(CTCR) = 0; /* Use PCLK */
	TWREG(TC) = 0;
	TWREG(PR) = TIMER_PRESCALE ;
	TWREG(PC) = 0;

	TREG(TCR) = TCR_ENABLE;

	interrupt_register(TIMER1, timer1_interrupt_handler);

	T1REG(TCR) = TCR_ENABLE | TCR_RESET;

	T1REG(CTCR) = 0; /* Use PCLK */
	T1WREG(TC) = 0;
	T1WREG(PR) = TIMER_PRESCALE ;
	T1WREG(PC) = 0;

	T1WREG(CCR) = 0x00000fff;

	T1REG(TCR) = TCR_ENABLE;

	T2REG(TCR) = TCR_ENABLE | TCR_RESET;
	T2REG(CTCR) = 0; /* Use PCLK */
	T2WREG(PR) = 0; // Prescaling
	T2WREG(PC) = 0; // Reset the prescale counter
	T2WREG(TC) = 0; // Reset the counter

	T2WREG(MCR) = 0x0400; // Reset on MR3 match
	T2WREG(PWM) = 0x0000000d; // Enable PWMs

	T2WREG(MR3) = PWM_PERIOD; // Period duration

	/* This is chosen to be an invalid output. */
	T2WREG(MR1) = 1; // Pulse width
	T2WREG(MR0) = 1; // Pulse width

	T3REG(TCR) = TCR_ENABLE | TCR_RESET;
	T3REG(CTCR) = 0; /* Use PCLK */
	T3WREG(PR) = 0; // Prescaling
	T3WREG(PC) = 0; // Reset the prescale counter
	T3WREG(TC) = 0; // Reset the counter

	T3WREG(MCR) = 0x0010; // Reset on MR1 match
	T3WREG(PWM) = 0x0000000b; // Enable PWMs

	T3WREG(MR1) = PWM_PERIOD; // Period duration

	/* This is chosen to be an invalid output. */
	T3WREG(MR3) = 1; // Pulse width
	T3WREG(MR0) = 1; // Pulse width

	T2REG(TCR) = TCR_ENABLE;
	T3REG(TCR) = TCR_ENABLE;
}

unsigned int timer_read(void)
{
	return T1WREG(TC);
}

void timer_delay_clocks(unsigned int clocks)
{
	signed int time = TWREG(TC) + clocks;
	while (((signed int) (time-TWREG(TC))) > 0);
}

void timer_set_period(unsigned int period)
{
	interrupt_register(TIMER0, timer_interrupt_handler);
	TWREG(MR0) = period;
	TWREG(MCR) = MR0I | MR0R;
	TWREG(TC) = 0;
}

void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void)
{
	unsigned int ir;
	ir = TREG(IR);
	TREG(IR) = ir;

	if (ir & (1<<0)) {
		/* Match channel 0 */
		event_set(EVENT_TIMER);
	}

	interrupt_clear();
}

void __attribute__((interrupt("IRQ"))) timer1_interrupt_handler(void)
{
	unsigned int ir;
	unsigned int gpio;
	ir = T1REG(IR);
	T1REG(IR) = ir;

	gpio = FP0XVAL;

	if (ir & (1<<4)) {
		/* Capture channel 0 */
		if (gpio & (1<<10)) {
			timer1_rising[0] = T1WREG(CR0);
		} else {
			timer1_width[0] = T1WREG(CR0) - timer1_rising[0];
#ifdef TIMER_CPPM
			if (timer1_width[0] > TIMER_CPPM_SYNC) {
				timer1_cppm_chan = 0;
				timer1_sync_timestamp = timer1_rising[0];
			} else {
				if (timer1_cppm_chan < 8) {
					timer1_cppm[timer1_cppm_chan] =
					    timer1_width[0];
					timer1_cppm_chan++;
				}
			}
#endif
		}
	}
	if (ir & (1<<5)) {
		/* Capture channel 1 */
		if (gpio & (1<<11)) {
			timer1_rising[1] = T1WREG(CR1);
		} else {
			timer1_width[1] = T1WREG(CR1) - timer1_rising[1];
		}
	}
	if (ir & (1<<6)) {
		/* Capture channel 2 */
		if (gpio & (1<<17)) {
			timer1_rising[2] = T1WREG(CR2);
		} else {
			timer1_width[2] = T1WREG(CR2) - timer1_rising[2];
		}
	}
	if (ir & (1<<7)) {
		/* Capture channel 3 */
		if (gpio & (1<<18)) {
			timer1_rising[3] = T1WREG(CR3);
		} else {
			timer1_width[3] = T1WREG(CR3) - timer1_rising[3];
		}
	}

	interrupt_clear();
}

bool timer_valid(int channel) {
	channel = TIMER_CH(channel);
	/* Be careful here to ensure that this can't be in the past */
	unsigned int chtime = timer1_rising[channel];	/* Atomic */
	unsigned int time = T1WREG(TC);			/* Atomic */
	return (time - chtime) < TIMER_INPUT_TIMEOUT;
}

#ifdef TIMER_CPPM
bool timer_allvalid(void) {
	/* Be careful here to ensure that this can't be in the past */
	unsigned int chtime = timer1_sync_timestamp;	/* Atomic */
	unsigned int time = T1WREG(TC);			/* Atomic */
	return (time - chtime) < TIMER_INPUT_TIMEOUT;
}
#else
bool timer_allvalid(void) {
	unsigned int time;
	unsigned int chtime[4];
	int i;
	/* Be careful here to ensure that this can't be in the past */
	for (i = 0; i < 4; i++)
		chtime[i] = timer1_rising[i];
	time = T1WREG(TC);
	for (i = 0; i < 4; i++)
		if ((time - chtime[i]) >= TIMER_INPUT_TIMEOUT)
			return FALSE;
	return TRUE;
}
#endif

void timer_set_pwm_value(int channel, int value)
{
	value = PWM_PERIOD - (PWM_MAX + value);
	switch (channel) {
	case 0:
		T2WREG(MR2) = value;
		break;
	case 1:
		T2WREG(MR0) = value;
		break;
	case 2:
		T3WREG(MR3) = value;
		break;
	case 3:
		T3WREG(MR0) = value;
		break;
	}
}

void timer_set_pwm_invalid(int channel)
{
	int value = 1;
	switch (channel) {
	case 0:
		T2WREG(MR2) = value;
		break;
	case 1:
		T2WREG(MR0) = value;
		break;
	case 2:
		T3WREG(MR3) = value;
		break;
	case 3:
		T3WREG(MR0) = value;
		break;
	}
}