[Help needed!] using Adafruit-MCP23017-Arduino-Library
Moderators: adafruit_support_bill, adafruit

[Help needed!] using Adafruit-MCP23017-Arduino-Library

by pitchoilcan on Fri May 04, 2012 9:24 am

Hello all, I recently bought a couple of MCP23017 i2c port expanders from adafruit to drive 16 LEDs for my very first arduino project (a newbie). My inputs are 16 (maybe more) piezo sensors connected to the "mux shield". When a piezo is struck it sends a midi Note. So each sensor correlates to a specific note and now I would like to add a LED to each sensor. I had previously tried a pcf8575 breakout board and found it to have a poor design and difficult to use.

Can someone show me how to use the Adafruit-MCP23017-Arduino-Library and http://www.adafruit.com/products/732 MPC23017 to accomplish this.
A perfect example of what I'm trying to do is the midi_footsteps controller, which could be found here: http://www.thebox.myzen.co.uk/Hardware/MIDI_Footsteps.html or the YAAMI-Drum here: http://blog.georgmill.de/2011/03/22/e-drumset-selbst-gebaut/. I've got the multiplexers and midiout working thanks to Grumpy_mike, Crossroads and others in the Arduino forum. And now the final part is to add the LED section. Can anyone help me get this finale piece in place.

The library:
https://github.com/adafruit/Adafruit-MCP23017-Arduino-Library
The data sheet:
http://ww1.microchip.com/downloads/en/devicedoc/21952b.pdf
My wiring:
Image
The sketch goes like this: ( except no muxs are used here, in my actual project I'm using mux-shield i.e. 4051 multiplexers for up to 48 pads and the midi shield for midi OUT ) but you can get the basic idea. It's like a piano with keys that light up or a drum kit with pads that light up on inpact. So noteON = LED on.
Code: Select all | TOGGLE FULL SIZE
/
// DESCRIPTION:
// Arduino analog input used to sense piezo drum hits then sent serialy to processing.

//*******************************************************************************************************************
// User settable variables
//*******************************************************************************************************************

unsigned char PadNote[6] = {52,16,66,63,40,65}; // MIDI notes from 0 to 127 (Mid C = 60)

int PadCutOff[6] = {600,600,600,600,600,600}; // Minimum Analog value to cause a drum hit

int MaxPlayTime[6] = {90,90,90,90,90,90}; // Cycles before a 2nd hit is allowed

#define midichannel 0; // MIDI channel from 0 to 15 (+1 in “real world”)

boolean VelocityFlag = true; // Velocity ON (true) or OFF (false)

//*******************************************************************************************************************
// Internal Use Variables
//*******************************************************************************************************************

boolean activePad[6] = {0,0,0,0,0,0}; // Array of flags of pad currently playing
int PinPlayTime[6] = {0,0,0,0,0,0}; // Counter since pad started to play

unsigned char status;

int pin = 0;
int hitavg = 0;

//*******************************************************************************************************************
// Setup
//*******************************************************************************************************************

void setup()
{
Serial.begin(57600); // connect to the serial port 115200
}

//*******************************************************************************************************************
// Main Program
//*******************************************************************************************************************

void loop()
{
for(int pin=0; pin < 6; pin++)
{
hitavg = analogRead(pin); // read the input pin

if((hitavg > PadCutOff[pin]))
{
if((activePad[pin] == false))
{
if(VelocityFlag == true)
{
// hitavg = 127 / ((1023 – PadCutOff[pin]) / (hitavg – PadCutOff[pin])); // With full range (Too sensitive ?)
hitavg = (hitavg /  -1 ; // Upper range
}
else
{
hitavg = 127;
}

MIDI_TX(144,PadNote[pin],hitavg);
PinPlayTime[pin] = 0;
activePad[pin] = true;
}
else
{
PinPlayTime[pin] = PinPlayTime[pin] + 1;
}
}
else if((activePad[pin] == true))
{
PinPlayTime[pin] = PinPlayTime[pin] + 1;

if(PinPlayTime[pin] > MaxPlayTime[pin])
{
activePad[pin] = false;
MIDI_TX(128,PadNote[pin],127);
}
}
}
}

//*******************************************************************************************************************
// Transmit MIDI Message
//*******************************************************************************************************************
void MIDI_TX(unsigned char MESSAGE, unsigned char PITCH, unsigned char VELOCITY)
{
status = MESSAGE + midichannel;
Serial.print(status);
Serial.print(PITCH);
Serial.print(VELOCITY);
}


}
}

