Addressing 23017/4051 using I2C Serial Interface & PROGMEM

If you are using the Centipede library then your mapping should be easier.

As Grumpy_Mike says, you can pretty much forget that you have the hardware there and just turn on the output you need using the correct functions in the CS library, so you really need to read the library documentation and code examples.

As I don't have experience with the libraries I'll watch from the sidelines and learn (He's probably in a better time zone anyway).

Not a bad tutorial- [using just the wire library] [ Two's complement ] the 23017 data sheet again http://ww1.microchip.com/downloads/en/DeviceDoc/21952b.pdf
tronixstuff 230x1 tutorial revisited:
Tutorial: Maximising your Arduino’s I/O ports with MCP23017 | tronixstuff.com
Now to examine how to use the IC in our sketches. As you should know by now most I2C devices have several registers that can be addressed. Each address holds one byte of data that determines various options. With the MCP23017 the registers can be ordered in one of two ways – see tables 1.3 and 1.4 on page nine of the data sheet. In our examples we will use the addresses listed on table 1.4. So the first command to use in void setup() is:

  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();

The next is to set the I/O ports as inputs or outputs. First we will work with outputs. When the MCP23017 is turned on or reset, it defaults to inputs so we need to change them. So we use:

  Wire.beginTransmission(0x20);
  Wire.send(0x00); // IODIRA register
  Wire.send(0x00); // set all of bank A to outputs
  Wire.send(0x00); // set all of bank B to outputs
  Wire.endTransmission();

Go back to the data sheet and see table 1.4. Notice how we started with the IODIRA (“I/O direction, bank A”) register at 0×00 and sent two bytes? You can do this without having to separate address the second register. This only works when the registers have sequential addresses, as in this example we wanted a byte to go to 0×00 then 0×01. We sent zero which in binary is 00000000 – each bit refers to one output of the bank and refers to I/O pins 7~0.
So now we are in void loop() or a function of your own creation and want to control some output pins. To control bank A, we use:

  Wire.beginTransmission(0x20);
  Wire.send(0x12); // address bank A
  Wire.send(??);  // value to send
  Wire.endTransmission();

replacing ?? with the binary or equivalent hexadecimal or decimal value to send to the register. To calculate the required number, consider each I/O pin from 7 to 0 matches one bit of a binary number – 1 for on, 0 for off. So you can insert a binary number representing the output levels. Or if binary does your head in, convert it to hexadecimal. So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0×82, or 130 decimal. (Using decimals is convenient if you want to display values from an incrementing value or function result).

If you had some LEDs via resistors connected to the outputs, you would have this as a result of sending 0×82:

Now if you want to address all the outputs at once, just send the byte for bank B after bank A. For example, we want bank A to be 11001100 and bank B to be 10001000 – so we send the following:

Wire.beginTransmission(0x20);
  Wire.send(0xCC); // address bank A
  Wire.send(0x88); // address bank B
  Wire.endTransmission();

… with the results as such (bank B on the left, bank A on the right):

You can also just address bank B, if so bank A does not change. Now let’s put all of this output knowledge into a more detailed example. From a hardware perspective we are using a circuit as described above, with the addition of a 560 ohm resistor followed by an LED thence to ground from on each of the sixteen outputs. Here is the sketch (download):

Example 41.1

/*
 Example 41.1 - Microchip MCP23017 with Arduino
 http://tronixstuff.wordpress.com/tutorials > chapter 41
 John Boxall | CC by-sa-nc
*/

// pins 15~17 to GND, I2C bus address is 0x20

#include "Wire.h"

void setup()
{
  Wire.begin(); // wake up I2C bus

  // setup addressing style
  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();

  // set I/O pins to outputs
  Wire.beginTransmission(0x20);
  Wire.send(0x00); // IODIRA register
  Wire.send(0x00); // set all of bank A to outputs
  Wire.send(0x00); // set all of bank B to outputs
  Wire.endTransmission();
}

void binaryCount()
{
  for (byte a=0; a<256; a++)
  {
    Wire.beginTransmission(0x20);
    Wire.send(0x12); // GPIOA
    Wire.send(a);    // bank A
    Wire.send(a);    // bank B
    Wire.endTransmission();
    delay(100);
  }
}

void loop()
{
  binaryCount();
  delay(500);
}

And here is the example blinking away:

Although that may have seemed like a simple demonstration, it was created show how the outputs can be used. So now you know how to control the I/O pins set as outputs. Note that you can’t source more than 25 mA of current from each pin, so if switching higher current loads use a transistor and an external power supply and so on.

Now let’s turn the tables and work on using the I/O pins as digital inputs. The MCP23017 I/O pins default to input mode, so all we need to do is set the addressing method as such in void setup()

 // setup addressing style
  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();

To Hex, or not to hex?.... [table A or table B][c or d]
An alternative conversion process

A shortcut to manually convert a binary number into its two's complement is to start at the least significant bit (LSB), and copy all the zeros (working from LSB toward the most significant bit) until the first 1 is reached; then copy that 1, and flip all the remaining bits. This shortcut allows a person to convert a number to its two's complement without first forming its ones' complement. For example: the two's complement of "0011 1100" is "1100 0100", where the underlined digits were unchanged by the copying operation (while the rest of the digits were flipped).
In computer circuitry, this method is no faster than the "complement and add one" method; both methods require working sequentially from right to left, propagating logic changes. The method of complementing and adding one can be sped up by a standard carry look-ahead adder circuit; the alternative method can be sped up by a similar logic transformation.

source: Two's complement - Wikipedia
defining the LED and Note bits like so:

if(midiNote == 64) ledBits |= 0x1;
if(midiNote == 65) ledBits |= 0x2;
if(midiNote == 66) ledBits |= 0x4;
if(midiNote == 67) ledBits |= 0x8;
if(midiNote == 68) ledBits |= 0x10;

the same goes for turning the LED off:-

if(midiNote == 64) ledBits &= ~0x1;
if(midiNote == 65) ledBits &= ~0x2;
if(midiNote == 66) ledBits &= ~0x4;
if(midiNote == 67) ledBits &= ~0x8;
if(midiNote == 68) ledBits &= ~0x10;

Pointers and integers are two different things which is why you are stopped form doing that. It has no meaning, like comparing the address of a house to the house itself.

What are you trying to do?

//Table 1-2 (0)
if(PadNote == 60) ledBits |= 0x01;
if(PadNote == 61) ledBits |= 0x02;
if(PadNote == 62) ledBits |= 0x03;
if(PadNote == 63) ledBits |= 0x04;
if(PadNote == 64) ledBits |= 0x05;

  • // the same goes for turning the LED off:-*
    if(PadNote == 60) ledBits &= ~0x01;
    if(PadNote == 61) ledBits &= ~0x02;
    if(PadNote == 62) ledBits &= ~0x03;
    if(PadNote == 63) ledBits &= ~0x04;
    if(PadNote == 64) ledBits &= ~0x05;
    > In mathematics and computer science, hexadecimal (also base 16, or hex) is a positional numeral system with a radix, or base, of 16. It uses sixteen distinct symbols, most often the symbols 0–9 to represent values zero to nine, and A,?B,?C,?D,?E,?F (or alternatively a–f) to represent values ten to fifteen. For example, the hexadecimal number 2AF3 is equal, in decimal, to (2?×?163) + (10?×?162) + (15?×?161) + (3?×?160), or 10,995.
    > Each hexadecimal digit represents four binary digits (bits), and the primary use of hexadecimal notation is a human-friendly representation of binary-coded values in computing and digital electronics. One hexadecimal digit represents a nibble, which is half of an octet (8 bits). For example, byte values can range from 0 to 255 (decimal), but may be more conveniently represented as two hexadecimal digits in the range 00 to FF. Hexadecimal is also commonly used to represent computer memory addresses.
    OK back to my scrapbook
    > 16 (hexadecimal) 0x7B leading "0x" characters 0-9, A-F, a-f valid

padNote is an array of characters (or bytes, probably)

unsigned char PadNote[48] = {35,36,37,38,39,40,41,42,

to access one of the values of padNote you need to reference it using an array index, shown as i in the code below

if (padNote[i] == 99) ledPin |=  0x1;

Just using padNote on it's own, in C++, tells the compiler you are using the address of the array. That is an advanced topic for you to learn later.

void readSensors(int analogPin){
//This for loop is used to scroll through and store the 16 inputs on the FIRST multiplexer
for (int i=0; i<16; i++){
digitalWrite(CONTROL0, (i&15)>>3);
digitalWrite(CONTROL1, (i&7)>>2);
digitalWrite(CONTROL2, (i&3)>>1);
digitalWrite(CONTROL3, (i&1));

//Read and store the input value at a location in the array
if(analogPin==0){
mux0array = analogRead(analogPin);

  • }*
  • else if(analogPin==1){*
    _ mux1array = analogRead(analogPin);_
    * }*
    * else if(analogPin==2){*
    _ mux2array = analogRead(analogPin);
    * }
    //Table 1-2 (0)
    if(PadNote == 60) ledBits |= 0x01;
    if(PadNote == 61) ledBits |= 0x02;
    if(PadNote == 62) ledBits |= 0x03;
    if(PadNote == 63) ledBits |= 0x04;
    if(PadNote == 64) ledBits |= 0x05;
    if(PadNote == 65) ledBits |= 0x06;
    if(PadNote == 66) ledBits |= 0x07;
    if(PadNote == 67) ledBits |= 0x08;
    if(PadNote == 68) ledBits |= 0x09;
    if(PadNote == 69) ledBits |= 0x0A;
    if(PadNote == 70) ledBits |= 0x0B;
    if(PadNote == 71) ledBits |= 0x0C;
    ////if(PadNote == 72) ledBits |= 0x0D;
    ////if(PadNote == 73) ledBits |= 0x0E;
    ////if(PadNote == 74) ledBits |= 0x0F;
    // the same goes for turning the LED off:-
    if(PadNote == 60) ledBits &= ~0x01;
    if(PadNote == 61) ledBits &= ~0x02;
    if(PadNote == 62) ledBits &= ~0x03;
    if(PadNote == 63) ledBits &= ~0x04;
    if(PadNote == 64) ledBits &= ~0x05;
    if(PadNote == 65) ledBits &= ~0x06;
    if(PadNote == 66) ledBits &= ~0x07;
    if(PadNote == 67) ledBits &= ~0x08;
    if(PadNote == 68) ledBits &= ~0x09;
    if(PadNote == 69) ledBits &= ~0x0A;
    if(PadNote == 70) ledBits &= ~0x0B;
    if(PadNote == 71) ledBits &= ~0x0C;
    ////if(PadNote == 72) ledBits &= ~0x0D;
    ////if(PadNote == 73) ledBits &= ~0x0E;
    ////if(PadNote == 74) ledBits &= ~0x0F;
    }
    }*_

added

#include <Centipede.h>
#include <Wire.h>

Centipede ledBits; // create  object

  ledBits.initialize(); // set all registers to default
 
  ledBits.portMode(0, 0b0000000000000000); // set all pins on chip 0 to output

Not I get
twelve of these :

no match for 'operator |=' in 'ledBits |=1'

and
twelve of these :

no match for 'operator &=' in 'ledBits &= -0x0000000002'

How do I resolve this ?

Centipede ledBits; // created an  object

so I need to add:

int pattern =0; //create an interger

and

ledBits.portWrite(0, pattern); // write to port//pin

then change 'if' statements from:

if(PadNote[i] == 64) ledBits |= 0x05; //condition

to

if(PadNote[i] == 64) pattern |= 0x05; //condition

=============
working it out......

//Table 1-4  (BANK=0)
if(PadNote[i] == 60) pattern |= 0x01;
if(PadNote[i] == 61) pattern |= 0x02;
if(PadNote[i] == 62) pattern |= 0x03;
if(PadNote[i] == 63) pattern |= 0x04;
if(PadNote[i] == 64) pattern |= 0x05;

if(PadNote[i] == 65) pattern |= 0x0C;
if(PadNote[i] == 66) pattern |= 0x0D;
if(PadNote[i] == 67) pattern |= 0x12;
if(PadNote[i] == 68) pattern |= 0x13;
if(PadNote[i] == 69) pattern |= 0x14;

if(PadNote[i] == 70) pattern |= 0x15;
//Table 1-3 (BANK=1)
if(PadNote[i] == 71) pattern |= 0x10;
////if(PadNote[i] == 72) pattern |= 0x01;
////if(PadNote[i] == 73) pattern |= 0x11;
////if(PadNote[i] == 74) pattern |= 0x02;

               // the same goes for turning the LED off:-
//Table 1-4 (BANK=0)
if(PadNote[i] == 60) pattern &= ~0x01;
if(PadNote[i] == 61) pattern &= ~0x02;
if(PadNote[i] == 62) pattern &= ~0x03;
if(PadNote[i] == 63) pattern &= ~0x04;
if(PadNote[i] == 64) pattern &= ~0x05;

if(PadNote[i] == 65) pattern &= ~0x0C;
if(PadNote[i] == 66) pattern &= ~0x0D;
if(PadNote[i] == 67) pattern &= ~0x12;
if(PadNote[i] == 68) pattern &= ~0x13;
if(PadNote[i] == 69) pattern &= ~0x14;

if(PadNote[i] == 70) pattern &= ~0x15;
//Table 1-3 (BANK=1)
if(PadNote[i] == 71) pattern &= ~0x10;
////if(PadNote[i] == 72) pattern &= ~0x01;
////if(PadNote[i] == 73) pattern &= ~0x11;
////if(PadNote[i] == 74) pattern &= ~0x02;

http://forums.adafruit.com/viewtopic.php?f=25&t=28254#p145039

// Example code for Centipede Library
// Works with Centipede Shield or MCP23017 on Arduino I2C port
 
#include <Wire.h>
#include <Centipede.h>
 /* Available commands
  .digitalWrite([0...127], [LOW...HIGH]) - Acts like normal digitalWrite
  .digitalRead([0...127]) - Acts like normal digitalRead
  .pinMode([0...127], [INPUT...OUTPUT]) - Acts like normal pinMode
  .portWrite([0...7], [0...65535]) - Writes 16-bit value to one port (chip)
  .portRead([0...7]) - Reads 16-bit value from one port (chip)
  .portMode([0...7], [0...65535]) - Write I/O mask to one port (chip)
  .pinPullup([0...127], [LOW...HIGH]) - Sets pullup on input pin
  .portPullup([0...7], [0...65535]) - Sets pullups on one port (chip)
  .init() - Sets all registers to initial values
 
  Examples
  CS.init();
  CS.pinMode(0,OUTPUT);
  CS.digitalWrite(0, HIGH);
  int recpin = CS.digitalRead(0);
  CS.portMode(0, 0b0111111001111110); // 0 = output, 1 = input
  CS.portWrite(0, 0b1000000110000001); // 0 = LOW, 1 = HIGH
  int recport = CS.portRead(0);
  CS.pinPullup(1,HIGH);
  CS.portPullup(0, 0b0111111001111110); // 0 = no pullup, 1 = pullup
*/
 
Centipede CS; // create Centipede object
 
 void setup()
{
  Wire.begin(); // start I2C
 
  CS.initialize(); // set all registers to default
 
  CS.portMode(0, 0b0000000000000000); // set all pins on chip 0 to output
 
  //TWBR = 12; // uncomment for 400KHz I2C (on 16MHz Arduinos)
 
}
 
 
void loop()
{  
  for (int i = 0; i < 15; i++) {
    CS.digitalWrite(i, HIGH);
    delay(10);
  }
 
  for (int i = 0; i < 15; i++) {
    CS.digitalWrite(i, LOW);
    delay(10);
  } 
}

differs from

#include <Wire.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp; // create mcp object

 void setup() {  
  mcp.begin();      // use default address 0

  mcp.pinMode(0, OUTPUT);
}

void loop()
{  
  for (int i = 0; i < 15; i++) {
    mcp.digitalWrite(i, HIGH);
    delay(10);
  }
 
  for (int i = 0; i < 15; i++) {
    mcp.digitalWrite(i, LOW);
    delay(10);
  } 
}

Cheers!

passeetryagainapril2012.pde (9.75 KB)

so if I'm understanding adafruit.mcp23017.h and adafruit-mcp23017.cpp correctly the chips is reading 8 but writing 16. However I think there are still some changes I need to make to my program for GPIOAB operation

uint16_t Adafruit_MCP23017::readGPIOAB() {
  uint16_t ba = 0;
  uint8_t a;

  // read the current GPIO output latches
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_GPIOA);	
  Wire.endTransmission();
  
  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 2);
  a = wirerecv();
  ba = wirerecv();
  ba <<= 8;
  ba |= a;

  return ba;
}

void Adafruit_MCP23017::writeGPIOAB(uint16_t ba) {
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_GPIOA);	
  wiresend(ba & 0xFF);
  wiresend(ba >> 8);
  Wire.endTransmission();
}

