using the MCP23008 gpio expander with chip Pro and perl

I’ve mentioned the next thing co.  chip family of single board computers before.  It was billed as the world’s first $9 computer.  I first heard of it on NPR one morning and couldn’t get to a computer to pre-order one fast enough.  A full-blown debian distribution, wifi, i2c, SPI, 8-gpio pins, composite video, UART, USB and more about the size of a credit card.  It seemed too good to be true.  I guess it was, because they did not last long.  I bought 15 of them, but never received the last five before they tanked.  They also came out with the chip Pro,  an even smaller, somewhat stripped down version of the chip aimed at being a platform for mass-produced products for $16.  I really liked the optional ufl wifi antenna port.  With an external high-gain antenna, it is really great at sniffing wifi networks.   It is totally awesome, and I wish I had 100 of them.

chip pro
chip Pro

Sadly, I burned up all my gpio pins on a project.  I didn’t want to scrap my chip pro, however, and decided to use the MCP23008 gpio I/O expander to get my gpio back up and working.

I wrote my own easy to use perl based driver to interface with the MCP23008.  There are some great tools on CPAN that implement I2C for stuff like this, but I went an even simpler route.  My driver (at a mere 40 lines of code)  uses system calls (via backticks)  to read and write to registers on the gpio expander.  For example, to read the gpio register, the script will just make a system call like so:

sudo i2cget -y 1 0X20 0x09

This tells the chip Pro to talk to the i2c device on bus 1, at address 0x20, and read the value in register 0x09 (gpio register).   Here is the driver in it’s entirety:

#!/usr/bin/perl -w
use strict;

utilities for MCP23008 gpio extender
execute any scripts that use this as sudo

#global variables
my $address;
my $gpio_w = 0;

sub gpio_enable{
	#function takes the i2c address of the MCP23008
	#it also  sets the IO direction
	#register.  Must be a value from 0-255
	#1 is input, 0 is output

	$address = $_[0];
	my $ioreg_val = $_[1];

	#write io reg
	`i2cset -y 1 $address 0x00 $ioreg_val`;
}#end gpio_enable

sub gpio_read{
	#function uses i2cget to
	#read gpio register 0x09
	my $reading = `i2cget -y 1 $address 0x09`;
	return $reading;
}#end gpio_read

sub gpio_write{
	#takes int from 0-255 to write to the
	#gpio register
	$gpio_w = $_[0];
	`i2cset -y 1 $address 0x09 $gpio_w`;
}#end gpio_write


So simple, I’m embarrassed, but it works great.  To test, I wrote a simple script that visually counts to 255 in binary with LED output.

perl mcp23008 driver
i2c mcp23008 binary counter with chip Pro and perl

Here is the script:

use strict;
use Time::HiRes qw(usleep);
require '';

#init the 23008 IO register as output
gpio_enable(0x20, 0);

for(my $i=0;$i<256;$i++){
}#end for



battery discharge analyzer

pid3A Battery loadtest analyzer
pid3A Battery loadtest analyzer

This is the first of probably several posts about a battery discharge analyzer I have been perfecting for a little over a year now. I work in the telecommunications field where uninterrupted power is a must. To achieve this, there are large, high-capacity backup battery plants that keep equipment up and running in the event of a commercial power outage. Generally, but not always, these are -48 volt DC lead-acid batteries  anywhere from 50 amp-hour to over 2000 amp-hour depending on the application and power requirements of the facility they are backing up. It is important to know how long a battery plant will be able to supply power before a facility goes down. To calculate this, you take into factor the combined current draw of all the equipment, and the amp-hour rating of the batteries. So, if your equipment loads the batteries at 15 amps, and you have 200-AH batteries, you should be able to power the site for 13.3 hours if your batteries are at 100% capacity.

hours of backup power = amp hours / site load

200AH / 15A site load = 13.3 hours (assuming 100% battery capacity)

But what if the batteries are not at 100% capacity?  What if they are in poor condition and have much less than 100% capacity?  How do you know?  The answer is capacity testing with a load bank.  IEEE450 describes load testing recommendations for vented lead-acid battery plants and IEEE1188 for valve-regulated lead-acid (VRLA) battery systems.  While this load test analyzer will work with any type of battery composition,  I have focused on lead-acid batteries.

characteristic discharge curve of a lead-acid cell
characteristic discharge curve of a lead-acid cell

The picture above shows a characteristic discharge curve of a lead-acid cell under a slight load.  It dips into a trough,  rebounds, and discharges somewhat logarithmically until it totally drops off.  This graph was generated by my load test analyzer, which I refer to as pid3A (pi, as in raspberry pi, data acquisition and analysis).  It takes thousands of samples,   plots the results on dynamically generated graphs, creates user-defined reports,  stores results for download, and displays test results via it’s internal web server.

Right now, I am on my second prototype.  It can sample up to 24 individual cells during a load test.  It can function as a stand-alone analyzer that travels with a separate load bank, or an online all the time battery monitoring system.

IEEE450 IEEE1188 load tester invention
pid3a battery load test analyzer in online monitoring system configuration

The samples are taken by three MCP3208 12-bit analog to digital converters (ADC).  Each chip has eight inputs, and is connected to a dedicated voltage reference.  I wrote a bit-banged driver for the ADC chip in perl using my own gpio interface.

MCP3208 Analog to digital converter
MCP3208 Analog to digital converter
MCP3208 Connections to raspberry pi
MCP3208 Connections to raspberry pi

The maximum input voltage the ADC’s can sample is 5VDC, so I had to make an adjustable voltage divider network to tune each cell input into the device.

Voltage divider network
Voltage divider network

The sampling rate is user defined.  During the discharge test, results are written to a CSV file which is used later to process the results, and generate the graphs and reports.

To keep the file small, it contains the unix epoch timestamp, sample number, the cell# being sampled,  the binary OP code from the ADC reading, and the voltage relative the negative terminal of the battery plant (calculated from the ADC opcode and some test parameters).

I used the DBD::CSV database driver from cpan to mine data and produce results from the readings contained in the csv file.  I also developed a handy desktop application for testing  that can generate graphs for my device, or any other general purpose csv database.

CSV database analyzer
CSV database analyzer

Below is a graph produced by pid3A of a 350Ah 24-cell VRLA load test that failed about half way through.  You can clearly see that a few cells began failing quickly, and nearly reversed polarity.

VLRA load test results
VLRA load test results

Like I said, this is merely an introduction to the pid3A loadtest analyzer with more to follow.

Here is an incomplete whitepaper I did for the first prototype some time ago.  It shows how far pid3A has come