The unified diff between revisions [d8ed90db..] and [81e4dce2..] is displayed below. It can also be downloaded as a raw diff.

This diff has been restricted to the following files: 'timer.c'

#
# old_revision [d8ed90db2d4284a290224447c40a0d9cef3fbc31]
# new_revision [81e4dce274e79dd9187ed4bd182e1d6fc0fdfb37]
#
# add_file "timer.c"
#  content [88939ba8fd01747c78fddeb6d82012af7d61da7a]
#
============================================================
--- /dev/null	
+++ timer.c	88939ba8fd01747c78fddeb6d82012af7d61da7a
@@ -0,0 +1,266 @@
+#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];
+
+unsigned int timer_map[] = {0, 3, 2, 1};
+
+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 TWREG(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];
+		}
+	}
+	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;
+}
+
+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;
+}
+
+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;
+	}
+}
+