#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 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]; } } 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; } }