The unified diff between revisions [a39fe798..] and [056a532c..] 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 [a39fe7980c8f14b70401f4c97f3e10232dce016a]
# new_revision [056a532c92301bcb224e1f786c5f6720e8acf3eb]
#
# patch "timer.c"
#  from [9ef2a6c50a8a227103c6c98477c1ce62327a0977]
#    to [bcc39911ffda1137e85438b93c640cfb61c66a65]
#
============================================================
--- timer.c	9ef2a6c50a8a227103c6c98477c1ce62327a0977
+++ timer.c	bcc39911ffda1137e85438b93c640cfb61c66a65
@@ -3,8 +3,12 @@
 #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
@@ -28,6 +32,15 @@
 #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)
 
@@ -44,21 +57,84 @@
 #define MR3R (1<<10)
 #define MR3S (1<<11)
 
+
+volatile unsigned int timer0_rising[4];
+volatile unsigned int timer0_width[4];
+
+#ifdef TIMER_CPPM
+volatile unsigned int timer0_cppm[8];
+volatile unsigned int timer0_cppm_chan = 0;
+volatile unsigned int timer0_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"))) timer0_interrupt_handler(void);
 
 void timer_event_handler(void);
 
+/* Timer 0 : Capture */
+/* Timer 1 : Output */
+/* Timer 2 : Output */
+/* Timer 3 : System */
+
 void init_timer(void)
 {
+	T3REG(TCR) = TCR_ENABLE | TCR_RESET;
+
+	T3REG(CTCR) = 0; /* Use PCLK */
+	T3WREG(TC) = 0;
+	T3WREG(PR) = TIMER_PRESCALE;
+	T3WREG(PC) = 0;
+
+	T3REG(TCR) = TCR_ENABLE;
+
+	interrupt_register(TIMER0, timer0_interrupt_handler);
+
 	TREG(TCR) = TCR_ENABLE | TCR_RESET;
 
 	TREG(CTCR) = 0; /* Use PCLK */
 	TWREG(TC) = 0;
-	TWREG(PR) = TIMER_PRESCALE ;
+	TWREG(PR) = TIMER0_PRESCALE;
 	TWREG(PC) = 0;
 
+	TWREG(CCR) = 0x00000fff;
+
 	TREG(TCR) = TCR_ENABLE;
-	event_register(EVENT_TIMER, timer_event_handler);
+
+	T2REG(TCR) = TCR_ENABLE | TCR_RESET;
+	T2REG(CTCR) = 0; /* Use PCLK */
+	T2WREG(PR) = 3; // Prescaling
+	T2WREG(PC) = 0; // Reset the prescale counter
+	T2WREG(TC) = 0; // Reset the counter
+
+	T2WREG(MCR) = 0x0400; // Reset on MR3 match
+	T2WREG(PWM) = 0x00000005; // Enable PWMs
+
+	T2WREG(MR3) = PWM_PERIOD; // Period duration
+
+	/* This is chosen to be an invalid output. */
+	T2WREG(MR2) = 1; // Pulse width
+	T2WREG(MR0) = 1; // Pulse width
+
+	T1REG(TCR) = TCR_ENABLE | TCR_RESET;
+	T1REG(CTCR) = 0; /* Use PCLK */
+	T1WREG(PR) = 3; // Prescaling
+	T1WREG(PC) = 0; // Reset the prescale counter
+	T1WREG(TC) = 0; // Reset the counter
+
+	T1WREG(MCR) = 0x0400; // Reset on MR3 match
+	T1WREG(PWM) = 0x00000003; // Enable PWMs
+
+	T1WREG(MR3) = PWM_PERIOD; // Period duration
+
+	/* This is chosen to be an invalid output. */
+	T1WREG(MR1) = 1; // Pulse width
+	T1WREG(MR0) = 1; // Pulse width
+
+	T2REG(TCR) = TCR_ENABLE;
+	T1REG(TCR) = TCR_ENABLE;
 }
 
 unsigned int timer_read(void)
@@ -74,28 +150,133 @@ void timer_set_period(unsigned int perio
 
 void timer_set_period(unsigned int period)
 {
-	TWREG(MR0) = period;
-	TWREG(MCR) = MR0I | MR0R;
-	interrupt_register(TIMER0, timer_interrupt_handler);
+	interrupt_register(TIMER3, timer_interrupt_handler);
+	T3WREG(MR0) = period-1;
+	T3WREG(MCR) = MR0I | MR0R;
+	T3WREG(TC) = 0;
 }
 
 void __attribute__((interrupt("IRQ"))) timer_interrupt_handler(void)
 {
 	unsigned int ir;
-	ir = TREG(IR);
-	TREG(IR) = ir;
+	ir = T3REG(IR);
+	T3REG(IR) = ir;
 
 	if (ir & (1<<0)) {
 		/* Match channel 0 */
-		putstr(" *timer0* ");
+		event_set(EVENT_TIMER);
 	}
 
-	event_set(EVENT_TIMER);
+	interrupt_clear();
+}
 
+void __attribute__((interrupt("IRQ"))) timer0_interrupt_handler(void)
+{
+	unsigned int ir;
+	unsigned int gpio;
+	ir = TREG(IR);
+	TREG(IR) = ir;
+
+	gpio = FP0XVAL;
+
+	if (ir & (1<<5)) {
+		/* Capture channel 1 */
+		if (gpio & (1<<4)) {
+			timer0_rising[0] = TWREG(CR1);
+		} else {
+			timer0_width[0] = TWREG(CR1) - timer0_rising[0];
+#ifdef TIMER_CPPM
+			if (timer0_width[0] > TIMER_CPPM_SYNC) {
+				timer0_cppm_chan = 0;
+				timer0_sync_timestamp = timer0_rising[0];
+			} else {
+				if (timer0_cppm_chan < 8) {
+					timer0_cppm[timer0_cppm_chan] =
+					    timer0_width[0];
+					timer0_cppm_chan++;
+				}
+			}
+#endif
+		}
+	}
+	if (ir & (1<<6)) {
+		/* Capture channel 2 */
+		if (gpio & (1<<6)) {
+			timer0_rising[1] = TWREG(CR2);
+		} else {
+			timer0_width[1] = TWREG(CR2) - timer0_rising[1];
+		}
+	}
+
 	interrupt_clear();
 }
 
-void timer_event_handler(void)
+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 = timer0_rising[channel];	/* Atomic */
+	unsigned int time = TWREG(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 = timer0_sync_timestamp;	/* Atomic */
+	unsigned int time = TWREG(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] = timer0_rising[i];
+	time = TWREG(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)
 {
-	putstr(" *t0event* ");
+	value = PWM_PERIOD - (PWM_MAX + value);
+	switch (channel) {
+	case 0:
+		T2WREG(MR2) = value;
+		break;
+	case 1:
+		T2WREG(MR0) = value;
+		break;
+	case 2:
+		T1WREG(MR0) = value;
+		break;
+	case 3:
+		T1WREG(MR1) = 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:
+		T1WREG(MR0) = value;
+		break;
+	case 3:
+		T1WREG(MR1) = value;
+		break;
+	}
+}
+