Thanks much.
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by adafruit_support_rick on Sat May 12, 2012 5:53 pm

Have you looked at the examples in the adafruit library? They should be enough to get you going with the port expander.

I can't quite tell from your picture if you've got the port expander chips all wired up on your breadboard, but I'll assume you have.

The adafruit library wraps around the standard arduino Wire library, which handles I2C communication. Using the adafruit library, you should be able to ignore the details of I2C communication, and just use the expander pins as if they were regular arduino pins. Here's the 'toggle' example. As you can see, you declare a variable of type Adafruit_MCP23017 to represent a port expander, and then you simply use that variable to perform the familiar pinMode, digitalRead, and digitalWrite functions.
Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include "Adafruit_MCP23017.h"

// Basic pin reading and pullup test for the MCP23017 I/O expander
// public domain!

// Connect pin #12 of the expander to Analog 5 (i2c clock)
// Connect pin #13 of the expander to Analog 4 (i2c data)
// Connect pins #15, 16 and 17 of the expander to ground (address selection)
// Connect pin #9 of the expander to 5V (power)
// Connect pin #10 of the expander to ground (common ground)

// Output #0 is on pin 21 so connect an LED or whatever from that to ground

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

  mcp.pinMode(0, OUTPUT);
}


// flip the pin #0 up and down

void loop() {
  delay(100);

  mcp.digitalWrite(0, HIGH);

  delay(100);

  mcp.digitalWrite(0, LOW);
}


You say you have two port expanders? In that case, you are going to have to wire them into your circuit such that they have different I2C addresses. Pins 15, 16, and 17 of the expander chip are used to select the chip's address. With all three pins wired to ground, the library will find the chip at address 0. If you tie pin 15 to +5V and leave pins 16 and 17 tied to ground, then that chip will have address 1. You can have up to 8 of these chips on an I2C bus.

I suggest you wire the addresses on your two chips as I've just described, to give your chips addresses 0 and 1.

In your code you would then declare two variables of type Adafruit_MCP23017, one for each chip.

Use the library's begin function to give the library the addresses of the two chips:
Code: Select all | TOGGLE FULL SIZE
#include <Wire.h>
#include "Adafruit_MCP23017.h"

// Blink 2 LEDs using 2 MCP23017 I/O expander chips!
// public domain!

// Connect pin #12 of each expander to Analog 5 (i2c clock)
// Connect pin #13 of each expander to Analog 4 (i2c data)
// Connect pins #15, 16 and 17 of expander 0 to ground (address selection)
// Connect pins #15 of expander 1 to 5V (power) (address selection)
// Connect pins #16 and 17 of expander 2 to ground (address selection)
// Connect pin #9 of each expander to 5V (power)
// Connect pin #10 of each expander to ground (common ground)

// Output #0 is on pin 21. On each expander chip, connect an LED from pin 21 to ground

Adafruit_MCP23017 expander0;
Adafruit_MCP23017 expander1;

void setup() { 
  expander0.begin(0);      // first expander at address 0
  expander1.begin(1);      // second expander at address 1

  expander0.pinMode(0, OUTPUT);  //select expander 0 GPIO zero as output pin
  expander1.pinMode(0, OUTPUT);  //select expander 1 GPIO zero as output pin

}

// alternate blinking led 0 on expander 0 with led 0 on expander 1

