[FrontPage] [TitleIndex] [WordIndex

Slice of PI/O

(Purchased from Ciseco who based it on an original idea by Nathan Chantrell)

The Basic Kit

Assembled board1 fitted into raspired:

DSCN0771s.jpg

DSCN0778cs.jpg

Assembled board1 "close-up"2:

DSCN0773cs.jpg DSCN0774cs.jpg
NB: Full build and assembly instructions are provided by Ciseco here.

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:

DSCN0784crs.jpg

More detailed views of the "Piggy-Back" boards etc.:

DSCN0786cs.jpg
DSCN0787cs.jpg DSCN0788cs.jpg

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:

DSCN0789rcs.jpg

DSCN0790cs.jpg

(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

DSCN0807cs.jpg

DSCN0808cs.jpg
DSCN0810cs.jpg

DSCN0806s.jpg

DSCN0805s.jpg

8-digit, 7-segment display (Revised board, 21.05.2103)

DSCN0923cs.jpg

DSCN0924cs.jpg

DSCN0925cs.jpg

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

DSCN0836cs.jpg

DSCN0836rcs.jpg

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 */


  1. Brown "Molex" 4-way socket not supplied by Ciseco (1 2)

  2. MPC23017 address selection pins all tied low to GND (3)

  3. This was before I2C support was enabled via raspi-config etc. (4)

  4. Built from a kit in the mid-1970's (5)


2024-02-11 21:50