Hi Nick!
Always a big pleasure visit your site, it's always full of useful informations!
I'm trying to use your code for the MCP23017 for the SPI version of the same chip, the MCP23S17. Reading your notes about SPI I have modified like the following to use both chip for experiments:
#include <SPI.h>
#include "pins_arduino.h"
// Author: Nick Gammon
// Date: 20 February 2011
// Demonstration of an interrupt service routine connected to the MCP23017
#include <Wire.h>
// MCP23017 registers (everything except direction defaults to 0)
#define SS 53 //I'm using arduinoMega2560
#define IODIRA 0x00 // IO direction (0 = output, 1 = input (Default))
#define IODIRB 0x01
#define IOPOLA 0x02 // IO polarity (0 = normal, 1 = inverse)
#define IOPOLB 0x03
#define GPINTENA 0x04 // Interrupt on change (0 = disable, 1 = enable)
#define GPINTENB 0x05
#define DEFVALA 0x06 // Default comparison for interrupt on change (interrupts on opposite)
#define DEFVALB 0x07
#define INTCONA 0x08 // Interrupt control (0 = interrupt on change from previous, 1 = interrupt on change from DEFVAL)
#define INTCONB 0x09
#define IOCON 0x0A // IO Configuration: bank/mirror/seqop/disslw/haen/odr/intpol/notimp
//#define IOCON 0x0B // same as 0x0A
#define GPPUA 0x0C // Pull-up resistor (0 = disabled, 1 = enabled)
#define GPPUB 0x0D
#define INFTFA 0x0E // Interrupt flag (read only) : (0 = no interrupt, 1 = pin caused interrupt)
#define INFTFB 0x0F
#define INTCAPA 0x10 // Interrupt capture (read only) : value of GPIO at time of last interrupt
#define INTCAPB 0x11
#define GPIOA 0x12 // Port value. Write to change, read to obtain value
#define GPIOB 0x13
#define OLLATA 0x14 // Output latch. Write to latch output.
#define OLLATB 0x15
#define chip1 0x20 // MCP23017 is on I2C address 0x20
volatile boolean keyPressed;
// set register "reg" on expander to "data"
// for example, IO direction
void expanderWriteBoth (const byte address, const byte reg, const byte data )
{
if (SS>0){
digitalWrite(SS, LOW);
SPI.transfer (reg);
SPI.transfer (data);
SPI.transfer (data);
digitalWrite(SS, HIGH);
}
else {
Wire.beginTransmission (address);
Wire.send (reg);
Wire.send (data); // port A
Wire.send (data); // port B
Wire.endTransmission ();
}
} // end of expanderWrite
// read a byte from the expander
unsigned int expanderRead (const byte address, const byte reg)
{
unsigned int data = 0;
if (SS>0){
digitalWrite(SS, LOW);
SPI.transfer (reg);
digitalWrite(SS, HIGH);
digitalWrite(SS, LOW);
data = SPI.transfer (0);
digitalWrite(SS, HIGH);
}
else {
Wire.beginTransmission (address);
Wire.send (reg);
Wire.endTransmission ();
Wire.requestFrom (address, (byte) 1);
data = Wire.receive();
}
return data;
} // end of expanderRead
// interrupt service routine, called when pin D2 goes from 1 to 0
void keypress ()
{
keyPressed = true; // set flag so main loop knows
} // end of keypress
void setup ()
{
Serial.begin (38400);
if (SS>0){
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8);
digitalWrite(SS, HIGH);
}
else {
Wire.begin ();
}
// expander configuration register
expanderWriteBoth (chip1, IOCON, 0b01100100); // mirror interrupts, disable sequential mode, open drain
// enable pull-up on switches
expanderWriteBoth (chip1, GPPUA, 0xFF); // pull-up resistor for switch - both ports
// invert polarity
expanderWriteBoth (chip1, IOPOLA, 0xFF); // invert polarity of signal - both ports
// enable all interrupts
expanderWriteBoth (chip1, GPINTENA, 0xFF); // enable interrupts - both ports
// no interrupt yet
keyPressed = false;
// read from interrupt capture ports to clear them
expanderRead (chip1, INTCAPA);
expanderRead (chip1, INTCAPB);
// pin 19 of MCP23017 is plugged into D18 of the ArduinoMega which is interrupt 5
pinMode (18, INPUT); // make sure input
digitalWrite (18, HIGH); // enable pull-up as we have made the interrupt pins open drain
attachInterrupt(5, keypress, FALLING);
} // end of setup
void handleKeypress ()
{
unsigned int keyValue1 = 0;
delay (100); // de-bounce before we re-enable interrupts
keyPressed = false;
// check first chip
if (expanderRead (chip1, INFTFA))
keyValue1 |= expanderRead (chip1, INTCAPA) << 8; // read value at time of interrupt
if (expanderRead (chip1, INFTFB))
keyValue1 |= expanderRead (chip1, INTCAPB); // port B is in low-order byte
// show state of first 16 buttons
for (byte button = 0; button < 16; button++)
{
// this key down?
if (keyValue1 & (1 << button))
{
Serial.print ("Button ");
Serial.print (button + 1, DEC);
Serial.println (" now down");
} // end of if this bit changed
} // end of for each button
} // end of handleKeypress
volatile unsigned long i;
void loop ()
{
// some important calculations here ...
// was there an interrupt?
if (keyPressed)
handleKeypress ();
} // end of loop
The I2C version works but the SPI not. I've changed some pin since I'm using an Mega2560 but I'm suspect that the SPI routine that read data is not correct, can you help me? |