void Adafruit_MCP23017::digitalWrite(uint8_t p, uint8_t d) {
  uint8_t gpio;
  uint8_t gpioaddr, olataddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8) {
    olataddr = MCP23017_OLATA;
    gpioaddr = MCP23017_GPIOA;
  } else {
    olataddr = MCP23017_OLATB;
    gpioaddr = MCP23017_GPIOB;
    p -= 8;
  }

  // read the current GPIO output latches
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(olataddr);	
  Wire.endTransmission();
  
  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
   gpio = wirerecv();

  // set the pin and direction
  if (d == HIGH) {
    gpio |= 1 << p; 
  } else {
    gpio &= ~(1 << p);
  }

  // write the new GPIO
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gpioaddr);
  wiresend(gpio);	
  Wire.endTransmission();
}

void Adafruit_MCP23017::pullUp(uint8_t p, uint8_t d) {
  uint8_t gppu;
  uint8_t gppuaddr;

  // only 16 bits!
  if (p > 15)
    return;

  if (p < 8)
    gppuaddr = MCP23017_GPPUA;
  else {
    gppuaddr = MCP23017_GPPUB;
    p -= 8;
  }


  // read the current pullup resistor set
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gppuaddr);	
  Wire.endTransmission();
  
  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  gppu = wirerecv();

  // set the pin and direction
  if (d == HIGH) {
    gppu |= 1 << p; 
  } else {
    gppu &= ~(1 << p);
  }

  // write the new GPIO
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gppuaddr);
  wiresend(gppu);	
  Wire.endTransmission();
}