void loop() {
  delay(100);

  expander0.digitalWrite(0, HIGH);  //expander 0 LED on
  expander1.digitalWrite(0, LOW);   //expander 1 LED off

  delay(100);

  expander0.digitalWrite(0, LOW);  //expander 0 LED off
  expander1.digitalWrite(0, HIGH); //expander 1 LED on

}


Hope this helps you get started!

(famous last words: I don't have one of these chips, so I haven't tested the code. But it ought to be pretty close to right!)

adafruit_support_rick
 
Posts: 13730
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

GPIOn register pin-pong

by pitchoilcan on Sun May 13, 2012 11:04 am

Thanks much!
[Ralph is confident he will inherit $40 million after he starts his own fictional company which Norton is a stockholder in]
Ed Norton: Thirty-five percent of the 40 million dollars belongs to the stockholders.

Ralph Kramden: [to Norton] I'm gonna become a corporation. Do you know what a corporation is?
Ed Norton: Yeah, I know what a corporation is. When a person or group of persons duly authorized to sell, distribute shares, become avowed with the intention of the stockholders grouping about together, with those shares with the intention of selling the shares, comes to an evil interest there.
Ralph Kramden: [pause] How did you know that?
Ed Norton: Ever heard of Merrill, Lynch, Pierce, Pierce and Bean?
Ralph Kramden: Yes.
Ed Norton: They got an office right outside a downtown sewer I work in.
Last edited by pitchoilcan on Tue May 22, 2012 1:27 pm, edited 2 times in total.
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

addr:IOCON.SEQOP(Control Byte), IOCON.BANK(Control Bit), read OLATn, write GPIOn

by pitchoilcan on Mon May 14, 2012 1:41 am

I be lovin' me some Adafu.it Libraries!
[url]http://arduino.cc/forum/index.php/topic,104672.msg793498.html#msg793498[url][/url][/url]

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. http://tronixstuff.wordpress.com/2011/0 ... -io-ports/
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 ad 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 ?
https://github.com/adafruit/Adafruit-MC ... no-Library
Thanks much!
Last edited by pitchoilcan on Sat May 19, 2012 2:25 pm, edited 1 time in total.
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by adafruit_support_rick on Mon May 14, 2012 11:30 am

First of all, the 4.7K ohm resistors are called "pull-up" resistors. What they do is ensure that the SDA and SCL lines transition sharply and cleanly between their high and low states. Your circuit will sort-of work without them, but it won't necessarily work reliably. If you've removed them, I can see where that could lead to some of your other problems.

If it wasn't working for you with the pull-ups installed, you probably want to try it again, making sure that you've got the right resistor values and that you have them connected to the proper pins. (4700 ohm resistors will be color coded yellow/violet/red, followed by either gold or silver).

Without looking at your code, it's hard to say why you would only be getting one LED blinking in your knight-rider demo. You don't want to be chaining pin mode to make the lights blink. You should set those once in setup and then forget about them

You could certainly use writeGPIOAB instead of digitalWrite. If you do that, be aware that you will always be writing the state of all the pins. If you only want to change the state of one pin, you will have to know the states of the other 15 so that you can write them back unchanged.

This is, in fact, exactly what digitalWrite does for you. When you call digitalWrite, if first calls the equivalent of readGPIOAB to get the current state of all the pins into a uint16_t. In there, it changes the single bit representing the pin you want to change, and then it writes the resulting uint16_t back out by the equivalent of writeGPIOAB.

That's a long way of saying that there's no particularly good reason for you to use writeGPIOAB 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.

adafruit_support_rick
 
Posts: 13730
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

address internal pulllUp resistor, [GGPU] [GPINTEN] [GPIO]

by pitchoilcan on Mon May 14, 2012 3:09 pm

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 to be polyphonic.
Thank again. Your post are very clear. Go Yankees! Who needs the moon? I've god New York City, baby! YEAH! :)
Last edited by pitchoilcan on Sat May 19, 2012 2:24 pm, edited 3 times in total.
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Adafruit_MCP23017.cpp [ab] GPIOn & OLATn addressing

