Creating a home-brew IR receiver / transmitter with an FTDI chip
author: A. J. Huitsing (firstname.lastname@example.org)
date: 6 oct 2008
last modified: 26 may 2016
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 libftdi-dev for
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' /
- each bit in RC5 code has same duration (+/- 1.78ms)
- transmission is done via a modulated carrier: either the
carrier is on (='pulse') or the carrier is off (='space')
- a logical 1 is coded as space,pulse
- a logical 0 is coded as pulse,space
- a button press on a remote contains 28 bits
To let the FTDI generate this pattern in bitbang mode, we simply
feed it with 64 'samples' which should be clocked out with 72KHz:
The chip does the timing, so we don't have to bother writing a
kernel driver for timing etc.
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.
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:
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 ;-)
Albert's 2nd prototype: very small with MM232R
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 Schlegel (email@example.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 !
Current LIRC versions support this FTDI based hardware out of the
box. So there's no need for patching, just the usual compilation
>tar -xzvf lirc-x.x.x.tgz
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 code (default 0x0403 for FTDI)
||product code (default 0x6001 for FT232)
||description string (default = not defined)
||serial string (default = not defined)
||input bit number (0..7, default = 1)
0 = TxD
1 = RxD (default)
2 = RTS
3 = CTS
4 = DTR
5 = DSR
6 = DCD
7 = RI
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:
- download rc5.c
- change the serial number 'FTE1G5RU' to your own serial number
(somewhere near line 49)
- compile with '
gcc rc5.c -lftdi -o rc5'
- try to transmit some codes:
./rc5 12 (switch TV to stdby)
./rc5 0 (switch to channel '0' on TV)
./rc5 32 (zap P+ on TV)
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
17-jan-2010: FTDI bitrate
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
26-may-2016: more investigations by Will
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.
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
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
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
- The role pins in bitbang mode are all equal (i.e.: all pins
can be configured to be input or output) so potentially we have
a 4x sender or a 4x receiver or any mix of this.
- Adapt the schematic to use a FTDI cable which has
a on-board RS232 level shifter
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
17 jan 2010
- removed the need for patches: LIRC cvs contains sending &
- 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