uint8_t Adafruit_MCP23017::digitalRead(uint8_t p) {
  uint8_t gpioaddr;

  // only 16 bits!
  if (p > 15)
    return 0;

  if (p < 8)
    gpioaddr = MCP23017_GPIOA;
  else {
    gpioaddr = MCP23017_GPIOB;
    p -= 8;
  }

  // read the current GPIO
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(gpioaddr);	
  Wire.endTransmission();
  
  Wire.requestFrom(MCP23017_ADDRESS | i2caddr, 1);
  return (wirerecv() >> p) & 0x1;
}

from adafruit-mcp23017.cpp

Adafruit_MCP23017.cpp (4.66 KB)

A couple of things, let me start with the wiring. The wiring I used in the knight-rider video style demo I posted earlier came from the troxicstuff website. Tutorial: Maximising your Arduino’s I/O ports with MCP23017 | tronixstuff.com

the sixteen I/O ports are separated into two ‘banks’ – A (on the right) and B (on the left. Pin 9 connects to 5V, 10 to GND, 11 isn’t used, 12 is the I2C bus clock line (Arduino Uno/Duemilanove analogue pin 5, Mega pin 21), and 13 is the I2C bus data line (Arduino Uno/Duemailnove analogue pin 4, Mega pin 20). External pull-up resistors should be used on the I2C bus – in our examples we use 4.7k ohm values. Pin 14 is unused, and we won’t be looking at interrupts, so ignore pins 19 and 20. Pin 18 is the reset pin, which is normally high – therefore you ground it to reset the IC. So connect it to 5V!

I wasn't able to make it work as shown in the diagram however if I removed the point where the sda and scl line are connected to +5v via 4.7ohm resistor it work fine BTY Grumpy_Mike midifoot controller also supplies those line with +5v via resistors. Any thoughts on that and secondly,

as I said before in the Knight-righter demo I used the centipede shield code and library; all the pins turned on/off in SEQUENCE (mode) both banks a and b, 0-16.
I them copy the code modifying if to use the adafruit library but this time only one pin on only one bank is going on/off. I'm thinking

void writeGPIOAB(uint16_t);
uint16_t readGPIOAB();

Any ideas?
I'm thinking that to write the 16 bits I'll need to use GPIOAB rather than pinMode and writeGPIO as far as it concerns the project at hand (16+ piezo inputs/LED outputs) and as far as the centipede sketch using the adafruit library I'm thinking pinMode needs to be changed as well so that all pins 16 pins turn on/off in sequence. Any thoughts ?

Thanks much!

Adafruit_MCP23017.h (1.61 KB)

So I'm sitting here reading Adafruit_MCP23017.cpp

// set defaults!
  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_IODIRA);
  wiresend(0xFF);  // all inputs on port A
  Wire.endTransmission();

  Wire.beginTransmission(MCP23017_ADDRESS | i2caddr);
  wiresend(MCP23017_IODIRB);
  wiresend(0xFF);  // all inputs on port B
  Wire.endTransmission();
}

