Browse Source

fixed MCP23S17 port classes and keybrd_4c_split_with_IOE.ino

tags/v0.6.0
wolfv6 7 years ago
parent
commit
4b1b53a76a

+ 1
- 1
examples/keybrd_PCA9655E/keybrd_PCA9655E.ino View File

@@ -37,7 +37,7 @@ PortIOE port_R1(1, 0);
PortWrite_PCA9655E portWrite_R1(port_R1);

PortIOE port_R0(0, 0);
//PortWrite_PCA9655E portWrite_R0(port_R0); for LEDs
//PortWrite_PCA9655E portWrite_R0(port_R0); //for LEDs
PortRead_PCA9655E portRead_R0(port_R0, 1<<0 | 1<<1 );

Scanner_IOE scanner_R(HIGH, portWrite_R1, portRead_R0);

+ 2
- 13
src/PortIOE.h View File

@@ -24,24 +24,13 @@ For example, I2C address with AD2=GND AD1=SCL AD0=SCL,
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 instead of A, use 1 instead of B.
outputVal: For pins that are connected to active low rows, set outputVal bit to 1.
Set all other outputVal bits to 0.
Example instantiation for port0 with active low rows on all pins:
PortIOE port0(0, ~0);
Example instantiation for portA with active low rows on pins 0,1,2:
PortIOE portA(0, 1<<0 | 1<<1 | 1<<2 );
Example instantiation for portB with active high rows on pins 0,1,2:
PortIOE portB(1, 0);
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 number
uint8_t outputVal; //bitwise value of output register
uint8_t outputVal; //bitwise value of output register for LEDs
PortIOE(const uint8_t portNumber, uint8_t outputVal)
: num(portNumber), outputVal(outputVal) {}

+ 1
- 1
src/PortReadInterface.h View File

@@ -12,7 +12,7 @@ Details are in config_key.h
class PortReadInterface
{
public:
virtual void begin()=0;
virtual void begin(const uint8_t strobeOn)=0;
virtual uint8_t read()=0;
};
#endif

+ 12
- 12
src/PortRead_MCP23S17.cpp View File

@@ -1,12 +1,10 @@
#include "PortRead_MCP23S17.h"
/*
SPI bus is configured in PortWrite_MCP23S17::begin().
begin() is called from Scanner_IOE::begin().
*/
void PortRead_MCP23S17::begin(const uint8_t strobeOn)
{
uint8_t pullUp; //bitwise, 1 means internal pull-up resistor enabled
if (strobeOn == LOW) //if active low
{
pullUp = readPins;
@@ -16,25 +14,27 @@ void PortRead_MCP23S17::begin(const uint8_t strobeOn)
pullUp = 0;
}
Keyboard.print("\npullUp=");//todo
Keyboard.print(pullUp);
/*
//todo these 4 lines are duplicated in PortWrite_MCP23S17::begin(), which is called first
pinMode(SS, OUTPUT); //configure controller's Slave Select pin to output
digitalWrite(SS, HIGH); //disable Slave Select
SPI.begin();
SPI.beginTransaction(SPISettings (SPI_CLOCK_DIV8, MSBFIRST, SPI_MODE0)); //control SPI bus todo is slow clock needed?
//SPI.endTransaction() not called to release SPI bus because keyboard only has one SPI device.
*/
digitalWrite(SS, LOW); //enable Slave Select
SPI.transfer(port.DEVICE_ADDR << 1); //write command
SPI.transfer(port.DEVICE_ADDR << 1); //write command
SPI.transfer(port.num); //configure IODIR
SPI.transfer(readPins); //0=output (for LED), 1=input (for read)
digitalWrite(SS, LOW); //enable Slave Select
digitalWrite(SS, HIGH); //enable Slave Select
digitalWrite(SS, HIGH); //disable Slave Select
SPI.transfer(port.DEVICE_ADDR << 1); //write command
digitalWrite(SS, LOW); //disable Slave Select
SPI.transfer(port.DEVICE_ADDR << 1); //write command
SPI.transfer(port.num + 0x0C); //configure GPPU
SPI.transfer(pullUp); //0=pull-up disabled (for LED), 1=pull-up enabled (for read)
digitalWrite(SS, HIGH); //disable Slave Select
//SPI.endTransaction() is not called to release the SPI bus
// because keyboard only has one SPI device.
}
/*
@@ -45,7 +45,7 @@ uint8_t PortRead_MCP23S17::read()
uint8_t portState; //bit wise
digitalWrite(SS, LOW); //enable Slave Select
SPI.transfer(port.DEVICE_ADDR << 1 | 1); //read command
SPI.transfer(port.DEVICE_ADDR << 1 | 1); //read command
SPI.transfer(port.num + 0x12); //GPIO register address to read data from
portState = SPI.transfer(0); //save the data (0 is dummy data to send)
digitalWrite(SS, HIGH); //disable Slave Select

+ 3
- 1
src/PortRead_MCP23S17.h View File

@@ -29,9 +29,11 @@ class PortRead_MCP23S17 : public PortReadInterface
{
private:
PortIOE& port;
uint8_t pullUp; //bitwise, 1 means internal pull-up resistor enabled
const uint8_t readPins; //bitwise, 1 means internal pull-up resistor enabled
public:
PortRead_MCP23S17(PortIOE& port, const uint8_t readPins) : port(port), readPins(readPins) {}
PortRead_MCP23S17(PortIOE& port, const uint8_t readPins)
: port(port), readPins(readPins) {}
void begin(const uint8_t strobeOn);
virtual uint8_t read();
};

+ 3
- 1
src/PortRead_PCA9655E.cpp View File

@@ -1,6 +1,8 @@
#include "PortRead_PCA9655E.h"
void PortRead_PCA9655E::begin()
/*
*/
void PortRead_PCA9655E::begin(const uint8_t strobeOn)
{
Wire.beginTransmission(port.DEVICE_ADDR);
Wire.write(port.num + 6); //configuration byte command

+ 1
- 1
src/PortRead_PCA9655E.h View File

@@ -33,7 +33,7 @@ class PortRead_PCA9655E : public PortReadInterface
public:
PortRead_PCA9655E (PortIOE& port, const uint8_t readPins)
: port(port), readPins(readPins) {}
void begin();
void begin(const uint8_t strobeOn);
virtual uint8_t read();
};
#endif

