TV Remote IR decoder module using ATtiny85

The goal was to make a compact IR decoder that processes the signals from a TV-remote and gives a Linux based embedded computer the codes.

Pre-built version of the module.

Pre-built version of the module.

With just 8 pins the ATtiny85 is tiny!  and the Olimexino-85 gives us a very small but useful project board to work with.

It communicates with the host computer using I2C and a separate interrupt line to signal when data is ready for reading.

Key features of this solution:

  • NEC and RC5 protocols
  • Configurable IR-remote address
  • Promiscuous debug mode
  • Configuration by the host
  • Rejects bad data
  • Repeat code supported
  • Easily extended for other IR protocols
  • Host signalling interrupt line
  • I2C host data interface
  • Powered by the host (3.3 or 5V)

Pin assignments
: I2C SDA (serial data line)
PB2: I2C SCL (serial clock line)
PB1: Signalling LED – flashes to show IR decoding
PB3: Host signal line – momentarily changes state when data ready
PB4: IR detector input. This is connected to the IR detector chip.

To receive the IR signal I built a small receiver board (IR detector circuit) that wires in to PB4 of the ATtiny85.  ( The Olimexino-85 also uses PB3 and PB4 for programming the ATtiny85 via USB.  You must unplug the board from the USB interface before plugging  the Olimexino-85 in to the host computer)

To communicate with the host system (an A10-OLinuXino-LIME ) I wanted to use I2C. Luckily the TinyWireS library supports I2C slave mode and is easy to use with the Arduino IDE.

PicoScope 6 trace of I2C communication. Shows IR module working with address 0x04 and the reading of 128 bytes of data.

PicoScope 6 trace of I2C communication. Shows IR module working with address 0x04 and the reading of 128 bytes of data

High Level: How the code works

The program uses a timer and two interrupts.

The Pin Change interrupt from PB4 is used to flag when the IR signal moves from high to low  and from low to high.

Timer0 is scaled to make clock tick every 32µS. Each tick increments a tick counter. When another Pin Change interrupt occurs the count is stored in a data array and the counter is reset to zero to measure the next period.

When the TV remote has finished sending data there are no more pin changes and the timer keeps going until the counter overflows and generates an overflow interrupt (after 8.192 mS approximately).  The Timer0 overflow interrupt service routine is used to analyse the data and store it in the I2C data array. When the data is stored the routine then signals data ready on PB3.

The I2C data array (128 bytes) is used for communicating between the module and the host computer. The lower 16 bytes are reserved for the decoded IR codes. The last 16 bytes are reserved to act as configuration registers. The space in the middle is used for the debug data and for future expansion (The ATtiny85 can do a lot more and there is still one more pin I haven’t used yet!).

Low Level: Decoding

Without configuration by the host the module starts up in debug (promiscuous) mode.  It uses some timing values determined by experimentation to decide on “marks” and “spaces”.

It uses the timing data to identify the protocol used. The NEC protocol has a long period at the beginning and this can be used to decide between RC5 and NEC protocols.

In debug mode the I2C buffer will also contain raw data so you can see the timing of each bit in the protocol and tweak the configuration as required.

In debug mode the module will react to all IR signals. This will let you find out the address of the IR remote you have chosen to use and what protocol it is using.

To use the module normally the application will disable debug mode, set the IR protocol and IR address to be used. Once it is configured the module will reject wrong addresses/protocols and bad transmissions.

I2C buffer contents:
Decoded data
00: IR protocol detected
01: TV remote address
02: not used
03: Command code
04: not used
05: Command repeat count
06: RC5 command toggle flag

Debug raw data
16: Start of raw data in debug mode.
17: Each byte is number of ticks for high or low

84:End of raw debug data (max)

Normally no need to change the timing unless your clock is not 8MHz
119: RC5 high pulse period (ticks)

120: NEC high pulse period (ticks)
121: NEC short pulse following short gap in repeat (ticks)
122: NEC short start gap for repeats (ticks)
123: NEC start gap following start period (ticks)
124: NEC code start period (ticks)
Main configuration in these three registers
125: IR address to use. Ignore other addresses
126: IR mode (0 = any, ‘N’ = NEC, ‘R’= RC5) force decoding mode
127: Debug mode (none zero value for debug) decode everything.

Basic module configuration (Linux)

Use ic2detect to locate the module, i2cdump to dump the data from this module (I2C address = 4 ).  Fire your TV remote at the module and dump the data again. Identify the protocol and address of the IR remote (byte 0 and 1 of the dump). Use i2cset to put these values into bytes 126 and 125. Set byte 127 to 0, disabling debug mode. Now the module will only work with that TV remote ( until you reset it).

Download code that does all that: I2C_IR_010814.