Why byte b = (byte) 0xFF is equal to integer -1
java - Why byte b = (byte) 0xFF is equals to integer -1? - Stack Overflow

No data direction registers normally are a one for inputs and a zero for outputs.

this is from the tronixstuff
table 1.4. So the first command to use in void setup() is:

  Wire.beginTransmission(0x20);
  Wire.send(0x12);
  Wire.send(0x20); // use table 1.4 addressing
  Wire.endTransmission();

The next is to set the I/O ports as inputs or outputs. First we will work with outputs. When the MCP23017 is turned on or reset, it defaults to inputs so we need to change them. So we use:

Wire.beginTransmission(0x20);
Wire.send(0x00); // IODIRA register
Wire.send(0x00); // set all of bank A to outputs
Wire.send(0x00); // set all of bank B to outputs
Wire.endTransmission();

Go back to the data sheet and see table 1.4. Notice how we started with the IODIRA (“I/O direction, bank A”) register at 0×00 and sent two bytes? You can do this without having to separate address the second register. This only works when the registers have sequential addresses, as in this example we wanted a byte to go to 0×00 then 0×01. We sent zero which in binary is 00000000 – each bit refers to one output of the bank and refers to I/O pins 7~0.
So now we are in void loop() or a function of your own creation and want to control some output pins. To control bank A, we use:

