Talkin' IR sensor blues

I received the sensor that I purchased from Heimann Sensor a couple weeks ago, and today was able to succesfully read an image off of it. The sensor communicates over I2C, which I have used before, but have never had to dive extremely deeply into. However, in debugging the communication with this sensor, I had to dive quite deeply into the specific timing of the I2C specification.

With the device connected to a Raspberry Pi, and with the Pi configured correctly for I2C, I was able to see the devices connected with the i2cdetect command.

pi@raspberrypi:~ $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --       

This is weird, as this does not correspond to the expected addresses listed in the datasheet! (0x34 for the sensor itself, and 0xA0 for the EEPROM.) 0xA0 is actually an 8 bit number, and 0x50 corresponds to this address with the last bit (a 0 for read) left off, so this makes some sense. However, 0x1A seems to be wrong – a mispring in the datasheet.

The quickest way to start working with the Raspberry Pi’s I2C bus is with a Python library that uses the smbus interface. However, with this, I received an IOError whenever attempting to read a register from the device. To dive in further, I looked at what the devices were communicating with each other through a logic analyzer.

Writing a value to a register seems to work correctly:

A good write

However, reading a value does not:  A bad read

Note the stop condition (P) in the middle. This confuses the device, which expects a “repeated start” rather than a complete write immediately followed by a complete read.

Enabling repeated starts

Researching this online revealed that the I2C driver has a combined write/read mode that can be enabled by editing the file /etc/modprobe.d/i2c.conf to include the following line:

options i2c-bcm2708 combined=1

This forces the I2C kernel driver to be loaded with combined mode enabled, and results in the following:

A good read

Reading

To read data off of the sensor, one must read 258 bytes with a particular command. However, the SMBus is limited to 32 bytes. That said, the 32 bytes I did manage to receive look reasonable.

a = [126, 167, 131, 110, 129, 159, 130, 92, 131, 143, 131, 26, 130, 80, 131, 85, 130, 87, 128, 174, 130, 9, 130, 149, 131, 7, 130, 210, 131, 5, 130, 202]

To solve this I needed to interface with the I2C bus directly, rather than through smbus.

I ended up using the Python library python-periphery to accomplish this, and it worked very well. The test script before sets up the device, following a prescribed set of configuration options published in the datasheet, before reading the data from the sensor in a set of four blocks and saving it using pickle.

Results

When I looked at one of the captured images, I saw this:

Noise!

This doesn’t look good. Exposing the sensor again, this time holding my hand in front of it, and subtracting that image from the first one results in the following:

A hand!

This shows the issue – each pixel (or each analog-to-digital converter, given the repeating structure corresponding to each “block” of the sensor) has its own offset, and its on responsivity to incoming light. Without calibrating this, this constant “noise” overpowers the signal from changing IR/temperature conditions. By subtracting two frames in quick succession, this common noise signal is removed, and we can see the actual signal, the hand, directly.

However, it is still quite noisy, as this process of frame subtraction increases random noise (because now we have contributions from two frames) and doesn’t correct for pixel dependent sensitivity.

Improving this noisiness and allowing single frame exposures will require either calibrating this sensor myself, or purchasing a new sensor from Heimann that has been calibrated at the factory.