by pitchoilcan on Sat May 19, 2012 2:20 pm

User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by adafruit_support_rick on Sat May 19, 2012 2:58 pm

I'm afraid you lost me a long time ago. But I get the sense that you don't really understand binary arithmetic well enough to use writeGPIOAB().

Why don't you keep it simple and just try to get something working with digitalWrite()?

adafruit_support_rick
 
Posts: 13730
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by pitchoilcan on Sat May 19, 2012 5:33 pm

Hex Value
0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0A 0x0B 0x0C 0x0D 0x0E 0x0F
Binary Value
0000_0000 0000_0001 0000_0010 0000_0011 0000_0100 0000_0101 0000_0110 0000_0111 0000_1000 0000_1001 0000_1010 0000_1011 0000_1100 0000_1101 0000_1110 0000_1111
Hex Value
0x10 0x20 0x30 0x40 0x50 0x60 0x70 0x80 0x90 0xA0 0xB0 0xC0 0xD0 0xE0 0xF0 0xFF
Binary Value
0001_0000 0010_0000 0011_0000 0100_0000 0101_0000 0110_0000 0111_0000 1000_0000 1001_0000 1010_0000 1011_0000 1100_0000 1101_0000 1110_0000 1111_0000 1111_1111
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by adafruit_support_rick on Sat May 19, 2012 5:46 pm

That's fine. But to use writeGPIOAB, you need to know how to set and clear individual bits in there.

Let's say your've got LEDs 1, 7, 9, and 14 lit up. Now, you want to also light up LED 12, but turn off LED 7. Do you know how to do that?

adafruit_support_rick
 
Posts: 13730
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by pitchoilcan on Sat May 19, 2012 6:49 pm

NO. not yet. Pondering............
All I know at this point is that the left side is input while the right side is output. That's the way I understand it at this point. If you can shed any light on this matter please do.
thanks in advance.
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by adafruit_support_rick on Sat May 19, 2012 8:17 pm

That's why I suggest you stick with digitalWrite.
The answer to the problem I posed then becomes simple:
Code: Select all | TOGGLE FULL SIZE
mcp.digitalWrite(12, HIGH);
mcp.digitalWrite(7, LOW);

Let the MCP23017 library take care of all the arithmetic and maintain the current status of all the other LEDs.

adafruit_support_rick
 
Posts: 13730
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by pitchoilcan on Sun May 20, 2012 9:44 am

============
pondering
Code: Select all | TOGGLE FULL SIZE
void Adafruit_MCP23017::digitalWrite(uint8_t p, uint8_t d) {
  uint8_t gpio;
  uint8_t gpioaddr, olataddr;

OK so there is a function called digtalWrite in the library, how does it differ from WriteGPIOAB?
Is it that one write to the port and the other writes to the latches?
Thanks mate!
Image
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am

Re: [Help needed!] using Adafruit-MCP23017-Arduino-Library

by adafruit_support_rick on Sun May 20, 2012 3:55 pm

writeGPIOAB writes all 16 port pins at once. digitalWrite writes to individual pins without changing the states of the other pins.
In this case, "latches" and "port pins" mean the same thing. When you write to a "pin", you're in fact setting a "latch".

adafruit_support_rick
 
Posts: 13730
Joined: Tue Mar 15, 2011 11:42 am
Location: Buffalo, NY

Very Helpful!

by pitchoilcan on Sun May 20, 2012 4:10 pm

I see.
Thanks again.
8)
[Ralph and Norton go to the IRS and sees Richard Puder]
Richard Puder: Which one of you gentlemen is Kramden?
Norton: He's Kramden, I'm clean.
Last edited by pitchoilcan on Tue May 22, 2012 10:42 am, edited 1 time in total.
User avatar
pitchoilcan
 
Posts: 23
Joined: Tue Apr 24, 2012 10:18 am