Creating a home-brew IR receiver / transmitter with an FTDI chip

author: A. J. Huitsing (albert@huitsing.nl)
date: 6 oct 2008
last modified: 21 oct 2011

Introduction

This page documents my hobby project of building a home-brew IR receiver/transmitter based on the FTDI chipset.
During the past couple of years I've been using several IR receivers and transmitters that where based on RS232 connections. Unfortunately my newest boxes don't have any legacy RS232 connections anymore. Googling around for a cheap USB based solution didn't give me the results I hoped for.

So I came up with the idea to build one myself.

FTDI bitbang mode

The FTDI chipset incorporates a 'bitbang' mode in which the chip supports writing & reading of it's pin directly without the uart functionality. Especially cool is that reading / writing is buffered *and* clocked (!)
The clock-rate is determined by the baudrate generator, and the FIFO buffers are used to buffer.

On the FTDI website there are some documents describing this special mode (for example: here)

Together with this cool mode, another cool project makes it possible to even use it in real life! The libftdi project provides a user-space driver which allows it to use the chip in the advanced modus.
Ubuntu has a nice package for it, so it's easy to install (e.g. apt-get install libftdi0 and apt-get install libftdi-dev for developing purposes)

Carrier modulation

To generate a 36..38 KHz modulated carrier the sender just has to generate 'samples' which will be clocked out by the chip with desired rate automatically!

For example (Philips RC5 code)
To transmit for example the logical 0, the transmitter has to transmit 888 uS 'on' / 'pulse' carrier, and then 888uS 'off' / 'space' carrier:

rc5 0 bit

To let the FTDI generate this pattern in bitbang mode, we simply feed it with 64 'samples' which should be clocked out with 72KHz:
1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,

The chip does the timing, so we don't have to bother writing a kernel driver for timing etc.

Carrier reception

Receiving is the opposite from transmission, and in this case it's 'sampling' the pin at a high enough datarate. The chip will simply sample all pins and put it in it's fifo buffers. We can read the fifos and inspect the samples.
To make reception reliable I've choosen to use a chip which already is tuned to a specific carrier frequency and which outputs the demodulated carrier, so in stead of sampling with 72KHz (see Nyquist: >2x max. freq to be sampled), it is possible to sample with a much lower rate. A lower baudrate will cause less CPU load during reception.

Decoding of the samples can be done relatively easy in software. Detecting a 'pulse' or a 'space' is a matter of evaluating the received samples and counting the number of samples in-between to get the timing of the pulse and space.

Albert's hardware

The hardware for my testing device is as easy as it can be: just connect a IR diode and an IR receiver directly to the pins of the FTDI chip. When you only want transmission or only reception just connect one of them:


albert's hardware schematic
note: I've used a SFH506-38 IR receiver which just was lying around here. It's no longer in production, alternatives are for example PNA4602M or TSOP1138

Albert's hardware vs. 2:

In order to check IR transmission I've built a better transmitter. This setup uses a FTDI MM232R prototype module which I pottered to some LEDs, a receiver and even a FET to boost the current through the LEDs ;-)


Alberts 2nd prototype
Albert's 2nd prototype: very small with MM232R
MM232 module
the MM232R module

receiver example with MM232R

Inversion of the RTS signal
When using a N-channel mosfet like the BS170 there is one issue which should be noted. After a reset the with default settings of the MM232R eeprom, the RTS signal of the MM232R will drive the mosfet, possibly overheating the LEDs. This can be easily tweaked by altering the EEprom inside the MM232R setting the 'invert RTS' option (use the MPROG tool provided by FTDI)
Another solution would be to use a P-channel mosfet which inverts the logic, but then the software must be adapted too (and I noticed this effect after I muddled my hardware together)

Looking at IR signals
In order to check your transmitter operation: you can use a digital photo camera (CCD) to look at the LEDs. With a CCD camera the infra-red LEDs are visibile !


Armin's hardware:

Armin Schlegel (armin.schlegel@avenet.stw.uni-erlangen.de) sent me a nice PCB with the bare minimal to build a USB based receiver. It uses the FT232RL chip, connected to a TSOP 1836 receiver: simple and clean, just the way we like it.



 

Armin has been so nice to send me the schematics (IR_rec.sch) and board design (IR_rec.brd / IR_rec.pdf) as EAGLE files. EAGLE can be found in the Ubuntu repositories.

Thanks Armin !

The software

The software is work in progress. At the moment I've written a daemon driver which connects to LIRC for reception in mode2 operation. I've written a small testprogram for transmitting RC5 codes to try carrier generation.

Adam Sampson(ats@offog.org) was so nice to clean up and improve my code.

Furthermore Alexander Hochbaum (admin@typoflash.com) has written the first steps to include transmission to the driver. These were just the steps I needed to get on going and get the modulated transmission in.

the source for reception with LIRC can be found in  hw_ftdi.c but it's included in the LIRC sources too.

LIRC testing (receive + transmit)