+ 1
- 1
src/PortWriteInterface.h View File

@@ -13,6 +13,6 @@ class PortWriteInterface
{
public:
virtual void begin()=0;
virtual void write(const uint8_t pin, const bool level)=0;
virtual void write(const uint8_t strobePin, const bool pinLogicLevel)=0;
};
#endif

+ 6
- 8
src/PortWrite_MCP23S17.cpp View File

@@ -5,13 +5,13 @@
void PortWrite_MCP23S17::writePort(const uint8_t registerAddr, const uint8_t data)
{
digitalWrite(SS, LOW); //enable Slave Select
SPI.transfer(port.DEVICE_ADDR << 1); //write command
SPI.transfer(port.DEVICE_ADDR << 1); //write command
SPI.transfer(registerAddr); //register address to write data to
SPI.transfer(data); //data
digitalWrite(SS, HIGH); //disable Slave Select
}
/* begin() should be called once from sketch in setup().
/* begin() is called from Scanner_IOE::begin(). Initiates SPI bus and configures write pins.
PortRead_MCP23S17 and PortWrite_MCP23S17 should be on seperate ports on the same MCP23S17.
Output pins can be used for strobe pins and LEDs.
*/
@@ -21,20 +21,18 @@ void PortWrite_MCP23S17::begin()
digitalWrite(SS, HIGH); //disable Slave Select
SPI.begin();
SPI.beginTransaction(SPISettings (SPI_CLOCK_DIV8, MSBFIRST, SPI_MODE0)); //control SPI bus todo is slow clock needed?
//SPI.endTransaction() not called to release SPI bus because keyboard only has one SPI device.
writePort(port.num, 0); //configure port direction (port.num) to output (0)
//SPI.endTransaction() is not called to release the SPI bus
// because keyboard only has one SPI device.
}
/*
strobePin is bitwise, where pin being strobed is 1.
pinLogicLevel is HIGH or LOW.
port.outputVal can be shared by LEDs.
The functions does not reset the other pins so that they can be used for LEDs.
The function does not reset the other pins so that they can be used for LEDs.
*/
void PortWrite_MCP23S17::write(const uint8_t strobePin, const uint8_t pinLogicLevel)
void PortWrite_MCP23S17::write(const uint8_t strobePin, const bool pinLogicLevel)
{
if (pinLogicLevel == LOW)
{
@@ -45,5 +43,5 @@ void PortWrite_MCP23S17::write(const uint8_t strobePin, const uint8_t pinLogicLe
port.outputVal |= strobePin; //set strobePin output to high
}
writePort(port.num + 0x12, port.outputVal); //set GPIO port pins for stobe and LEDs
writePort(port.num + 0x12, port.outputVal); //set GPIO port pins for strobe and LEDs
}

+ 1
- 1
src/PortWrite_MCP23S17.h View File

@@ -43,6 +43,6 @@ class PortWrite_MCP23S17 : public PortWriteInterface
public:
PortWrite_MCP23S17(PortIOE& port) : port(port) {}
void begin();
virtual void write(const uint8_t pin, const uint8_t level);
virtual void write(const uint8_t pin, const bool pinLogicLevel);
};
#endif

