minipov2 light sensing

So, I have this minipov2 I made from Limor Fried's awesome minipov2 kit. And I wanted to add some input to it, since a device that turns LEDs on and off without paying any attention to its environment is useful for only a fairly limited number of things. There's a technique described in Mitsubishi Electric Research Labs Technical Report 2003-035, "Very Low-Cost Sensing and Communication Using Bidirectional LEDs" for using a single LED to alternately emit and sense light. So I figured I'd make this modification to my minipov2.


Photo of hardware modification

All the LEDs are connected to a common ground, and their high sides are connected to I/O pins of PORTB on the microcontroller. The high-bit LED, the one on the pin-1 end of the ATtiny2313, connected to R1 on the board, is at the very end of the common-ground trace, so I could cut the trace to it without affecting the other LEDs.

So I cut the trace with a box cutter and patched that side of the LED over to PD0, pin 2 on the microcontroller, with a patch wire. I cut a piece of some fairly thin magnet wire to the right length, scraped the green insulating varnish off at the ends, and soldered it in place. I did use a little extra solder for this, but probably shouldn't have.

The only change to the programming is that, for that LED to emit light, the low bit of port D (PORTD0 or PD0) has to be in output mode, outputting a 0. This isn't the default, so you have to add these lines (or something similar) to existing programs:

    DDRD = 0xFF;
    PORTD = 0;

Then I wrote a little program to sense light. The relevant bit looks like this:

void setup_for_measurement(void) {
  DDRB = 0xFF; // set all port B pins to output
  PORTB = 0;   // turn off the other LEDs so they don't interfere
  DDRD = 0xFF; // set all port D pins to output
  PORTD = 1;   // output 1 on the low bit of port D (PD0)
  MCUCR |= (1 << PUD);  // disable pull-up resistors
  // You might think we would have to delay here, but no, the
  // capacitance seems to already be fully charged before you can say
  // "Turn off that pin!"
  DDRD = 0xFE; // set port D pin 0 to input
}
// ...
    reps = 0;
    setup_for_measurement();
    while (PIND & 1) reps++;  // this loop is 6-7 cycles

The compile process (driven by a slightly modified version of Limor's Makefile) looks like this:

Compiling: test_light.c
avr-gcc -c -I. -g -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=8000000 -Wa,-adhlns=test_light.lst -mmcu=attiny2313 -std=gnu99 test_light.c -o test_light.o

Linking: test_light.elf
avr-gcc -I. -g -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -DF_CPU=8000000 -Wa,-adhlns=test_light.o -mmcu=attiny2313 -std=gnu99 test_light.o --output test_light.elf -Wl,-Map=.map,--cref

Creating load file for Flash: test_light.hex
avr-objcopy -O ihex -R .eeprom test_light.elf test_light.hex
avrdude -p attiny2313 -P /dev/parport0 -c dt006 -U flash:w:test_light.hex

18-second movie showing
response to shade

The program displays the light level 10 times a second. The lowest 8 light levels are represented by one LED being turned on (in 8 possible positions); the next lowest 7 are represented by two LEDs being turned on, in different positions, and so on, on a logarithmic scale until levels I have only seen in direct sunlight are represented with 7 and 8 LEDs being on. I took an 18-second movie clip showing it responding to the shade of my hand.

I was really astonished at how easy it was to get this working, although it took me quite a while to figure out how to display the light level reasonably.

I'm a little disappointed at the speed of the sensing, though; the MERL paper was talking about the back-biased LED getting discharged in hundreds of microseconds, and under normal indoor lighting (or shining an LED flashlight right on them), mine take tens of milliseconds instead. They were using theirs to exchange data at 250 bps, and that's clearly out of reach for me unless I can find a way to make them faster.

More information

There's the original MERL paper and the US patent, 6,870,148 issued to the MERL researchers; each has some interesting information. They both cite work by Forrest M. Mims III, "Siliconnections: Coming of Age in the Electronic Era," 139-149, McGraw-Hill, New York, NY, 1986, and "LED Circuits and Projects", 1973, but I don't know what that prior art protects, exactly. The key element in the patent (over and above sensing light with a reverse-biased photodiode) seems to be measuring the light level by the time to reach a threshold voltage, rather than the amount of discharge in a particular time, which last requires an ADC, or whether the voltage falls below the threshold in a specified period of time. There's also a PCT patent application, publication number WO/2003/084102, application number PCT/JP2003/004015, which covers a completely different different set of claims, and is being used to apply for patents in China and Japan.

So, if you want to be protected by patent law, you had better find out what the prior art protects from the patents.

Kragen Javier Sitaker <kragen@pobox.com>