#ifndef PORTIOE_H | |||||
#define PORTIOE_H | |||||
#include <inttypes.h> | |||||
/* The pins of an IC's port can be split between PortWrite, PortRead, and LED. | |||||
PortIOE contains outputVal, the value of a port's output register. | |||||
outputVal is used for port manipulation by classes PortWrite and LED. | |||||
One port's outputVal can be shared by strobe pins and multiple LED pins. | |||||
PortIOE is only used by I/O expander port classes. | |||||
AVR port classes do not need a similar class because PORTx is global in the Arduino library. | |||||
Instantiation | |||||
------------ | |||||
Example PortIOE::DEVICE_ADDR initilization: | |||||
const uint8_t PortIOE::DEVICE_ADDR = 0x18; | |||||
Be careful with the DEVICE_ADDR. | |||||
Table 6 in PCA9655E datasheet lists 8-bit versions of I2C addresses. | |||||
The Arduino Wire library uses 7-bit addresses throughout, so drop the low bit. | |||||
For example, I2C address with AD2=GND AD1=SCL AD0=SCL, | |||||
Table 6 lists 8-bit DEVICE_ADDR = 0x30 (b 00110000) | |||||
while Arduino uses 7-bit DEVICE_ADDR = 0x18 (b 00011000) | |||||
http://playground.arduino.cc/Main/WireLibraryDetailedReference | |||||
The PCA9655E data sheet is on http://www.onsemi.com/pub_link/Collateral/PCA9655E-D.PDF | |||||
portNumber: If the I/O expander uses port letters, use 0 inplace of A, use 1 inplace of B. | |||||
*/ | |||||
struct PortIOE | |||||
{ | |||||
static const uint8_t DEVICE_ADDR; | |||||
const uint8_t num; //port identification number | |||||
uint8_t outputVal; //bit value of output register for LEDs | |||||
PortIOE(const uint8_t portNumber) | |||||
: num(portNumber), outputVal(0) {} | |||||
}; | |||||
#endif |
class PortInterface | class PortInterface | ||||
{ | { | ||||
public: | public: | ||||
virtual void beginProtocol()=0; //SPI or I2C bus | |||||
virtual void beginProtocol()=0; //SPI bus or I2C bus | |||||
virtual void begin(const uint8_t strobeOn)=0; //configure GPIO pins | virtual void begin(const uint8_t strobeOn)=0; //configure GPIO pins | ||||
virtual void write(const uint8_t strobePin, const bool pinLogicLevel)=0; | virtual void write(const uint8_t strobePin, const bool pinLogicLevel)=0; | ||||
virtual uint8_t read()=0; | virtual uint8_t read()=0; |
/* transfer() writes data to registerAddr, reads portSate from registerAddr, and returns portState. | /* transfer() writes data to registerAddr, reads portSate from registerAddr, and returns portState. | ||||
*/ | */ | ||||
uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data) | |||||
uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, | |||||
const uint8_t data) | |||||
{ | { | ||||
uint8_t portState; //bit pattern | uint8_t portState; //bit pattern | ||||
pinMode(SS, OUTPUT); //configure controller's Slave Select pin to output | pinMode(SS, OUTPUT); //configure controller's Slave Select pin to output | ||||
digitalWrite(SS, HIGH); //disable Slave Select | digitalWrite(SS, HIGH); //disable Slave Select | ||||
SPI.begin(); | SPI.begin(); | ||||
SPI.beginTransaction(SPISettings (5000000, MSBFIRST, SPI_MODE0)); //control SPI bus, 5 MHz | |||||
SPI.beginTransaction( SPISettings(5000000, MSBFIRST, SPI_MODE0) ); //control SPI bus, 5 MHz | |||||
//SPI.endTransaction() not called to release SPI bus because keyboard only has one SPI device | //SPI.endTransaction() not called to release SPI bus because keyboard only has one SPI device | ||||
} | } | ||||
pullUp = 0; | pullUp = 0; | ||||
} | } | ||||
transfer(port.DEVICE_ADDR << 1, port.num, readPins); //configure IODIR | |||||
transfer(port.DEVICE_ADDR << 1, port.num + 0x0C, pullUp); //configure GPPU | |||||
transfer(DEVICE_ADDR << 1, portNum, readPins); //configure IODIR | |||||
transfer(DEVICE_ADDR << 1, portNum + 0x0C, pullUp); //configure GPPU | |||||
} | } | ||||
/* write() sets pin output to logicLevel (useful for strobePin, one LED pin, or multiple pins). | /* write() sets pin output to logicLevel (useful for strobePin, one LED pin, or multiple pins). | ||||
{ | { | ||||
if (logicLevel == LOW) | if (logicLevel == LOW) | ||||
{ | { | ||||
port.outputVal &= ~pin; //set pin output to low | |||||
outputVal &= ~pin; //set pin output to low | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
port.outputVal |= pin; //set pin output to high | |||||
outputVal |= pin; //set pin output to high | |||||
} | } | ||||
transfer(port.DEVICE_ADDR << 1, port.num + 0x12, port.outputVal); //set GPIO port to outputVal | |||||
transfer(DEVICE_ADDR << 1, portNum + 0x12, outputVal); //set GPIO port to outputVal | |||||
} | } | ||||
/* read() returns portState. Only portState pins with pull resistors are valid. | /* read() returns portState. Only portState pins with pull resistors are valid. | ||||
*/ | */ | ||||
uint8_t PortMCP23S17::read() | uint8_t PortMCP23S17::read() | ||||
{ | { | ||||
return transfer( (port.DEVICE_ADDR << 1) | 1, port.num + 0x12, 0); //read from GPIO | |||||
return transfer( (DEVICE_ADDR << 1) | 1, portNum + 0x12, 0); //read from GPIO | |||||
} | } |
#include <Arduino.h> | #include <Arduino.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <SPI.h> | #include <SPI.h> | ||||
#include <PortIOE.h> | |||||
#include <PortInterface.h> | #include <PortInterface.h> | ||||
/* | /* | ||||
Instantiation | Instantiation | ||||
------------ | ------------ | ||||
readPins parameter is configures port's pins. | |||||
Example instantiation: | |||||
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||||
PortIOE port_B(1); | |||||
Port_MCP23S17 portWrite_B(port_B, 0); //all pins are set to output for strobes and LEDs | |||||
MCP23S17 datasheet identifies ports by letters, while class PortMCP23S17 uses portNum | |||||
for port A, use portNum=0 | |||||
for port B, use portNum=1 | |||||
readPins parameter configures port's pins. | |||||
PortIOE port_A(0); | |||||
Port_MCP23S17 portRead_A(port_A, 1<<0 | 1<<1 ); //pins 0,1 are set to input for reading, | |||||
//remaining pins can be used for LEDs | |||||
Example instantiation: | |||||
const uint8_t Port_MCP23S17::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins grounded | |||||
Port_MCP23S17 portB(1, 0); //all pins are set to output for strobes and LEDs | |||||
Port_MCP23S17 portA(0, 1<<0 | 1<<1 ); //1 pins are set to input for reading, | |||||
//remaining pins can be used for LEDs | |||||
Diode orientation | Diode orientation | ||||
---------------- | ---------------- | ||||
class PortMCP23S17 : public PortInterface | class PortMCP23S17 : public PortInterface | ||||
{ | { | ||||
private: | private: | ||||
PortIOE& port; | |||||
static const uint8_t DEVICE_ADDR; | |||||
const uint8_t portNum; //port identification number | |||||
uint8_t outputVal; //bit pattern for strobe and LEDs | |||||
const uint8_t readPins; //bits, IODIR 0=output, 1=input | const uint8_t readPins; //bits, IODIR 0=output, 1=input | ||||
uint8_t transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data); | uint8_t transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data); | ||||
public: | public: | ||||
PortMCP23S17(PortIOE& port, const uint8_t readPins) : port(port), readPins(readPins) {} | |||||
PortMCP23S17(const uint8_t portNum, const uint8_t readPins) | |||||
: portNum(portNum), outputVal(0), readPins(readPins) {} | |||||
void beginProtocol(); | void beginProtocol(); | ||||
void begin(const uint8_t strobeOn); | void begin(const uint8_t strobeOn); | ||||
virtual void write(const uint8_t pin, const bool logicLevel); | virtual void write(const uint8_t pin, const bool logicLevel); |
#include <LED_uC.h> | #include <LED_uC.h> | ||||
//right matrix | //right matrix | ||||
#include <PortIOE.h> | |||||
#include <PortMCP23S17.h> | #include <PortMCP23S17.h> | ||||
#include <Scanner_IOE.h> | #include <Scanner_IOE.h> | ||||
#include <LED_IOE.h> | #include <LED_IOE.h> | ||||
// =============== RIGHT =============== | // =============== RIGHT =============== | ||||
// --------------- RIGHT SCANNER --------------- | // --------------- RIGHT SCANNER --------------- | ||||
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address with all 3 ADDR pins are grounded | |||||
const uint8_t PortMCP23S17::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||||
PortMCP23S17 portA(0, 1<<0 | 1<<1 ); //for read and LED | |||||
PortMCP23S17 portB(1, 0); //for strobe and LED | |||||
PortIOE port_A(0); | |||||
PortMCP23S17 portRead(port_A, 1<<0 | 1<<1 );//read and LED | |||||
PortIOE port_B(1); | |||||
PortMCP23S17 portWrite(port_B, 0); //write to strobe and LED | |||||
Scanner_IOE scanner_R(LOW, portWrite, portRead); | |||||
Scanner_IOE scanner_R(LOW, portB, portA); | |||||
// ---------------- RIGHT LEDs ----------------- | // ---------------- RIGHT LEDs ----------------- | ||||
LED_IOE LED_normal(portRead, 1<<5); //port A | |||||
LED_IOE LED_fn(portWrite, 1<<4); //port B | |||||
LED_IOE LED_normal(portA, 1<<5); | |||||
LED_IOE LED_fn(portB, 1<<4); | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
// ---------------- LAYER CODE ----------------- | // ---------------- LAYER CODE ----------------- |