From f324577af4726c9c233f269391c1b9487605a349 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Mon, 8 Mar 2021 22:09:12 +0200 Subject: [PATCH] IR receiver works, next up decoding --- src/main.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 95 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index 2584292..995149e 100644 --- a/src/main.c +++ b/src/main.c @@ -8,10 +8,12 @@ #include "i2c.h" /* TODO - * IR decoding, connected to PCINT0 + * IR decoding, connected to PD2 * enable/disable with switch on PCINT1 * some of the buttons multiplexed on ADC0 */ +#define PD_IR 2 +#define PD_ENSW 3 #define EVQ_SIZE 64 uint16_t evq[EVQ_SIZE]; @@ -40,6 +42,10 @@ static uint16_t dump_addr; static int dump_count; static int dbgmode; +static volatile unsigned char pending; +static volatile unsigned char enable, prev_enable; +static volatile uint16_t ir_input; + static void proc_cmd(char *input); static void printstat(void); static void printdump(void); @@ -47,7 +53,7 @@ static void printdump(void); int main(void) { - uint16_t val; + unsigned char pend; /* tri-state everything and disable pullups */ DDRB = 1; /* B0: activity LED */ @@ -55,7 +61,23 @@ int main(void) DDRD = 0; PORTB = 0; PORTC = 0; - PORTD = 0; + PORTD = 1 << PD_ENSW; + + /* setup external interrupts */ + EICRA = 0x6; /* INT0 falling edge, INT1 both */ + EIMSK = 3; /* enable INT0 and INT1 */ + + /* we'll use the timer 0 compare interrupt for sampling the IR input pulses + * we need to sample every 889us or 1124.86 Hz + * interrupt frequency = F_CPU / (prescaler * (1 - OCRnx)) + * 14745600 / (64.0 * (1.0 + 204)) -> 1123.9 Hz + */ + TCCR0A = 2; /* clear on compare match */ + TCCR0B = 3; /* clock select: ioclock / 64 <- prescaler */ + OCR0A = 192; /* count top */ + + /* read initial enable switch state */ + enable = (~PIND >> PD_ENSW) & 1; i2c_init(); @@ -67,6 +89,18 @@ int main(void) for(;;) { i2c_check_async(); + cli(); + pend = pending; + pending = 0; + sei(); + if(pend & 1) { + printf("IR: %04x (%s)\n", (unsigned int)ir_input & 0x7fff, ir_input & 0x8000 ? "err" : "ok"); + } + if(pend & 2 && enable != prev_enable) { + printf("enable: %d\n", enable); + prev_enable = enable; + } + if(have_input()) { int c = getchar(); putchar(c); @@ -82,6 +116,8 @@ int main(void) } /* read from queue and send over the serial port */ + /* + uint16_t val; val = 0xffff; cli(); if(evq_wr != evq_rd) { @@ -94,6 +130,7 @@ int main(void) unsigned char ev = val >> 8; printf("%02x: %02x\n", ev, val & 0xff); } + */ } return 0; } @@ -213,3 +250,58 @@ static void printdump(void) putchar('\n'); } } + +static unsigned char nsamples; +static uint32_t samples; + +ISR(INT0_vect) +{ + /* ignore interrupts while a previous input is pending */ + if(pending & 1) return; + + /* IR going low */ + ir_input = 0; + nsamples = 1; /* we're starting in the middle of the first bit which should be 01 (=1) */ + samples = 0; + EIMSK &= 0xfe; /* disable further interrupts while decoding IR code */ + + TCNT0 = 96; /* reset the counter to half the range so it'll trigger in the middle of the current pulse */ + TIFR0 |= 1 << OCF0A; /* clear pending interrupts */ + TIMSK0 = 1 << OCIE0A; /* enable output compare interrupt */ + + //PORTB ^= 1; +} + +ISR(TIMER0_COMPA_vect) +{ + static unsigned char err; + + PORTB ^= 1; + + samples = (samples << 1) | (~(PIND >> PD_IR) & 1); + if((++nsamples & 1) == 0) { + if((samples & 3) == 0 || (samples & 3) == 3) { + /* 00 or 11 are invalid sequences, we lost sync */ + err = 1; + } + + /* 01->1, 10->0 */ + ir_input = (ir_input << 1) | (samples & 1); + } + + if(nsamples >= 28) { + if(err) { + ir_input |= 0x8000; + } + pending |= 1; + err = 0; + TIMSK0 &= ~(1 << OCIE0A); /* disable the sampling interrupt */ + EIMSK |= 1; /* re-enable the edge-detect interrupt for the next input */ + } +} + +ISR(INT1_vect) +{ + enable = (~PIND >> PD_ENSW) & 1; + pending |= 2; +} -- 1.7.10.4