Wire.beginTransmission(0x20);
Wire.send(0x12); // address bank A
Wire.send(??); // value to send
Wire.endTransmission();
… replacing ?? with the binary or equivalent hexadecimal or decimal value to send to the register. To calculate the required number, consider each I/O pin from 7 to 0 matches one bit of a binary number – 1 for on, 0 for off. So you can insert a binary number representing the output levels. Or if binary does your head in, convert it to hexadecimal. So for example, you want pins 7 and 1 on. In binary that would be 10000010, in hexadecimal that is 0×82, or 130 decimal. (Using decimals is convenient if you want to display values from an incrementing value or function result).
Now if you want to address all the outputs at once, just send the byte for bank B after bank A. For example, we want bank A to be 11001100 and bank B to be 10001000 – so we send the following:

Wire.beginTransmission(0x20);
Wire.send(0xCC); // address bank A
Wire.send(0x88); // address bank B
Wire.endTransmission();

The tronixstuff post uses just the wire library, I'll try later to do it using just wire.h like Grummy_Mike does in his midifootsteps controller. Does the MCP23017 have internal pull up resistors?

i2c pullup resistors strictly needed?

So I'm laying out a circuit for an atmega328 and a mcp23017, which is an i2c port expander. If it is just the two components and then downstream (from the port expander) connections, are pullups strictly needed on the i2c lines? Nothing else on the i2c bus except the 328 and the mcp23017. Does the 328 have internal pullups on the i2c bus pins? I'm asking because I just send off a board design for prototypes and had a doh forehead slap moment when I noticed I'd left off the 4k7 pullups on the i2c bus. I'll greenwire up some pullups if they're absolutly needed for these prototypes, but was just wondering if the i2c comms would work well enough without them on there. I've already added them to the schematic and reworked the layout and will be sending off for another set of prototypes, but was just curious.

