Friday, October 9, 2015

Industrial I/O + CO2/VOC Sensors + I2C + Random Rants

Whoa long time since my last blog post so figured that it was the time to talk about a few own-time projects that I have been working on. These are probably the most non-sense embedded crap since my lightning sensor driver that got upstreamed... of course I live in Oregon where a lightning strike panics people :)

Anyone that knows me knows I like easy and fun projects that haven't been popped into a kernel driver. So when I spotted a few I2C sensors that allowed you to detect VOC and CO2 levels for indoors air quality readings, and no "drivers "existed outside of Arudino Sketch code or "userspace" "drivers".... I had to act to make these available to a real kernel implementation which within the Industrial I/O subsystem.

Now there is no chemical sensor framework that existed in IIO before these drivers so it required a few new datatypes to be added, and as well some new modifiers for the gas types (CO2, VOC, etc)

Some basic chemistry revisiting was required to remember what a VOC is for instance, which is pretty much any carbon molecule other than CO or CO2. However the EPA regulations don't define the important VOCs such as methane and ethane as such, and which are typically sensed as VOCs.

Now annoyingly these sensors have few design issues because they are designed as low sample rate devices (1HZ or less updates), and to be accessed via a microcontroller bit-banged I2C rather than a real I2C bus controller.

IIO Additions:

Several new IIO channel types and modifiers were needed for these sensors

  • IIO_CONCENTRATION - percentage of a substance (see modifiers below) in a given volume/solution/etc
  • IIO_RESISTANCE - meh just another channel available and inversely related to the VOC channel.. important for data integrity checks referenced below  
  • IIO_MOD_VOC - tVOC gas channel modifier
  • IIO_MOD_CO2 - CO2 gas channel modifier

Now all VOC and CO2 sensors report back in parts-per-million/billion so to be sane we convert it via the scale value to IIO_CONCENTRATION and let the userspace care if they want to swap it back to ppm/ppb.

Now to explain the I2C bit-banging issue... mainly these sensors may ask for a transaction start command and you have to I2C byte data off the bus... now if you are doing a I2C bitbanging you can do the non-spec allowed ADDRESS READ_BIT [BYTE 0 1 2 3 ... ] with these devices. However it ends up being byte reads like ADDRESS READ_BIT BYTE 0, ADDRESS READ_BIT BYTE 1, ADDRESS READ_BIT BYTE 2, etc for a real I2C bus...

Before anyone tells me about smbus/i2c block reads.. these will not work with these devices at all because they have no concept of them, and the byte written for the buffer size could damage the factory calibration data.

This causes a issue because the device can update the values between the milliseconds the scheduler gives someone else to run before the next I2C byte read, and with the VZ89 this update resets the data pointer within the IC.

SGX VZ89x Sensors:
  • Cheapest VOC/CO2 I2C capable sensors out there.
  • 400-2000 ppm CO2, and 0-1000 ppb VOC range
  • Initial development of the chemical part of the IIO subsystem was using this sensor.
  • Horrible I2C hacks needed for the rare update in a middle of a read.
    • Basically confirm the high byte of the IIO_RESISTANCE reading is 0 (which it is always per datasheet) and the VOC_short is 13 (after warmup it will be).  If you are in this state you return -EAGAIN, and the next reading is valid.
  • Staged for 4.4 hopefully! Already in linux-next!
Xively Hipster Apartment Feed ->

Normally QA/unit testing is my least favorite part of any project but for this it was pretty easy and fun (aka beer was involved).

  • Unit Test #1 - Drink a beer a blow on the sensor lightly (CO2 + VOC): PASS
  • Unit Test #2 - Put my lighter over the sensor with the flint removed (VOC): PASS
  • Unit Test #3 - Leave apartment to the bar to see if the levels normalize (CO2 + VOC): PASS