@@ -1,38 +0,0 @@ | |||
#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 |
@@ -9,7 +9,7 @@ Port classes are the keybrd library's interface to microcontroller ports or I/O | |||
class PortInterface | |||
{ | |||
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 write(const uint8_t strobePin, const bool pinLogicLevel)=0; | |||
virtual uint8_t read()=0; |
@@ -2,7 +2,8 @@ | |||
/* 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 | |||
@@ -27,7 +28,7 @@ void PortMCP23S17::beginProtocol() | |||
pinMode(SS, OUTPUT); //configure controller's Slave Select pin to output | |||
digitalWrite(SS, HIGH); //disable Slave Select | |||
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 | |||
} | |||
@@ -48,8 +49,8 @@ void PortMCP23S17::begin(const uint8_t strobeOn) | |||
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). | |||
@@ -61,19 +62,19 @@ void PortMCP23S17::write(const uint8_t pin, const bool logicLevel) | |||
{ | |||
if (logicLevel == LOW) | |||
{ | |||
port.outputVal &= ~pin; //set pin output to low | |||
outputVal &= ~pin; //set pin output to low | |||
} | |||
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. | |||
*/ | |||
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 | |||
} |
@@ -3,7 +3,6 @@ | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
#include <SPI.h> | |||
#include <PortIOE.h> | |||
#include <PortInterface.h> | |||
/* | |||
@@ -15,16 +14,16 @@ Arduino Pin 10 avoids the speed penalty of digitalWrite. | |||
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 | |||
---------------- | |||
@@ -37,11 +36,14 @@ MCP23S17 data sheet | |||
class PortMCP23S17 : public PortInterface | |||
{ | |||
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 | |||
uint8_t transfer(const uint8_t command, const uint8_t registerAddr, const uint8_t data); | |||
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 begin(const uint8_t strobeOn); | |||
virtual void write(const uint8_t pin, const bool logicLevel); |
@@ -27,7 +27,6 @@ This layout table shows left and right matrices: | |||
#include <LED_uC.h> | |||
//right matrix | |||
#include <PortIOE.h> | |||
#include <PortMCP23S17.h> | |||
#include <Scanner_IOE.h> | |||
#include <LED_IOE.h> | |||
@@ -47,19 +46,15 @@ LED_uC LED_CapsLck(21); | |||
// =============== RIGHT =============== | |||
// --------------- 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 ----------------- | |||
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 =================== | |||
// ---------------- LAYER CODE ----------------- |