Creating a home-brew IR receiver / transmitter with an FTDI chip
author: A. J. Huitsing
date: 6 oct 2008
last modified: 22 oct 2014
This page documents my hobby project of building a home-brew IR
receiver/transmitter based on the FTDI chipset.
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
So I came up with the idea to build one myself.
FTDI bitbang mode
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.
install libftdi0 and
apt-get install libftdi-dev
for developing purposes)
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
For example (Philips RC5 code)
transmit for example the logical 0, the transmitter has to transmit 888
uS 'on' / 'pulse' carrier, and then 888uS 'off' / 'space' carrier:
- 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
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.
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
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
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.
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:
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
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
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
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 (firstname.lastname@example.org)
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:
Thanks Armin !
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(email@example.com) was so
nice to clean up and improve my code.
Furthermore Alexander Hochbaum (firstname.lastname@example.org)
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,
apt-get install libftdi0 libftdi-dev libtool help2man
Configuring the driver
- create a playground:
- be sure to work in your playground:
- get latest lirc sources from CVS: (no password needed, just press enter when asked for)
cvs -d:pserver:email@example.com:/cvsroot/lirc login
cvs -z8 -d:pserver:firstname.lastname@example.org:/cvsroot/lirc co lirc
- outdated now:
possibly overwrite daemons/hw_ftdi.c with my bleeding edge version: hw_ftdi.c
- create autoconf stuff: ./autogen.sh
- configure to select the new FTDI driver: ./
&& make (note: don't
use make install to avoid
overwriting your existing LIRC daemon)
"Driver configuration" -> "USB devices"
-> "FTDI FT232-based IR Receiver"
"Save configuration & configure"
- be sure to have a valid
/etc/lircd.conf ready (see
LIRC website for this)
- startup the lircd by issueing
sudo daemon/lircd -n (the -n
avoids daemon mode)
- proceed testing by issueing for example '
in another shell
when pressing remote's keys you should see some debugging output in one
shell, and the decoded keys in the other.
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 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 -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:
- start lircd by issueing: sudo
daemon/lircd -n (the -n avoids daemon mode)
- in another shell use irsend
SEND_ONCE xx yy where (xx=device, yy=key: see documentation of
irsend on lirc homepage)
for example to send 'pause' to my squeezebox I'd issue:
>irsend SEND_ONCE sb3 Pause
(sb3 = device, Pause = key)
note: see my tip about CCD camera's
- Philips RC5 TV Set
- Sony receiver
- Slimdevices Squeezebox 3
RC5 transmission testing
Transmission is integrated in the LIRC driver now, but you can test
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 2An
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 investigationIt
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? "
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
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.
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
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
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