+ 9
- 7
src/PortWrite_PCA9655E.cpp View File

@@ -6,6 +6,8 @@ Otherwise readPins could be overwritten.
*/
void PortWrite_PCA9655E::begin()
{
Wire.begin();
Wire.beginTransmission(port.DEVICE_ADDR);
Wire.write(port.num + 6); //configuration byte command
Wire.write(0); //0=configure as output (for strobe pins and LED)
@@ -13,20 +15,20 @@ void PortWrite_PCA9655E::begin()
}
/*
pin is bitwise, where pin being strobed is 1.
value is HIGH or LOW.
strobePin is bitwise, where pin being strobed is 1.
pinLogicLevel is HIGH or LOW.
Does not reset the other pins because LEDs could be using some of the pins.
Syntax is similar to Arduino DigitalWrite().
*/
void PortWrite_PCA9655E::write(const uint8_t pin, const bool value)
void PortWrite_PCA9655E::write(const uint8_t strobePin, const bool pinLogicLevel)
{
if (value == LOW) //if active low
if (pinLogicLevel == LOW) //if strobePin low
{
port.outputVal &= ~pin; //set pin output to low
port.outputVal &= ~strobePin; //set pin output to low
}
else //if active high
else //if strobestrobe high
{
port.outputVal |= pin; //set pin output to high
port.outputVal |= strobePin; //set pin output to high
}
Wire.beginTransmission(port.DEVICE_ADDR);

+ 1
- 1
src/PortWrite_PCA9655E.h View File

@@ -41,6 +41,6 @@ class PortWrite_PCA9655E : public PortWriteInterface
PortWrite_PCA9655E(PortIOE& port) : port(port) {}
void begin();
virtual void write(const uint8_t pin, const bool level);
virtual void write(const uint8_t strobePin, const bool pinLogicLevel);
};
#endif

+ 10
- 6
src/Scanner_IOE.cpp View File

@@ -1,22 +1,22 @@
#include "Scanner_IOE.h"

/* Row constructor calls every Scanner's init().
/* init() is called once for each row from Row constructor.
*/
void Scanner_IOE::init(const uint8_t strobePin)
{
//emty function
//empty
}

/* begin() should be called once from sketch setup().
*/
void Scanner_IOE::begin()
{
Wire.begin();
refPortWrite.begin();
refPortRead.begin();
refPortWrite.begin(); //configures SPI bus
refPortRead.begin(strobeOn);
}

/* scan() strobes the row's strobePin and retuns state of port's input pins.
/* scan() is called on every iteration of sketch loop().
scan() strobes the row's strobePin and retuns state of port's input pins.
Bitwise variables are 1 bit per key.
*/
read_pins_t Scanner_IOE::scan(const uint8_t strobePin)
@@ -33,5 +33,9 @@ read_pins_t Scanner_IOE::scan(const uint8_t strobePin)
//strobe off
refPortWrite.write(strobePin, strobeOff);

if (strobeOn == LOW) //if active low
{
readState = ~readState;
}
return readState;
}

+ 0
- 1
src/Scanner_IOE.h View File

@@ -3,7 +3,6 @@

#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
#include <ScannerInterface.h>
#include <PortWriteInterface.h>
#include <PortReadInterface.h>

+ 1
- 1
src/Scanner_ShiftRegsPISOSingleRow.h View File

@@ -21,7 +21,7 @@ The Row "strobePin" parameter is ignored.
In the above example, the "strobePin" argument is 0, but it doesn't matter what value is given.

There are three Scanner_ShiftRegsPISOSingleRow parameters.
"strobeOn" paramter is active state HIGH or LOW.
"strobeOn" paramter is ignored, but should be active state HIGH or LOW required by ScannerInterface.

"slaveSelect" paramter can be any controller pin connected to shift register's SHIFT-LOAD pin.
slaveSelect pin SS (Arduino pin 10) has the fastest scan.

