These are brief notes on an IR transmitter designed for use in my To the Birdhouse geocache1. The transmitter is deployed inside a birdhouse hidden in woods near Cambridge, UK.

[Front View] 2 [Back View] 3

Desiderata

There’s also one non-issue: only a few units will be needed, so the unit cost isn’t that important.

Hardware

As you can see from the schematic below, the hardware is essentially trivial. The key components are a microcontroller, some infra-red LEDs switched by a MOSFET, and a voltage regulator. There are also a scattering of connectors and configuration links. The programming header matches the 0.1" pitch breakout board6 for the Black Magic Probe programmer/debugger.

The microcontroller, an STM32L4317, was chosen on the basis that it was the only STM32L4 part stocked by LCSC. It is possible that an F series part would have worked just as well: I just assumed that the low-power L series would be a better fit for the limited power available.

The LEDs and associated current limiting resistor are about the simplest thing which might work tolerably well. The resistor does waste power, but stops anything disasterous happening if the LED gets stuck on e.g. because of a software bug.

The voltage across the bottom two cells of the battery is tapped as an easy way to measure the battery voltage.

If making more of these, it would be prudent to add reverse voltage protection, and clamp the battery sense voltage. My bad!

All the design files can be downloaded from GitHub8.

Schematic

[Back View] 9

PCB

[Front View] 10 [Back View] 11
[Front View] 12 [Back View] 13

The curious board shape and mounting holes are compatible with the Hammond 1554B2GYCL14 waterproof enclosure, though that doesn't leave any space for the battery.

LED choice

IR LEDs drop about 1.2–1.3V which is larger than the voltage supplied by a half-empty alkaline cell. So it makes more sense to have, say, four cells driving 3 LEDs. On the other hand, four cells deliver about 6.5V when fully charged which is about 2.2V across each LED: enough to destroy them. Accordingly a 15Ω resistor limits the current to about 150mA.

Energy is lost in the resistor: between a third (at 6.5V) and a tenth (at 4.0V) of the power.

Empirically the current (in mA) through the LEDs in this setup is well modelled by

I = 55.86 * (V - 3.59)

Cell choice

The desire for simplicity led me to the humble alkaline D cell, which a capacity variously claimed to be in the range of 10–20Ah.

Wikipedia claim 12Ah as a lower bound so let’t take that. Although we might take 50mA as the average LED current when on, the signal is modulated by the 40kHz carrier, the 800Hz tone, and the Morse signal. Thus, the LED is only on for about 10% of the time, and leads us to an average LED current of 5mA. This implies that the battery might last about 2,400 hours or 100 days, which is about half an order of magnitude too small.

Modelling the battery voltage didn’t seem easy, so I did some experiments15 instead. In practice the D cells lasted about 120 days, a bit better than expected.

Given that the D cells last for months, doing experiments with them is rather time consuming. Using AAA cells instead makes things run roughly a dozen times faster: roughly ten days to discharge the batteries.

Finally, the four D cells fit neatly into a Hammond 1554EE16 box.

[Battery Box]

Firmware

The basic task of the firmware is to flash a message on the LEDs. Multiple messages can be sent in sequence, and different sequences can be selected by means of the configuration jumpers. One message includes the half-battery voltage.

The firmware makes significant use of the fancy timers on the STM32L431, so you should probably have a copy of the reference manual17 to hand to follow the register setup. That aside, the code runs in an interrupt handler, invoked whenever a new dit or dah has to be sent.

Battery monitoring

The voltage of half the battery is measured by an ADC, roughly every few minutes. So as to not interfere with the transmission, the ADC operations are spread over multiple interrupt calls. To avoid misreads, a checksum is appended to the voltage: the sum of all digits (mod 10) should be 0.

So 25328 is a valid reading because 2 + 5 + 3 + 2 + 8 = 20, and 20 mod 10 = 0. It corresponds to a half-battery voltage of 2.532V.

LED control

The current through the LEDs drops significantly as the battery runs down, and with it the brightness of the LEDs. To maintain the emitted power, the code increases the mark/space ratio of the signal as the battery voltage falls. This is done very crudely: I measured the current through the LEDs for a range of measured voltages, so I can work out the minimum time needed to send at least a given amount of charge to the LEDs in each pulse. There comes a point though when the battery to too weak to deliver the charge even at a duty-cycle of 50%.

The timing is crude: the precision is determined by the ratio of the PWM clock to the carrier frequency: here that’s 800kHz to 40kHz so we have an apparent factor of 20. However, it only makes sense to use duty-cycles up to 50%, so we have ten possible time intervals ranging from 5% to 50%: one order of magnitude.

There are eight different target charge levels covering the range 1nC to 3µC per pulse. The choice is set by means of configuration jumpers which are read at boot time.

By reducing the charge this way, it is easy to increase the battery lifetime by a factor of four without significantly affecting the range at which the signal could be detected. This leads to a battery life of 480 days.

Design Files

The firmware and PCB design can be downloaded from GitHub18. The electronics was designed with KiCad, the firmware is written in C and uses libopencm319. Random bits of Haskell and python were used too.

Lessons learned

Perhaps the most important lesson is that it worked: four D cells are enough to power the device for a year. There is little point in extending the life further: it is good practice to check the device every six months or so anyway.

It was very helpful to make all the frequencies divisors of the CPU clock frequency. With an 800kHz clock, 40kHz is easy to make, but 36kHz would have been trickier.

Although it was fun to play with the fancy timers, I'm not sure they added much practical benefit here.

If one did want to get better efficiency, I think the key is to drive the LEDs in a more sophisticated way. It would be nice to have a way to efficiently dump a given amount of charge into the LED regardless of battery voltage. If you could do that, then the CPU could run at 40kHz rather than 800kHz. Further, if you could move the 40kHz and 800Hz generators out of the CPU, you could reduce the CPU frequency to a few kHz, assuming it would run that slowly.