The unified diff between revisions [cc8258a6..] and [08a35a66..] 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 [cc8258a6c3643514892e84cf24fed008bc6f9660] # new_revision [08a35a6680cdf8985cfb16fa6779ee6db7202a9c] # # patch "timer.c" # from [bbb624ceb301647f8ffb240074c02ed3c3200135] # to [bcc39911ffda1137e85438b93c640cfb61c66a65] # ============================================================ --- timer.c bbb624ceb301647f8ffb240074c02ed3c3200135 +++ timer.c bcc39911ffda1137e85438b93c640cfb61c66a65 @@ -1,9 +1,14 @@ #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 @@ -27,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) @@ -43,18 +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; + + 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) @@ -70,22 +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 = T3REG(IR); + T3REG(IR) = ir; + + if (ir & (1<<0)) { + /* Match channel 0 */ + 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; - if (ir & (1<<0)) { - /* Match channel 0 */ - putstr(" *timer0* "); + 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(); } +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) +{ + 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; + } +} +