+ 2
- 1
src/Scanner_uC.cpp View File

@@ -39,7 +39,8 @@ void Scanner_uC::init(const uint8_t strobePin)
pinMode(strobePin, OUTPUT);
}

/* scan() strobes the row's strobePin and retuns state of readPins.
/* scan() is called on every iteration of sketch loop().
scan() strobes the row's strobePin and retuns state of readPins.
Bitwise variables are 1 bit per key.
*/
read_pins_t Scanner_uC::scan(const uint8_t strobePin)

+ 2
- 2
src/config_keybrd.h View File

@@ -13,9 +13,9 @@ Using smaller types on a 32-bit uC (Teensy LC) would accomplish nothing.
For Scanner_ShiftRegs74HC165, Scanner_ShiftRegs74HC165::readPinCount
For Scanner_IOE, cover the last 1 bit in Scanner_IOE::strobePin
*/
typedef uint8_t read_pins_t;
//typedef uint8_t read_pins_t;
//typedef uint16_t read_pins_t;
//typedef uint32_t read_pins_t;
typedef uint32_t read_pins_t;

/* SAMPLE_COUNT_MACRO is used in Debouncer_Samples.h
SAMPLE_COUNT_MACRO = 4 is very reliable for a keyboard.

+ 29
- 38
tutorials/keybrd_4c_split_with_IOE/keybrd_4c_split_with_IOE.ino View File

@@ -2,11 +2,6 @@

| Left | **0** | **1** | | Right | **0** | **1** |
|:-----:|-------|-------| |:-----:|-------|-------|
| **0** | a | b | | **0** | 1 | 2 |
| **1** | shift | c | | **1** | 3 | shift |

| Left | **0** | **1** | | Right | **0** | **1** | todo
|:-----:|-------|-------| |:-----:|-------|-------|
| **1** | 1 | 2 | | **1** | 3 | 4 |
| **0** | a | b | | **0** | c | d |
*/
@@ -14,79 +9,74 @@
// ================= INCLUDES ==================
#include <ScanDelay.h>
#include <Code_Sc.h>
#include <Row.h>

//left matrix
#include <Row_uC.h>
#include <Scanner_uC.h>

//right matrix
#include <Row_IOE.h>
#include <PortIOE.h>
#include <PortWrite_MCP23S17.h>
#include <PortRead_MCP23S17.h>
#include <Scanner_IOE.h>

// ============ SPEED CONFIGURATION ============
ScanDelay scanDelay(9000);

// ================ LEFT MATRIX ================
// ---------------- ACTIVE STATE ---------------
const bool Scanner_uC::STROBE_ON = LOW; //active low
const bool Scanner_uC::STROBE_OFF = HIGH;

// ------------------- PINS --------------------
// ================ LEFT SCANNER ===============
uint8_t readPins[] = {14, 15};
uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);

// ================ RIGHT MATRIX ===============
const bool Scanner_Port::STROBE_ON = HIGH; //active high
const bool Scanner_Port::STROBE_OFF = LOW;
Scanner_uC scanner_L(LOW, readPins, readPinCount);

const uint8_t PortIOE::DEVICE_ADDR = 0x18;
// =============== RIGHT SCANNER ===============
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded

// ------------------ PORT 1 -------------------
PortIOE port1_R(1, 0);
PortWrite_MCP23S17 portWrite1_R(port1_R);
PortIOE port_A(0, 0);
PortRead_MCP23S17 portRead_A(port_A, 1<<0 | 1<<1 );

// ------------------ PORT 0 -------------------
PortIOE port0_R(0, 0);
PortWrite_MCP23S17 portWrite0_R(port0_R);
PortRead_MCP23S17 portRead0_R(port0_R, 1<<0 | 1<<1 );
PortIOE port_B(1, 0);
//PortWrite_MCP23S17 portWrite_B(port_B); //for LEDs
PortWrite_MCP23S17 portWrite_B(port_B);

// =================== CODES ===================
Code_Sc s_shiftL(MODIFIERKEY_LEFT_SHIFT);
Code_Sc s_shiftR(MODIFIERKEY_RIGHT_SHIFT);
Scanner_IOE scanner_R(LOW, portWrite_B, portRead_A);

// =================== CODES ===================
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C);
Code_Sc s_d(KEY_D);

Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
Code_Sc s_3(KEY_3);
Code_Sc s_4(KEY_4);

