#include "PortMCP23S17.h" | #include "PortMCP23S17.h" | ||||
/* transfer() writes data to registerAddr, reads portSate from registerAddr, and returns portState. | /* transfer() writes data to registerAddr, reads portSate from registerAddr, and returns portState. | ||||
MCP23S17 SPI interface is 10 MHz max. | |||||
The electrical limitation to bus speed is bus capacitance and the length of the wires involved. | |||||
Longer wires require lower clock speeds. | |||||
*/ | */ | ||||
uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, | uint8_t PortMCP23S17::transfer(const uint8_t command, const uint8_t registerAddr, | ||||
const uint8_t data) | const uint8_t data) | ||||
{ | { | ||||
uint8_t portState; //bit pattern | uint8_t portState; //bit pattern | ||||
SPI.beginTransaction( SPISettings(5000000, MSBFIRST, SPI_MODE0) ); //control SPI bus, 5 MHz | |||||
digitalWrite(SS, LOW); //enable Slave Select | digitalWrite(SS, LOW); //enable Slave Select | ||||
SPI.transfer(command); //write or read command | SPI.transfer(command); //write or read command | ||||
SPI.transfer(registerAddr); //register address to write data to | SPI.transfer(registerAddr); //register address to write data to | ||||
portState = SPI.transfer(data); //write data, read portState | portState = SPI.transfer(data); //write data, read portState | ||||
digitalWrite(SS, HIGH); //disable Slave Select | digitalWrite(SS, HIGH); //disable Slave Select | ||||
SPI.endTransaction(); | |||||
return portState; | return portState; | ||||
} | } | ||||
/* begin() is called from Scanner_IOE::begin(). | |||||
Initiates SPI bus and configures I/O pins for read and write. | |||||
MCP23S17 SPI interface is 10 MHz max. | |||||
The electrical limitation to bus speed is bus capacitance and the length of the wires involved. | |||||
Longer wires require lower clock speeds. | |||||
/* begin() is called from Scanner_IOE::begin(). Initiates SPI bus. | |||||
*/ | */ | ||||
void PortMCP23S17::beginProtocol() | void PortMCP23S17::beginProtocol() | ||||
{ | { | ||||
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.endTransaction() not called to release SPI bus because keyboard only has one SPI device | |||||
//if two IOEs are used, move beginTransaction() endTransaction() to write() read() functions | |||||
} | } | ||||
/* begin() is called from Scanner_IOE::begin(). | /* begin() is called from Scanner_IOE::begin(). |
#include <PortInterface.h> | #include <PortInterface.h> | ||||
/* | /* | ||||
readPins are connected to matrix col | |||||
write pin is connected to matrix Row (strobe pin) or LED. | |||||
write pins are connected to matrix Row (strobe pin) or LED. | |||||
readPins are connected to matrix column to read which keys are pressed. | |||||
Slave Select is hardcoded to Arduino Pin 10. | Slave Select is hardcoded to Arduino Pin 10. | ||||
Arduino Pin 10 avoids the speed penalty of digitalWrite. | Arduino Pin 10 avoids the speed penalty of digitalWrite. | ||||
readPins parameter configures port's pins. | readPins parameter configures port's pins. | ||||
Example instantiation: | 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, | |||||
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||||
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs | |||||
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //first two pins are set to input for reading, | |||||
//remaining pins can be used for LEDs | //remaining pins can be used for LEDs | ||||
Diode orientation | Diode orientation | ||||
const uint8_t deviceAddr; | const uint8_t deviceAddr; | ||||
const uint8_t portNum; //port identification number | const uint8_t portNum; //port identification number | ||||
uint8_t outputVal; //bit pattern for strobe and LEDs | uint8_t outputVal; //bit pattern for strobe and LEDs | ||||
const uint8_t readPins; //bits, IODIR 0=output, 1=input | |||||
const uint8_t readPins; //bit pattern, 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(const uint8_t deviceAddr, const uint8_t portNum, const uint8_t readPins) | PortMCP23S17(const uint8_t deviceAddr, const uint8_t portNum, const uint8_t readPins) |
#include <Scanner_uC.h> | #include <Scanner_uC.h> | ||||
//right matrix | //right matrix | ||||
#include <PortIOE.h> | |||||
#include <PortWrite_MCP23S17.h> | |||||
#include <PortRead_MCP23S17.h> | |||||
#include <PortMCP23S17.h> | |||||
#include <Scanner_IOE.h> | #include <Scanner_IOE.h> | ||||
// ============ SPEED CONFIGURATION ============ | // ============ SPEED CONFIGURATION ============ | ||||
Left matrix rows work the same as the ones in keybrd_2_single-layer.ino | Left matrix rows work the same as the ones in keybrd_2_single-layer.ino | ||||
*/ | */ | ||||
uint8_t readPins[] = {14, 15}; | uint8_t readPins[] = {14, 15}; | ||||
const uint8_t READPIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | |||||
Scanner_uC scanner_L(LOW, readPins, READPIN_COUNT); | |||||
Scanner_uC scanner_L(LOW, readPins, readPinCount); | |||||
/* =============== RIGHT SCANNER =============== | /* =============== RIGHT SCANNER =============== | ||||
The right matrix is scanned by an I/O expander. | The right matrix is scanned by an I/O expander. | ||||
The I/O expander device address is configured by hardware pins. | |||||
DEVICE_ADDR is a static variable of class PortIOE. | |||||
The MCP23S17 address is set by grounding or powering pins. | |||||
*/ | */ | ||||
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address with all 3 ADDR pins are grounded | |||||
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||||
/* | /* | ||||
port_B stobes the row while port_A reads the colums. | |||||
port_A is assigned port identification number 0. | |||||
port_A is assigned to portRead, which reads port_A pins 0 and 1. | |||||
Normally all strobe pins are on one port, and all the read pins are on the other port. | |||||
In this example, portB stobes the row while portA reads the colums. | |||||
PortMCP23S17 constructor parameters are: deviceAddr, portNum, readPins | |||||
readPins is a bit pattern, where 0=output, 1=input. | |||||
In portA, the first two pins are set to input for reading. | |||||
"<<" (bit shift left) and "|" (OR) are bitwise operators. | "<<" (bit shift left) and "|" (OR) are bitwise operators. | ||||
Pin numbers to be read are to the right of "1<<" and delimited by "|". | Pin numbers to be read are to the right of "1<<" and delimited by "|". | ||||
*/ | */ | ||||
PortIOE port_A(0); | |||||
PortRead_MCP23S17 portRead(port_A, 1<<0 | 1<<1 ); | |||||
/* | |||||
port_B is assigned port identification number 1. | |||||
port_B is assigned to portWrite. | |||||
*/ | |||||
PortIOE port_B(1); | |||||
PortWrite_MCP23S17 portWrite(port_B); | |||||
Scanner_IOE scanner_R(LOW, portWrite, portRead); | |||||
PortMCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); | |||||
PortMCP23S17 portB(IOE_ADDR, 1, 0); | |||||
Scanner_IOE scanner_R(LOW, portB, portA); | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
Code_Sc s_a(KEY_A); | Code_Sc s_a(KEY_A); |
// ============ SPEED CONFIGURATION ============ | // ============ SPEED CONFIGURATION ============ | ||||
ScanDelay scanDelay(9000); | ScanDelay scanDelay(9000); | ||||
// ================ LEFT =============== | |||||
// ================= LEFT PINS ================= | |||||
// ---------------- LEFT SCANNER --------------- | // ---------------- LEFT SCANNER --------------- | ||||
uint8_t readPins[] = {14, 15}; | uint8_t readPins[] = {14, 15}; | ||||
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins); | ||||
// ----------------- LEFT LEDs ----------------- | // ----------------- LEFT LEDs ----------------- | ||||
LED_uC LED_CapsLck(21); | LED_uC LED_CapsLck(21); | ||||
// =============== RIGHT =============== | |||||
// ================ RIGHT PINS ================= | |||||
// --------------- RIGHT SCANNER --------------- | // --------------- RIGHT SCANNER --------------- | ||||
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | ||||
PortMCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED | PortMCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED |
The MCP23S17's /RESET pin is connected to VDD. | The MCP23S17's /RESET pin is connected to VDD. | ||||
The MCP23S17 I/O expander has two ports. Each port has eight pins. | The MCP23S17 I/O expander has two ports. Each port has eight pins. | ||||
Port B is connected to the matrix's rows. Port A is connected to the matrix's columns. | |||||
Port B is connected to the matrix's rows. | |||||
Port A is connected to the matrix's columns. | |||||
Building a split keyboard with I/O Expander | Building a split keyboard with I/O Expander | ||||
------------------------------------------- | ------------------------------------------- |