We’ve implemented an optical infrared Arduino bootloader based on the common 38kHz infrared remote modualtion. Using the Asuro as inspiration, our bootloader goes a step further in that it works seamlessly from within the Arduino IDE, utilizing the STK500V2 protocol without modification. 
As described in detail below, due to hardware specifics and a low carrier frequency, the maximum data rate is 4200 baud and in practice about 4k baud reliably without error. While not amazingly fast, this results in about 1 min 30 seconds to transfer a moderately large Arduino sketch of 20kb. With the sketch loaded, the IR hardware also functions as a bidirectional half duplex serial link. As itemized in the following list, the project as a whole is the sum of it’s parts:
- Echo Cancellation Simplex
- Continuous Demodulation
- Demodulator Phase Delay
- USB Transceiver (Software)
- USB Transceiver (Hardware)
- Arduino IR Transceiver
- Arduino Bootloader
- Board Specifications
Echo Cancellation Simplex
If you’ve ever talked to someone on speakerphone and heard your own echo, you can understand the confusion this creates. This is the issue when adapting the normally full-duplex USB converter to infrared communication, while transmitting the reflected infrared bitstream is also being heard and it stuffs up the receive buffer like a bad head cold. To make the bootloader work seamlessly with the Arduino IDE over modulated infrared, full duplex serial operation is blocked, this is achieved on both sides with software and/or hardware.
Continuous Demodulation
Almost all infrared receivers found in home appliances have an automatic gain control (AGC) circuit to account for variations in signal strength as well as ambient interference from fluorescent lights. If your lucky, the datasheet for the part will state the maximum duty cycle for data transmission before the AGC normalizes the signal and kills the output. From testing it appeared to be less than 5%, which is much too low to send appreciable amounts of data within a reasonable time frame.
Ideally we want the AGC to allow a bit over 50% or no AGC at all. Infrared demodulators without AGC are not common but thankfully, they do exist. Besides being specifically purposed for high volume data transmission, they also find use in sensing and light barrier systems. A couple of these devices are the TSOP58038 and the TSOP4038 from Vishay.
Demodulator Phase Delay
To reject ambient noise, the infrared data is modulated with a 38kHz carrier frequency, a digital one is represented as a tone and a digital zero as no tone. When the demodulator sees the correct carrier frequency, it outputs a digital one. Inside the demodulator, the detection process is implemented in analog as a band pass filter and requires about 7 carrier waves to pass before it reports on the output. It is this requirement that introduces as phase response delay of about 200 microseconds and which can be seen in the following signal capture of the transmission “Hello World”:
The red signal is the 38kHz modulated send and yellow is the demodulated receive signal. The received signal is phase shifted right a full bit width (200us), resolution is at 1ms per division.
USB Transceiver (Software)
For simplicity the computer side transceiver was first implemented in software with a spare Arduino and an IR shield. A 120 ohm resistor is used to hold the Arduino’s reset pin high, preventing the transceiver from resetting. It’s implemented using pinChange interrupt as a bit bang pass though, with the condition that when transmitting, the receiver is ignored. As TTL serial signals are active low and the IR LED is active high, the transmission component is inverted.
The Arduino, the IR shield and the logical truth table to make sense of it all.
USB Transceiver (Hardware)
Once the transceiver was proven in software, the design was moved into the hardware space. This presented a couple of challenges in that the aforementioned phase delay made a logical OR difficult. The solution was to implement a similar or longer delay on the TX line OR input. As can be seen in the following schematic, this is implemented with a 100nF capacitor and 4k7 resistor, click for pops: 
The phase delay arrangement turns on quickly and turns off slowly, adding about 2 milliseconds to block the receiver while transmitting using a bit of transistor logic. As the signals are active low and the TX line is inverted, the gate function required for RXD is the logical OR between inverted TX and the demodulator output (refer to truth table for clarification).
Arduino IR Transceiver
On the Arduino side, all that is required for additional hardware is a demodulator and an IR LED, this makes for a very cheap Arduino sans FT232R converter. The demodulator is connected directly to the Arduino UART receiver (Pin 0). The IR LED connection takes inspiration from the Asuro bootloader, the LEDs anode is fed with a 38kHz PWM from Pin3 while the cathode is connected to Arduino Pin1, the UART Transmitter. As TTL serial is active low, the LED lights with the 38kHz carrier when commanded by the UART.
This schematic has been setup on a bread board Arduino, the basics which have been detailed in the previous post here: http://n0m1.com/2012/04/30/how-to-bread-board-arduino/
Arduino Bootloader
The existing bootloader was modified for half duplex by turning off the receiver while transmitting, 38kHz PWM was setup and some delay was added to handle the phase offset of the demodulator. Prior to making changes, some effort was required to successfully compile the bootloader as documented here: http://n0m1.com/2012/04/01/how-to-compiling-the-arduino-bootloader/
When uploading the IDE checks for the existence of the bootloader, so the hex, source and makefile need to be in the folder here: arduino-1.0\hardware\arduino\bootloaders\IRbbArduino\. The source, hex and makefile can be downloaded here: IRbbArduino.
Board Specifications
The final bit of the puzzle is to let the Arduino IDE know who we are talking to. We add a few lines of text to the end of the boards.txt file in \arduino-1.0\hardware\arduino\. As seen below, it defines who, what and how we are talking. The IDE must be restarted for these changes to apply:
############################################################## bbArduino.name=BreadBoard Arduino328 16MHz w/IR Bootloader@2400 bbArduino.upload.protocol=arduino bbArduino.upload.maximum_size=30720 bbArduino.upload.speed=2400 bbArduino.bootloader.low_fuses=0xc6 bbArduino.bootloader.high_fuses=0xdd bbArduino.bootloader.extended_fuses=0x00 bbArduino.bootloader.path=IRbbArduino bbArduino.bootloader.file=ATmegaBOOT_168_atmega328ir.hex bbArduino.bootloader.unlock_bits=0x3F bbArduino.bootloader.lock_bits=0x0F bbArduino.build.mcu=atmega328p bbArduino.build.f_cpu=16000000L bbArduino.build.core=arduino bbArduino.build.variant=standard
Video
Of course no post would be complete without a video of the bootloader in action. The autoreset feature has yet to be implemented but will include a line in the sketch to signal a reset vector on command. For now it’s reset manually or with power on, there is about a 2 second window in which it must be reset after the IDE indicates uploading.
As per requested in comments below, here is the code for the PC side software transceiver which runs on an Arduino.
Don’t forget to disable reset with a 120 ohm pullup, otherwise the Arduino will bootload instead of passing the data along to IR.
/*
n0m1 IR bootloader PC side, software based bitbang pass through
http://n0m1.com/2012/05/07/superduplex-an-infrared-bootloader-for-arduino/
by krazatchu & socialhardware - 2012/05/07
IR Demodulator on pin 2
IR LED on pin 3 with NPN inversion
PC TXD on pin 1
PC RXD on pin 0
Reset pullup/disable using 120 ohm resistor
Optional Red LED indictor on A1/A4
*/
#include <PinChangeInt.h>
boolean SerialRX = false;
void setup() {
// dont use serial - bitbang output by turning pwm off and on
// onboard Red LED indicator
pinMode(A1, OUTPUT); // LED Anode
pinMode(A4, OUTPUT); // LED Cathode
// Disable the Timer2 Interrupt (which is used for receiving IR)
TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt
pinMode(3, OUTPUT); // IR TXT PWM
digitalWrite(3, LOW); // IR TXT PWM
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA as top
// CS2 = 000: no prescaling
TCCR2A = _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20);
// The top value for the timer. Mod frequency will be SYSCLOCK/2/OCR2A.
OCR2A = 210; // SYSCLOCK / 2 / khz / 1000; = 16M /2 /38 /1000 = 210.526
OCR2B = OCR2A / 3; // 33% duty cycle
pinMode(0, INPUT); // Serial receiver
PCintPort::attachInterrupt(0, serialRXDoff, RISING);
PCintPort::attachInterrupt(0, serialRXDon, FALLING);
pinMode(1, OUTPUT); // serial out
digitalWrite(1, HIGH); //
pinMode(2, INPUT); // IR RXR1 38kHz
PCintPort::attachInterrupt(2, serialTXDoff, FALLING);
PCintPort::attachInterrupt(2, serialTXDon, RISING);
}
void loop() {
// do nothing, let interupts work
}
void serialRXDon (){
// turn pwm on - PIN3
SerialRX = true;
// or switch to in/out
TCCR2A |= _BV(COM2B1);
// blink (300);
}
void serialRXDoff (){
// turn pwm off - PIN3
TCCR2A &= ~(_BV(COM2B1));
// digitalWrite(3, LOW);
PORTD &= ~ (1<<PORTD3);
SerialRX = false;
}
void serialTXDon (){
// turn on FTDI RXD
if(SerialRX == false){
// led on
PORTC &= ~(1<<PORTC1);
PORTD |= (1<<PORTD1);
}
}
void serialTXDoff (){
// turn off FTDI RXD
if(SerialRX == false){
// led off
PORTC |= (1<<PORTC1);
PORTD &= ~(1<<PORTD1);
}
}
Hi,
This sounds really interesting and I’m trying to implement it on my own. However, I’m having trouble replicating the USB Transceiver part.
I understand that I need to pull the reset high. I also understand that a pinChange interrupt will be used to process incoming data, so perhaps I should jumper between digital pins 0 and 2 and attach an interrupt there.
What I don’t understand is how to implement this “bit bang pass though” (or what it really means). Why can’t I make a SoftwareSerial port with TX on my LED (baud rate 2400) and simply shoot out buffered Serial.read() (also at 2400). When I try to do this and to IR.read() on another Arduino I don’t receive anything but I do get bits from an IR remote, which tells me that my Transceiver is wrong.
Would you be kind enough to point me in the right direction?
In case it’s relevant, the IR stuffs I’m using are in the two following links:
IR Receiver: http://www.sparkfun.com/products/8554
IR LED: http://www.sparkfun.com/products/10732
Thanks!
Louis
Hi Louis,
I had two working methods for the PC side transceiver, one in software and one in hardware.
It sounds like you are trying to implement the software method via bit bang which is simply software serial:
http://en.wikipedia.org/wiki/Bit_banging.
For this I used an Arduino with a pin change interrupt watching TX and passing the data along to the IR LED.
There was another pin change interrupt watching the IR demodulator and passing the bit stream to RX.
Where it gets interesting is implementing the blocking logic in software such that RX ignores when TX is sending, including a bit of phase shift to account for the delay of the demodulator.
I have appended the code for the PC side transceiver just under the video above.
As well, you will have one issue with your demodulator, it contains an automatic gain control circuit which will turn off the output after a short bit of data, as per the first page of the datasheet “will suppress some data signals”.
You will want to use a demodulator rated for continuous operation, such as the TSOP58038 or the TSOP4038.
Thanks,
Michael/krazatchu
Thank you for the help! I’m trying to complete the sketch since the end appears to be missing but it’s a great exercise since I don’t have much experience this low level.
So far, it seems that the include statement is incomplete: #include
And the almost finished function is:
void serialRXDoff (){
// turn pwm off – PIN3
TCCR2A &= ~(_BV(COM2B1));
// digitalWrite(3, LOW);
PORTD &= ~(1<<(COM2B1));
}
I'm still trying to figure out void serialTXDoff() and serialTXDon()…
Thanks for spotting that, the code display plugin didn’t like the copy and paste.
It wanted to format the code before it went in, the remainder of the code is now up.
-krazatchu
Hey Michael,
If the bootloader is properly loaded, shouldn’t I be able to upload sketches either via direct USB or using the IR pass through?
I’m wondering because I’m having the typical “avrdude: stk500_getsync(): not in sync: resp=0xec” error, but I get it regardless of IR or USB connection.
Note, I am still using the IR receiver that you said wouldn’t work but I don’t think it’s proven to not work until I know my bootloader is properly connected.
Thanks again!
Louis
Actually, I am getting two different error messages:
via IR: avrdude: stk500_recv(): programmer is not responding
via USB: avrdude: stk500_getsync(): not in sync: resp=0xec
Which suggests to me that the IR connection is lacking due to the module…
Will check in when/if I get a new part!
Thanks,
Louis
The IR demodulator will not make any difference to the USB connection.
It should also be reporting a non-zero error over IR.
The best plan of attack is to continue on your current course, get the USB going first, then add in the IR.
That is correct, you will be able to use either the IR or USB @ 2400 baud.
Hi,
I am trying to implement your project but I would like to take it a step further. Would it be possible to load a sketch into an Arduino and then once loaded press a button to upload via IR the same sketch into another arduino? this way you could carry a sketch in an Arduino and passed to another Arduino via IR without the PC.
The aim is to make a portable IR sketch uploader
Ya, that’s totally possible….