// =================== ROWS ====================
// ---------------- LEFT ROWS ------------------
Key* ptrsKeys_L0[] = { &s_a, &s_b };
Key* ptrsKeys_L0[] = { &s_1, &s_2 };
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0);
Row_uC row_L0(0, readPins, KEY_COUNT_L0, ptrsKeys_L0);
Row row_L0(scanner_L, 0, ptrsKeys_L0, KEY_COUNT_L0);

Key* ptrsKeys_L1[] = { &s_c, &s_shiftL };
Key* ptrsKeys_L1[] = { &s_a, &s_b };
const uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1);
Row_uC row_L1(1, readPins, KEY_COUNT_L1, ptrsKeys_L1);
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1);

// ---------------- RIGHT ROWS -----------------
Key* ptrsKeys_R0[] = { &s_1, &s_2 };
Key* ptrsKeys_R0[] = { &s_3, &s_4 };
const uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row_IOE row_R0(portWrite1_R, 1<<0, portRead0_R, KEY_COUNT_R0, ptrsKeys_R0);
Row row_R0(scanner_R, 1<<0, ptrsKeys_R0, KEY_COUNT_R0);

Key* ptrsKeys_R1[] = { &s_3, &s_shiftR };
Key* ptrsKeys_R1[] = { &s_c, &s_d };
const uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row_IOE row_R1(portWrite1_R, 1<<1, portRead0_R, KEY_COUNT_R1, ptrsKeys_R1);
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1);

// ################### MAIN ####################
void setup()
{
delay(7000); //todo
Keyboard.begin();
Wire.begin(); //Wire.begin() must be called before port begin()
portWrite1_R.begin();
portRead0_R.begin();
scanner_R.begin();
}

void loop()
@@ -102,4 +92,5 @@ void loop()
scanDelay.delay();
//debug.print_scans_per_second();
//debug.print_microseconds_per_scan();
delay(100); //todo
}

+ 4
- 8
unit_tests/PortRead_MCP23S17/PortRead_MCP23S17.ino View File

@@ -1,18 +1,14 @@
/* unit test for PortRead_MCP23S17
Picture of hardware is in unit_tests/PortRead_MCP23S17/PortRead_MCP23S17_bb.JPG
The setup is an MCP23S17 I/O expander on a Teensy LC controller.
MCP23S17 port-B pins are alternately grounded and energized.
portBState is a bitwise reading of port B.
output is: 10101010

posted on http://arduino.stackexchange.com/questions/tagged/spi
http://arduino.stackexchange.com/questions/28792/reading-an-mcp23s17-i-o-expander-port-with-the-arduino-spi-library
*/

#include "PortIOE.h"
#include "PortRead_MCP23S17.h"
#include "Scanner_Port.h"

const bool Scanner_Port::STROBE_ON = LOW;
const bool Scanner_Port::STROBE_OFF = HIGH;
#include "Scanner_IOE.h"

const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
PortIOE portB(1, 0);
@@ -24,7 +20,7 @@ void setup()
uint8_t portBState; //bit wise

delay(6000);
portBRead.begin();
portBRead.begin(LOW);

portBState = portBRead.read();
Keyboard.print("portBState = ");

BIN
unit_tests/PortRead_MCP23S17/PortRead_MCP23S17_bb.JPG View File


unit_tests/PortWrite_MCP23S17/PortRead_MCP23S17.ino → unit_tests/PortWrite_MCP23S17/PortWrite_MCP23S17.ino View File

@@ -1,9 +1,10 @@
/* unit test for PortRead_MCP23S17
/* unit test for PortWrite_MCP23S17
Picture of hardware is in unit_tests/PortRead_MCP23S17/PortRead_MCP23S17_bb.JPG
The setup is an MCP23S17 I/O expander on a Teensy LC controller.
MCP23S17 port-A GPIO pins are not connected to anything.
Port-A GPIO-pin ouputs alternate between 0 and 3.3 volts.

Use a volt meter to measure port-A GPIO-pin ouputs.
Use a volt meter to measure port-A GPIO-pin outputs.
MCP23S17 on 3.3v does not output enough power to reliable light LEDs
LED lights w/o resistor
LED not light with 56 ohm resistor
@@ -16,7 +17,7 @@ PortIOE portA(0, 0);

PortWrite_MCP23S17 portAWrite(portA); //PortAWrite needed for begin()

const uint8_t GPIOA = 0x12; //LEDs are on port A
//const uint8_t GPIOA = 0x12; //LEDs are on port A

void setup()
{