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

author: A. J. Huitsing (albert@huitsing.nl)
date: 6 oct 2008
last modified: 26 may 2016

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 (knallerbse@gmail.com) 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. Furthermore he has created a git repo where these designs can be found also: https://github.com/siredmar/ir_rec

Thanks Armin !

The software

Current LIRC versions support this FTDI based hardware out of the box. So there's no need for patching, just the usual compilation steps:

>tar -xzvf lirc-x.x.x.tgz
>./configure
>make
>make install
    
All the available drivers will be compiled, and can be loaded dynamically by configurating the config file.

Configuring the driver

The driver is selected at loadtime of lircd (/mode2) by the 'driver' argument (-Hftdi) and can be configured using the 'device' argument (-dserial=XXXX). 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 -Hftdi -dserial=A4001doI,input=7
    

The 'serial' argument is needed to uniquely address the FTDI chip in use, so please supply at least this argument. The serial number of your FTDI chip can be found by looking at the systemlog (dmesg) while plugging-in the chip. Here is an excerpt from my system log:


[ 1696.235780] usb 5-1.2: new full-speed USB device number 4 using xhci_hcd
[ 1696.271595] usb 5-1.2: New USB device found, idVendor=0403, idProduct=6001
[ 1696.271600] usb 5-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=3
....
[ 1696.271607] usb 5-1.2: SerialNumber: FTRVA1T9

So for my receiver I start mode2 with:

mode2 -Hftdi -dserial=FTRVA1T9
    

When you're not sure about the serial you could try:

mode2 -Hftdi -dvendor=0x0403

Which would try to open the first FTDI chip found on the system.

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.

26-may-2016: more investigations by Will & Dave

William Manley and his colleague David Röthlisberger did some more research regarding the accuracy of the FT232R chip, and came to the conclusion that the timing is unreliable. They recommend to use the FT230X series instead.

some tips

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

26 may 2016
- added link to Will & Dave's blog 27 may 2015
- removed manual patching of LIRC sources because FTDI stuff is included in LIRC now
- updated some instructions about -H and -d arguments

22 oct 2014
- updated Armin's e-mail address

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