keybrd version 0.x.x is for initial development. The public API should not be considered stable. | keybrd version 0.x.x is for initial development. The public API should not be considered stable. | ||||
keybrd version 1.0.0 will be released when the public API is stable. | keybrd version 1.0.0 will be released when the public API is stable. | ||||
## [Unreleased][unreleased] | |||||
## [Unreleased] | |||||
## [0.3.2] - 2016-06-21 | ## [0.3.2] - 2016-06-21 | ||||
### Added | ### Added |
//activeHigh has diode cathode (band) on col, and pull down resistors on cols | //activeHigh has diode cathode (band) on col, and pull down resistors on cols | ||||
//0=active low, 1= active high | //0=active low, 1= active high | ||||
const bool RowScanner_PinsArray::activeHigh = 0; | const bool RowScanner_PinsArray::activeHigh = 0; | ||||
//const bool RowScanner_PinsBitwise::activeHigh = 0; | |||||
Debug debug; | Debug debug; | ||||
// ================ LEFT PORTS ================= | |||||
// ================= LEFT PINS ================= | |||||
uint8_t readPins[] = {14, 15}; | uint8_t readPins[] = {14, 15}; | ||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | ||||
LED_PinNumber LED1(16); //Teensy LC pins 16, 17 are 20 ma | |||||
LED_PinNumber LED1(16); //Teensy LC pins 16, 17 are 20 mA | |||||
// ================ RIGHT PORTS ================ | |||||
/* | |||||
const uint8_t IOExpanderPort::ADDR = 0x20; | |||||
IOExpanderPort portA(0, 0); | |||||
RowPort_MCP23018 rowPort(portA); | |||||
IOExpanderPort portB(1, 0); | |||||
ColPort_MCP23018 colPort(portB, 1<<0 | 1<<1 ); | |||||
*/ | |||||
// =================== CODES =================== | // =================== CODES =================== | ||||
Code_Sc s_a(KEY_A); | Code_Sc s_a(KEY_A); | ||||
Code_Sc s_b(KEY_B); | Code_Sc s_b(KEY_B); | ||||
Key* ptrsKeys_R[] = { &s_0, &s_1, &s_2, &s_3, | Key* ptrsKeys_R[] = { &s_0, &s_1, &s_2, &s_3, | ||||
&s_4, &s_5, &s_6, &s_7 }; //the most that 8-bit send() can handle | &s_4, &s_5, &s_6, &s_7 }; //the most that 8-bit send() can handle | ||||
const uint8_t KEY_COUNT = sizeof(ptrsKeys_R)/sizeof(*ptrsKeys_R); | const uint8_t KEY_COUNT = sizeof(ptrsKeys_R)/sizeof(*ptrsKeys_R); | ||||
//Row_ShiftRegisters row_R(9, 2, ptrsKeys_R, KEY_COUNT); | //Row_ShiftRegisters row_R(9, 2, ptrsKeys_R, KEY_COUNT); | ||||
Row_ShiftRegisters row_R(9, 1, ptrsKeys_R, KEY_COUNT); //1 byte | |||||
Row_ShiftRegisters row_R(9, 1, ptrsKeys_R, KEY_COUNT); // (SS, BYTE_COUNT,,) | |||||
// ################### MAIN #################### | // ################### MAIN #################### | ||||
void setup() | void setup() | ||||
//delay(1000); //time for OS to detect USB before printing | //delay(1000); //time for OS to detect USB before printing | ||||
Keyboard.print(F("activeState.ino ")); | Keyboard.print(F("activeState.ino ")); | ||||
debug.print_free_RAM(); | debug.print_free_RAM(); | ||||
//Wire.begin(); | |||||
/* Teensy LC on 1*bb 6/13/16 copied to: activeState_MCP23018_begin_hangs.no | |||||
RowPort_MCP23018::begin() hangs | |||||
ColPort_MCP23018::begin() sometimes hangs, sometimes prints after 6 seconds | |||||
PCA9655E::begin()s works on 4*bb | |||||
maybe hangs if IOE is not attached because endTransmission() waiting for confirmation?? | |||||
trouble shooting MCP23018::begin()s | |||||
checked wiring against datasheets | |||||
measured power and ground, 3.3 volts checks out | |||||
!! next things to check could take days: | |||||
test MCP23018 with Teensy 2.0, because it worked last year | |||||
set Teensy 2.0 to 3.3 volts and test again | |||||
try with PCA9655E instead of MCP23018 (works on 4*bb) | |||||
might be solder joints on LC (I soldered it), try using other Teensy LC | |||||
test MCP23018 on simple demo sketch /home/wolfv/Documents/Arduino/demo_keep/mcp23018_../ | |||||
test MCP23018 with signal analyzer | |||||
//rowPort.begin(); //this breaks sketch, does not print "activeState.ino ", kb unresponsive | |||||
//colPort.begin(RowScanner_PinsBitwise::activeHigh); //hanges for 6 seconds | |||||
Keyboard.println(F(" after Port.begin()")); | |||||
*/ | |||||
} | } | ||||
//uint16_t next = 0; | //uint16_t next = 0; | ||||
//row_R0.process(); | //row_R0.process(); | ||||
//row_R1.process(); | //row_R1.process(); | ||||
/* used this when debugging MCP23018::begin() hangs | |||||
if ( (next < 10) && (elapsed > 1000 * next) ) | |||||
{ | |||||
Keyboard.print(next); | |||||
Keyboard.print(F(" ")); | |||||
next++; | |||||
} | |||||
*/ | |||||
//delay(100); | //delay(100); | ||||
//Keyboard.println(""); | //Keyboard.println(""); | ||||
} | } |
/* this works on Teensy LC 1*bb, active low and active high | |||||
MCP23018::begin() hangs, details in setup() | |||||
| Layout | **0** | **1** | | |||||
|:------:|-------|-------| | |||||
| **0** | a | b | | |||||
| **1** | c | d | | |||||
*/ | |||||
// ################## GLOBAL ################### | |||||
// ================= INCLUDES ================== | |||||
#include <Debug.h> | |||||
//IOE Ports | |||||
#include "IOExpanderPort.h" | |||||
#include <RowPort_MCP23018.h> | |||||
#include <ColPort_MCP23018.h> | |||||
//Codes | |||||
#include <Code_Sc.h> | |||||
//Matrix | |||||
#include <Row_uC.h> | |||||
#include <Row_IOE.h> | |||||
// =============== CONFIGURATION =============== | |||||
const unsigned int RowBase::DELAY_MICROSECONDS = 500; | |||||
//activeLow has diode cathode (band) on row | |||||
//activeHigh has diode cathode (band) on col, and pull down resistors on cols | |||||
//0=active low, 1= active high | |||||
const bool RowScanner_PinsArray::activeHigh = 0; | |||||
const bool RowScanner_PinsBitwise::activeHigh = 0; | |||||
Debug debug; | |||||
// ================= uC PINS ================= | |||||
uint8_t readPins[] = {14, 15}; | |||||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||||
// ================ IOE PORTS ================ | |||||
const uint8_t IOExpanderPort::ADDR = 0x20; | |||||
IOExpanderPort portA(0, 0); | |||||
RowPort_MCP23018 rowPort(portA); | |||||
IOExpanderPort portB(1, 0); | |||||
ColPort_MCP23018 colPort(portB, 1<<0 | 1<<1 ); | |||||
// =================== 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_0(KEY_0); | |||||
Code_Sc s_1(KEY_1); | |||||
Code_Sc s_2(KEY_2); | |||||
Code_Sc s_3(KEY_3); | |||||
// ================= LEFT ROWS ================= | |||||
Key* ptrsKeys_L0[] = { &s_a, &s_b }; | |||||
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0); | |||||
Key* ptrsKeys_L1[] = { &s_c, &s_d }; | |||||
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1); | |||||
// ================= RIGHT ROWS ================ | |||||
Key* ptrsKeys_R0[] = { &s_0, &s_1 }; | |||||
Row_IOE row_R0(rowPort, 1<<0, colPort, ptrsKeys_R0); | |||||
Key* ptrsKeys_R1[] = { &s_2, &s_3 }; | |||||
Row_IOE row_R1(rowPort, 1<<1, colPort, ptrsKeys_R1); | |||||
// ################### MAIN #################### | |||||
void setup() | |||||
{ | |||||
Keyboard.begin(); | |||||
Wire.begin(); //Wire.begin() must be called before rowPort.begin() colPort.begin() | |||||
//delay(1000); //time for OS to detect USB before printing | |||||
Keyboard.print(F("activeState.ino ")); | |||||
debug.print_free_RAM(); | |||||
/* Teensy LC on 1*bb | |||||
RowPort_MCP23018::begin() hangs | |||||
ColPort_MCP23018::begin() sometimes hangs, sometimes prints after 6 seconds | |||||
PCA9655E::begin()s works on 4*bb | |||||
maybe hangs if IOE is not attached because endTransmission() waiting for confirmation?? | |||||
trouble shooting MCP23018::begin()s | |||||
checked wiring against datasheets | |||||
measured power and ground, 3.3 volts checks out | |||||
!! next things to check could take days: | |||||
test MCP23018 with Teensy 2.0, because it worked last year | |||||
set Teensy 2.0 to 3.3 volts and test again | |||||
try with PCA9655E instead of MCP23018 (works on 4*bb) | |||||
might be solder joints on LC (I soldered it), try using other Teensy LC | |||||
test MCP23018 on simple demo sketch /home/wolfv/Documents/Arduino/demo_keep/mcp23018_../ | |||||
test MCP23018 with signal analyzer | |||||
//rowPort.begin(); //this breaks sketch, does not print "activeState.ino ", kb unresponsive | |||||
//colPort.begin(RowScanner_PinsBitwise::activeHigh); //hanges for 6 seconds | |||||
Keyboard.println(F(" after Port.begin()")); | |||||
*/ | |||||
} | |||||
uint16_t next = 0; | |||||
elapsedMillis elapsed; | |||||
void loop() | |||||
{ | |||||
row_L0.process(); | |||||
row_L1.process(); | |||||
//row_R0.process(); | |||||
//row_R1.process(); | |||||
/* used this when debugging MCP23018::begin() hangs | |||||
if ( (next < 10) && (elapsed > 1000 * next) ) | |||||
{ | |||||
Keyboard.print(next); | |||||
Keyboard.print(F(" ")); | |||||
next++; | |||||
} | |||||
*/ | |||||
//delay(500); | |||||
//Keyboard.println(""); | |||||
} |
{ | { | ||||
read_pins_t isFallingEdge; //bitwise, 1 means falling edge | read_pins_t isFallingEdge; //bitwise, 1 means falling edge | ||||
read_pins_t isRisingEdge; //bitwise, 1 means rising edge | read_pins_t isRisingEdge; //bitwise, 1 means rising edge | ||||
read_pins_t rowMask; //bitwise, active col bit is 1 (same type as rowEnd) | |||||
read_pins_mask_t rowMask; //bitwise, active col bit is 1 | |||||
uint8_t col; //index for ptrsKeys[col] array | uint8_t col; //index for ptrsKeys[col] array | ||||
//bit=1 if last debounced changed from 1 to 0, else bit=0 | //bit=1 if last debounced changed from 1 to 0, else bit=0 |
*/ | */ | ||||
read_pins_t RowScanner_SPIShiftRegisters::scan(read_pins_mask_t& rowEnd) | read_pins_t RowScanner_SPIShiftRegisters::scan(read_pins_mask_t& rowEnd) | ||||
{ | { | ||||
//todo rowEnd, rowState, return int size depend on BYTE_COUNT, like in send() | |||||
//todo rowEnd, rowState, return int size depend on BYTE_COUNT, like in send(), set in config_keybrd? | |||||
read_pins_t rowState = 0; | read_pins_t rowState = 0; | ||||
digitalWrite(SS, LOW); | |||||
digitalWrite(SS, HIGH); | |||||
digitalWrite(SS, LOW); //load parallel inputs to the register | |||||
digitalWrite(SS, HIGH); //shift the data toward a serial output | |||||
SPI.transfer(&rowState, BYTE_COUNT); | SPI.transfer(&rowState, BYTE_COUNT); | ||||
rowEnd = 1 << KEY_COUNT; | rowEnd = 1 << KEY_COUNT; | ||||
return rowState; | return rowState; |
class RowScanner_SPIShiftRegisters : public RowScannerInterface | class RowScanner_SPIShiftRegisters : public RowScannerInterface | ||||
{ | { | ||||
private: | private: | ||||
const uint8_t SS; //Slave Select, pin on master | |||||
const uint8_t BYTE_COUNT; //number of shift registers | |||||
const uint8_t SS; //pin on master that selects slave | |||||
const uint8_t BYTE_COUNT; //number of bytes to read from shift registers | |||||
const uint8_t KEY_COUNT; //number of keys in row | const uint8_t KEY_COUNT; //number of keys in row | ||||
public: | public: | ||||
RowScanner_SPIShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, uint8_t KEY_COUNT) | RowScanner_SPIShiftRegisters(const uint8_t SS, uint8_t BYTE_COUNT, uint8_t KEY_COUNT) |
For RowScanner_SPIShiftRegisters, RowScanner_SPIShiftRegisters::KEY_COUNT | For RowScanner_SPIShiftRegisters, RowScanner_SPIShiftRegisters::KEY_COUNT | ||||
For RowScanner_PinsBitwise, cover the last 1 bit in RowScanner_PinsBitwise::strobePin | For RowScanner_PinsBitwise, cover the last 1 bit in RowScanner_PinsBitwise::strobePin | ||||
*/ | */ | ||||
typedef uint8_t read_pins_t; | |||||
//typedef uint8_t read_pins_t; | |||||
//typedef uint16_t read_pins_t; | //typedef uint16_t read_pins_t; | ||||
//typedef uint32_t read_pins_t; | |||||
typedef uint32_t read_pins_t; | |||||
/* read_pins_mask_t is only used for rowEnd, which extends one bit beyond the last col pin. | |||||
/* read_pins_mask_t is only used for rowMask and rowEnd, which extends one bit beyond the last col pin. | |||||
uncomment typedef that covers one bit beyond the last col pin. | uncomment typedef that covers one bit beyond the last col pin. | ||||
This could be the same typedef as read_pins_t, or the next larger typedef. | This could be the same typedef as read_pins_t, or the next larger typedef. | ||||
*/ | */ | ||||
typedef uint8_t read_pins_mask_t; | |||||
//typedef uint8_t read_pins_mask_t; | |||||
//typedef uint16_t read_pins_mask_t; | //typedef uint16_t read_pins_mask_t; | ||||
//typedef uint32_t read_pins_mask_t; | |||||
typedef uint32_t read_pins_mask_t; | |||||
/* SAMPLE_COUNT = 4 is very reliable for a keyboard. | /* SAMPLE_COUNT = 4 is very reliable for a keyboard. | ||||
Split keyboards with a long connecting wire or in environment with | Split keyboards with a long connecting wire or in environment with |