Thanks.

Please note that in my sketch the arduino pre-scaler is modified for drum rolls would that have a direct affect on the i2c bus ?

The internal pullups are a much higher resistance and won't work well at high speeds.

http://forums.adafruit.com/viewtopic.php?f=8&t=27328
so they do have internal pull ups? Again I ask this question because with external resistors wired in place my Knight rider example does not work. without them the example works.
note that in midi footsteps the polarity is reversed on the i/o pins :0

Does the MCP23017 have internal pull up resistors?

No.
Read this as to why you need them.

A 4K7 (or 4.7K) has the colours yellow violet red.

Your problem is that you tend to be a bit grasshopper like and keep changing what you want to do and the way you want to do it. Instead of working at something and getting it going you flit from solution to solution, never seeing any one through. If you don't stick with one approach you will never succeed with any. All you are doing is swapping one set of problems for another without getting any foundation in anything.

This is why I suggest you stick with the centipede library, at least you have something working with that and your hardware. So start with the knight rider sketch because that works. Now what appears not to work for you is the port write command. So take the working sketch and change the bit that outputs the LEDs to use the port write, can you get that to work? If not find out why, read the library instructions, look at the examples and see what you need to make it work. Then when you have got to a situation where all 16 bits of an integer can be output in one port write command, only then look to incorporate it into your drum code.
The secrete is to take simple small steps one at a time, and see each step working before moving on to the next. Keep getting closer and closer to what you want to happen. Predict what your changes will achieve and make it happen.