The latest CVS version of LIRC includes Adam's and Alexander's patches (reception + transmission)
To test my LIRC setup yourself: (be sure to have libftdi, libtool, help2man, man2html installed, e.g.  apt-get install libftdi0 libftdi-dev libtool help2man man2html)
  1. create a playground: mkdir ~/lircftdi
  2. be sure to work in your playground: cd ~/lircftdi
  3. get latest lirc sources from CVS: (no password needed, just press enter when asked for)
    cvs -d:pserver:anonymous@lirc.cvs.sourceforge.net:/cvsroot/lirc login
    cvs -z8 -d:pserver:anonymous@lirc.cvs.sourceforge.net:/cvsroot/lirc co lirc
    cd lirc
    cvs update
  4. possibly overwrite daemons/hw_ftdi.c with my bleeding edge version: hw_ftdi.c
  5. create autoconf stuff: ./autogen.sh
  6. configure to select the new FTDI driver: ./setup.sh && make (note: don't use make install to avoid overwriting your existing LIRC daemon)
  7. be sure to have a valid /etc/lircd.conf ready (see LIRC website for this)
  8. startup the lircd by issueing sudo daemon/lircd -n (the -n avoids daemon mode)
  9. proceed testing by issueing for example 'sudo irw' in another shell
    when pressing remote's keys you should see some debugging output in one shell, and the decoded keys in the other.
Configuring the driver
One of the nice improvements of Adam's patch is that it has become a more generic driver. The driver can be configured using the 'device' argument of lircd.
The driver is configured using key=val pairs (all settings are optional, and have reasonable defaults):

vendor vendor code (default 0x0403 for FTDI)
product product code (default 0x6001 for FT232)
desc description string (default = not defined)
serial serial string (default = not defined)
input input bit number (0..7, default = 1)
0 = TxD
1 = RxD (default)
2 = RTS
3 = CTS
4 = DTR
5 = DSR
6 = DCD
7 = RI
output
see input

example, for Adam's hardware (Receiver on RI pin)
lircd -d serial=A4001doI,input=7

LIRC transmission testing

Transmitting is much more critical than receiving. In order to be able to transmit correctly a very accurate lircd.conf file is needed! Test it as follows:
Here I've succesfully tested transmission with:
note: see my tip about CCD camera's

RC5 transmission testing

Transmission is integrated in the LIRC driver now, but you can test it's proof of concept by a RC5 (36 Khz, Philips code) sender only:

2-7-2009: transmission to the power of 2

An important tip from a member on the LIRC mailing list (thanks Enrique !) is that the choosen bitrate for the FTDI chip should be a power of 2!
After a lot of testing it seems that when choosing the bitrate to be a power of 2, the generated carrier is clean enough to control my test-setup, and the scope measurements look fine enough too! : so choose the FTDI bitrate to be a power of 2! I've already adapted this in hwftdi.c (see tx_baud_rate=65536). This is not updated in rc5.c yet.

17-jan-2010: FTDI bitrate investigation

It seems there is something funky going on with the FTDI chips, libftdi or both. In the datasheet of the chip it is stated that the bitrate used in bitbang mode is 16 times the baudrate setup (at least the D2XX function is described that way). But this seems to be not correctly. Several people have reported that reception works, but seem to have problems with transmission. I'm investigating this, and try to find a solution. When you have problems try to alter the baudrates (*2, *4 or /2, /4 etc.) and please feed-back your experiences.

A quick test to verify your hardware can be found in test3.c  (compile with gcc -o test3 -lftdi) This app. generates a 'modulated carrier' which means that it generates a 38Khz signal which is switched on/off with 500 Hz continously. This is especially useful for testing your hardware setup. You can connect a scope on the sender LED and verify if 38Khz signals are generated. Secondly you can connect a scope to the receiver and verify if 500 Hz (demodulated) squarewave is received: this should work at a distance of several meters at least!

tip from Dave Herman when working with multiple connected chips:
Quick way to lookup serial number:
plug into usb port (only 1 though)
udevadm info -q all -n /dev/ttyUSB0

Investigating the Sample accuracy

During testing of the receiver one of my biggest concerns are: "How accurate is the sampling? Is the 'stream' we receive from the FTDI chip continous? Are there drop-outs due to FIFO buffering or USB traffic? "
To check this I used a test setup which consists of a signal generator connected to the RxD pin. The test signal simply contains a square-wave generator of known frequency (my generator can only generate 480Hz). When sampling this signal we should read a consistent # samples before the level of the samples change ('the pulse-width')
I used the program (see: test2.c) for this purpose which samples continously and counts the number of samples between level changes of the input signal. The number of samples is the pulse-width and these are stored in a file for observation (see: pulses.txt) which i did by plotting it with OpenOffice Calc:


Conclusion: the stream is not really accurate I'd say... There is a noise of about 20 'counts' on a value of about 150 (+/- 13%).. but this seems to be OK for the LIRC reception algorithm to deal with.

Ideas

Links

Changelog

21 oct 2011
- added Armin Schlegel's design

20 nov 2010
- updated 'bleeding-edge' hw-ftdi.c for deprecated setbitbang and static time_left()

17 jan 2010
- removed the need for patches: LIRC cvs contains sending & receiving now
- added remarks about funky bitrate business
- added test3.c for testing hardware

7 jul 2009
- added remarks about bitrate being a power of 2

14 mar 2009
- added 'receiver with mm232r' image
- added title 'transmitter' to Albert's hardware vs. 2

12 feb 2009
- updated link to libftdi

26 jan 2009
- added LIRC transmission
- updated RC5.c to accept any FTDI found

31 dec 2008
 - removed manual patching

30 dec 2008
 - added Adam Sampson's patches
 - added a note about alternative IR receivers

23 oct 2008
 - added sample accuracy

8 oct 2008
 - added patches

6 oct 2008
 - initial version