Slice of PI/O
(Purchased from Ciseco who based it on an original idea by Nathan Chantrell)
Contents
The Basic Kit
|
|
|
Two files needed to be edited3 to enable Raspbian Wheezy's i2c support:
pi@raspired ~ $ more /etc/modprobe.d/raspi-blacklist.conf # blacklist spi and i2c by default (many users don't need them) blacklist spi-bcm2708 #blacklist i2c-bcm2708
pi@raspired ~ $ more /etc/modules # /etc/modules: kernel modules to load at boot time. # # This file contains the names of kernel modules that should be loaded # at boot time, one per line. Lines beginning with "#" are ignored. # Parameters can be specified after the module name. snd-bcm2835 i2c-dev
Then install i2c-tools and add user "pi" (or equivalent) to the "i2c" group to use them:
pi@raspired ~ $ id uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),106(netdev),111(lpadmin),115(i2c),999(input)
Check that the MCP23017 appears at the correct i2c address (0x20):
pi@raspired ~ $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: 20 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
"Piggy-back" Boards
Bargraph Display
Power indicator and 10-LED Bargraph boards: |
|
|
|
More detailed views of the "Piggy-Back" boards etc.: |
|
|
Here is an example bash script to drive the bargraph LEDs:
pi@raspired ~ $ more bar_test2.sh #!/bin/bash #Slice of PI/O Bar Test 2 #Set Bank A to be outputs i2cset -y 1 0x20 0x00 0x00 #Set Bank B to be outputs i2cset -y 1 0x20 0x01 0x00 #Set A bits ... i2cset -y 1 0x20 0x12 0x40 sleep 1 i2cset -y 1 0x20 0x12 0xc0 sleep 1 #Set B bits ... i2cset -y 1 0x20 0x13 0x80 sleep 1 i2cset -y 1 0x20 0x13 0xc0 sleep 1 i2cset -y 1 0x20 0x13 0xe0 sleep 1 i2cset -y 1 0x20 0x13 0xf0 sleep 1 i2cset -y 1 0x20 0x13 0xf8 sleep 1 i2cset -y 1 0x20 0x13 0xfc sleep 1 i2cset -y 1 0x20 0x13 0xfe sleep 1 i2cset -y 1 0x20 0x13 0xff sleep 10 #Clear both banks i2cset -y 1 0x20 0x12 0x00 i2cset -y 1 0x20 0x13 0x00
Snapshots of the working Bargraph Display: |
|
|
|
(A longer sequence can be seen here ...)
8-digit, 7-segment display (Original board)
Recycling a nearly 30 year old, 8-digit, 7-segment display from a Sinclair Cambridge calculator4 |
|
|
|
|
|
8-digit, 7-segment display (Revised board, 21.05.2103)
|
|
|
Multiplexing the 8-digit, 7-seg. display
The current demonstration/test program relies heavily upon Gordon@Drogan's wiringPi library. Before installing that, the libi2c-dev library is also needed to ensure that wiringPi's I2C library is installed too:
sudo apt-get install libi2c-dev
Working Display
|
|
Code Snippits
The code is built using autotools methods, detecting whether wiringPi's I2C library is available and defining "HAVE_WIRINGPII2C_H" in config.h to show this. Below is a snippit of the "wrapper" around wiringPiI2CWriteReg8() - because the demo program can also use i2ctools-based methods via 'C' system calls, "wrappers" are used so that diagnostics can be echoed without full execution and, thus, check data flow etc., eg. the state of the qx flag in the routine below.
#ifdef HAVE_WIRINGPII2C_H typedef struct { int did; int fd; int reg; int data; } wpi2cvb; /* WiringPiI2C Variables Block */ wpi2cvb i2c; void WP_i2cset(wpi2cvb wpi2c, char qx) { int lflag; if (qx) { if ((lflag = wiringPiI2CWriteReg8(wpi2c.fd, wpi2c.reg, wpi2c.data)) < 0) { fprintf(stderr, "wiringPiI2CWriteReg8 failed ... "); perror("wiringPiI2CWriteReg8"); } } else printf("wiringPiI2CWriteReg8: fd=%d reg=0x%02x data=0x%02x\n", wpi2c.fd, wpi2c.reg, wpi2c.data); } #endif /* HAVE_WIRINGPII2C_H */
/* Things that might become sopio.h/sopio.c */ /* >>> */ typedef struct { unsigned int addr; unsigned int iocon; unsigned int iodira; unsigned int iodirb; unsigned int gpioa; unsigned int gpiob; } mcp23017; mcp23017 sopio; #define ALL_GPIO_BITS_OUT 0x00 #define ALL_GPIO_BITS_IN 0xff #define ALL_GPIO_BITS_LOW 0x00 #define ALL_GPIO_BITS_HIGH 0xff int init_sopio(unsigned int sopio_addr) { unsigned int lca; lca = 0x20; if (sopio_addr > 0) lca = sopio_addr; if (lca > 0xff) return(0); sopio.addr = lca; sopio.iocon = 0x0a; /* assumes IOCON.BANK = 0 on power-on reset */ sopio.iodira = 0x00; /* ditto */ sopio.iodirb = 0x01; /* ditto */ sopio.gpioa = 0x12; /* ditto */ sopio.gpiob = 0x13; /* ditto */ return(lca); } void echo_mcp23017_status(mcp23017 chip) { printf("mcp23017 chip status:\n"); printf("ADDR %02x\n", chip.addr); printf("IOCON %02x\n", chip.iocon); printf("IODIRA %02x\n", chip.iodira); printf("IODIRB %02x\n", chip.iodirb); printf("GPIOA %02x\n", chip.gpioa); printf("GPIOB %02x\n", chip.gpiob); } /* <<< */
/* Things that might become sevenseg.h/sevenseg.c */ /* (multiplexed) SEVEN SEGment display tools */ /* >>> */ int codes7seg[19]; /* 16 (hex) digits + All on/off + d.p. */ void init_codes7seg(void) /* Common cathode LED display - Anode (high-level) hex codes */ { codes7seg[ 0] = 0x3f; codes7seg[ 1] = 0x06; codes7seg[ 2] = 0x5b; codes7seg[ 3] = 0x4f; codes7seg[ 4] = 0x66; codes7seg[ 5] = 0x6d; codes7seg[ 6] = 0x7d; codes7seg[ 7] = 0x07; codes7seg[ 8] = 0x7f; codes7seg[ 9] = 0x67; codes7seg[10] = 0x5f; codes7seg[11] = 0x7c; codes7seg[12] = 0x58; codes7seg[13] = 0x5e; codes7seg[14] = 0x7b; codes7seg[15] = 0x71; codes7seg[16] = 0x00; /* All off */ codes7seg[17] = 0xff; /* All on */ codes7seg[18] = 0x80; /* Decimal Point */ } int cathode[10]; void init_cathodes(void) /* 8 digits from left to right */ { cathode[0] = 0xff; /* All disabled */ cathode[1] = 0x7f; cathode[2] = 0xbf; cathode[3] = 0xdf; cathode[4] = 0xef; cathode[5] = 0xf7; cathode[6] = 0xfb; cathode[7] = 0xfd; cathode[8] = 0xfe; /* NB: May not have a d.p. */ cathode[9] = 0x00; /* All enabled */ } typedef struct { int poll; int data; int dcode; } mxdigit; /* Multi-pleXed DIGIT */ mxdigit sevenseg[8]; void init_sevenseg(void) { /* All blank and off */ short int i; init_codes7seg(); init_cathodes(); for (i=0; i<8; i++) { sevenseg[i].poll = cathode[0]; sevenseg[i].data = -1; /* ie. undefined */ sevenseg[i].dcode = codes7seg[16]; } } int load_sevenseg_digit(int index, int dpflag, int value) /* LOAD a SEVEN SEGment DIGIT from left to right */ /* dpflag < 0 assigns Decimal Point */ { int lidx,nidx; int lval; lidx = (index-1) % 8; nidx = lidx + 1; sevenseg[lidx].poll = cathode[nidx]; lval = (int)(value % 10); sevenseg[lidx].data = lval; sevenseg[lidx].dcode = codes7seg[lval]; if (dpflag < 0) sevenseg[lidx].dcode = codes7seg[lval] + codes7seg[18]; nidx--; return(nidx); } /* <<< */
#ifdef HAVE_WIRINGPII2C_H if (i2cmode == WPIMODE) { printf("Using wiringPiI2C methods: ...\n"); i2c.did = (int)(sopio.addr); if ((i2c.fd=wiringPiI2CSetup(i2c.did)) < 0) { fprintf(stderr, "Could not setup i2c.did %d!", i2c.did); perror("wiringPiI2CSetup"); exit(EXIT_FAILURE); } else printf("I2C Device 0x%2x has i2c.fd of %d\n", i2c.did, i2c.fd); /* Common initialisation ... */ i2c.reg = (int)(sopio.iodira); i2c.data = ALL_GPIO_BITS_OUT; WP_i2cset(i2c, xflag); i2c.reg = (int)(sopio.iodirb); i2c.data = ALL_GPIO_BITS_OUT; /* Test code follows ... */ switch(tstmode) { ... case D7MXTST: { i2c.reg = (int)(sopio.gpioa); i2c.data = codes7seg[16]; WP_i2cset(i2c, xflag); i2c.reg = (int)(sopio.gpiob); i2c.data = cathode[0]; WP_i2cset(i2c, xflag); init_sevenseg(); mxc = 800; if (!xflag) mxc=1; for (l=mxc; l>0; l--) { i=8; do { k = load_sevenseg_digit(i, 1, i); i2c.reg = (int)(sopio.gpioa); i2c.data = sevenseg[k].dcode; WP_i2cset(i2c, xflag); i2c.reg = (int)(sopio.gpiob); i2c.data = sevenseg[k].poll; WP_i2cset(i2c, xflag); delay(5); i--; } while(k>0); } i2c.reg = (int)(sopio.gpioa); i2c.data = codes7seg[16]; WP_i2cset(i2c, xflag); i2c.reg = (int)(sopio.gpiob); i2c.data = cathode[0]; WP_i2cset(i2c, xflag); break; } ... default: break; } } #endif /* HAVE_WIRINGPII2C_H */