if the resistors are an issue (I'm still digesting 'effects of varing i2c pull-up resistors)...

CS.portMode(0, 0b0000000000000000);
The b suffix for byte will only work with 8 bit values. Please use hex when you want to specify a bit pattern.

.Source: Pacitcal Arduino - the book

this approach to outputs doesn't come freely. As you have probably guessed, each update to the output pins will take a dozen instruction being executed bt the CPU to clock data out rather than a single write to the relevant port. However if the internal UART is used in SPI mode, this over load is reduced.

========
UART or USART

All Arduino boards have at least one serial port (also known as a UART or USART): Serial. It communicates on digital pins 0 (RX) and 1 (TX) as well as with the computer via USB. Thus, if you use these functions, you cannot also use pins 0 and 1 for digital input or output.

when looking into cascading multiple shift regs.
also the 5955s require 4 pins scl, sda Q latch, (OE is optional).

Digital Input/Output Expansion
The Arduino has 20 general-purpose I/O pins, which is more than enough for most projects. However,
there are situations where more inputs or outputs are required. By making use of the Arduino’s SPI
support, we can use a simple logic element—a shift register—to provide virtually unlimited digital input
or output capabilities.
Shift Registers As Outputs
When using a shift register to provide outputs, we must provide three signals from the Arduino: clock
(CLK), data (D), and latch (Q). We might also want to provide an output enable (OE) signal so that the
outputs remain off until we initialize them properly.

CHAPTER 16
Taking the example in Figure 16-7, we have a single eight-output serial in parallel out shift
register/latch connected to the Arduino. To set Output 3 high and all other outputs low, we would set D
low, transition CLK Low-High four times, set D high, transition CLK Low-High once, set D low again,
then transition CLK a further three times. Thus, we “shift” in the sequence 00001000 into the register.
Finally, we transition the Q (latch) signal Low-High-Low to move this new pattern to the output pins
themselves.

Figure 16-8. Cascading multiple shift registers for more output pins
This approach to outputs doesn’t come entirely free. As you’ll probably have guessed, each update
to the output pins will take a few dozen instructions being executed by the CPU to clock the data out
rather than a single write to the relevant port. However, if the Arduino’s internal UART is used in SPI
mode, this overhead can be reduced.
For practical applications, there are at least a few devices to consider. The 74HC595 is a basic logic
level serial in/parallel out shift register. It’s good for about 20mA per pin tops, and is inexpensive and
easy to find. A little more expensive, but more versatile, is the TPIC6595, which is essentially a 74HC595
and ULN2003 combined. It’s a serial in/parallel out shift register with high current drivers—about
200mA per pin.

Please note again that my ADC prescaler is modified in the drum sketch
practical arduino -The book [page 198] [How Successive Approximation ADC Works]

also looking into;
isolated and non isolated inputs
before I move on to the big kahuna DSP. with 12 bit DAC
lol
there were five in pack, I used the two. XD

pondering

change:
CS.portMode(0, 0b0000000000000000); // set all pins on chip 0 to output
to
CS.portWrite(0x00, 0x00); // set all pins on chip 0 to output

and

CS.digitalWrite(i, HIGH);
CS.digitalWrite(i, LOW);
to
CS.portWrite(i, 0x01);
CS.portWrite(i, 0x00); /

I'm very emotional right now :roll_eyes:

see HEX/Binary values:
http://wwweng.uwyo.edu/electrical/research/FroshECE/Microp/MicroprocessorsPORTHandout.pdf

[NOT wasting TIME!] in good ole DIY fashion I think I wouldn't get the cs shield and continue to support good old Made in America! Thank you for your support. :grin:
.IT isn't so bad.

Adafru.it :%
http://forums.adafruit.com/viewtopic.php?f=25&t=28254&p=145202#p145202

if you only want to change one pin at a time. But, if you already keep track of all the pins states anyway, and/or you want to be changing more than one pin at a time, then you definitely want to use writeGPIOAB.

XD
cool!
Polyphonic vs. monophonic, I diffidently want it to be polyphonic. I believe Grummpy_Mike saves his readings in PROGMEM; (current val) and (last val) (midi footsteps controller).
thanks much!

pondering...........
http://www.kernel.org/doc/Documentation/gpio.txt

I know that Grummpy_Mike saved his readings in eeprom;

No I don't.