@@ -7,8 +7,9 @@ Improvement suggestions | |||
We need to know what improvements to the keybrd library would help you create your keyboard design. | |||
Before requesting an improvement, please check [planned_features list](doc/planned_features.md) | |||
Submit improvement suggestions to [GitHub issues](https://github.com/wolfv6/Keybrd/issues). | |||
* The issue title should start with "suggestion:" followed by a descriptive title | |||
Submit improvement suggestions to [GitHub issues](https://github.com/wolfv6/Keybrd/issues) | |||
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0). | |||
<!-- * The issue title should start with "suggestion:" followed by a descriptive title --> | |||
* Provide a use case | |||
* Explain why the improvement is useful | |||
* Site other product examples where this improvement exists | |||
@@ -16,6 +17,8 @@ Submit improvement suggestions to [GitHub issues](https://github.com/wolfv6/Keyb | |||
Bug reports | |||
----------- | |||
A bug report is the first step in making the keybrd library work the way it's supposed to work. | |||
Submit bug reports to [GitHub issues](https://github.com/wolfv6/Keybrd/issues) | |||
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0). | |||
Please provide enough information so we can reproduce the bug behaviour! | |||
* Complete sketch (copy & paste, attachment, or a link to the code) | |||
@@ -52,7 +55,7 @@ A healthy project needs the perspective of many people. | |||
* Documentation - Suggest a clarification, simplification, correction, or other improvement. | |||
We need the perspective of people new to the project to see these things. | |||
Sometimes just changing a word or two makes a big difference. | |||
* [Current user contributions](https://geekhack.org/index.php?topic=83599.0) highlights contributions that are needed for the keybrd project's current stage of development. | |||
* [Current user contributions](https://geekhack.org/index.php?topic=83599.msg2223776#msg2223776) highlights contributions that are needed for the keybrd project's current stage of development. | |||
Text file documentation style guide: | |||
* Use Markdown with a .md suffix. |
@@ -27,7 +27,7 @@ Row_Ext::keyWasPressed() overrides Row::keyWasPressed() which is used to unstick | |||
Row_Ext_uC and Row_Ext_ShiftRegisters are a custom classes composed of stock keybrd library classes.<br> | |||
Row_Ext_uC uses Scanner_uC to scan the primary matrix.<br> | |||
Row_Ext_ShiftRegisters uses Scanner_ShiftRegs74HC165 to scan the secondary matrix. | |||
Row_Ext_ShiftRegisters uses Scanner_ShiftRegs74HC165 to scan the peripheral matrix. | |||
Class inheritance diagram | |||
``` | |||
@@ -68,7 +68,7 @@ Keybrd library class inheritance diagram | |||
``` | |||
________ Row ___________ | |||
/ | \ | |||
Row_uC Row_ShiftRegisters Row_IOE (to be added) | |||
Row_uC Row_ShiftRegisters Row_IOE (todo to be added) | |||
Scanner_uC Scanner_Port Scanner_ShiftRegs74HC165 | |||
@@ -78,7 +78,7 @@ Keybrd library class inheritance diagram | |||
PortWrite | |||
| | |||
PortWrite_PCA9655E (one PortWrite class for each IOE type) | |||
PortWrite_PCA9655E (one PortWrite class for each IOE type) | |||
PortRead | |||
| | |||
@@ -115,9 +115,9 @@ Keybrd library class inheritance diagram | |||
| | | | |||
| Code_LayeredScSc Code_LayeredCodeSc | |||
| | |||
|__________________________________________ | |||
\ \ \ \ | |||
Code_Sc Code_Shift Code_AutoShift Code_LEDLock | |||
|_________________________________________________________ | |||
\ \ \ \ \ | |||
Code_Sc Code_Shift Code_AutoShift Code_LEDLock Code_Null | |||
/ \ | |||
Code_ScS Code_ScNS | |||
@@ -149,7 +149,7 @@ Dependency diagram of example multi-layer keyboard with layer LEDs | |||
``` | |||
Dependency diagram of example secondary matrix with shift registers | |||
Dependency diagram of example peripheral matrix with shift registers | |||
``` | |||
Row_ShiftRegisters[1..*] | |||
/ \ \ | |||
@@ -159,17 +159,17 @@ Dependency diagram of example secondary matrix with shift registers | |||
``` | |||
Dependency diagram of example secondary matrix with I/O Expander and LEDs | |||
Dependency diagram of example peripheral matrix with I/O Expander and LEDs | |||
``` | |||
___ Row_IOE[1..*] _________ | |||
/ \ \ | |||
_ Scanner_Port[1] _ Debouncer[1] Keys[1..*] __ | |||
/ | \ | \ | |||
PortWrite[1] RowPin[1] PortRead[1] Code[1..*] Code_LEDLock[1..*] | |||
\ / \ | | |||
\ / ColPins[1..*] LED[1] | |||
\ / | |||
PortIOE[0..*] | |||
_____ Row_IOE[1..*] _________ | |||
/ \ \ | |||
__ Scanner_Port[1] __ Debouncer[1] Keys[1..*] __ | |||
/ | \ | \ | |||
PortWrite[1] strobePin[1] PortRead[1] Code[1..*] Code_LEDLock[1..*] | |||
\ / \ | | |||
\ / ColPins[1..*] LED[1] | |||
\ / | |||
PortIOE[0..*] | |||
``` | |||
@@ -243,7 +243,7 @@ Following the style guide makes it easier for the next programmer to understand | |||
Trace of keybrd scan | |||
-------------------- | |||
Arduino does not have a debugger. | |||
So here is the next best thing; a list of functions in the order that they are called. | |||
So here is a list of functions in the order that they are called. | |||
The trace is of a one-row single-layer keybrd scan. | |||
Refer to it like a table of contents while reading the keybrd library. | |||
@@ -13,7 +13,7 @@ Details are in config_key.h | |||
class PortRead | |||
{ | |||
protected: | |||
const uint8_t readPins; //bitwise pin configuration, 1 means read column | |||
const uint8_t readPins; //bitwise pin configuration, 1 means read pin | |||
public: | |||
PortRead(const uint8_t readPins): readPins(readPins) {} | |||
virtual uint8_t read()=0; |
@@ -0,0 +1,23 @@ | |||
#include "PortRead_MCP23S17.h" | |||
/* | |||
PortRead_MCP23S17::begin() is not needed because port direction is already configured to input by default. | |||
SPI bus is configured in PortWrite_MCP23S17::begin(). | |||
*/ | |||
/* | |||
returns port value | |||
*/ | |||
uint8_t PortRead_MCP23S17::read() | |||
{ | |||
uint8_t portState; //bit wise | |||
//slower clock | |||
digitalWrite(SS, LOW); //enable Slave Select | |||
SPI.transfer(port.ADDR << 1 | 1); //read command | |||
SPI.transfer(port.num + 0x12); //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 | |||
return portState; | |||
} |
@@ -0,0 +1,42 @@ | |||
#ifndef PORTREAD_MCP23S17_H | |||
#define PORTREAD_MCP23S17_H | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
#include <SPI.h> | |||
#include <PortRead.h> | |||
#include "PortIOE.h" | |||
/* One MCP23S17 I/O expander port connected to matrix columns. | |||
MCP23S17 does not have internal pull-up resistors (PCA9535E does). | |||
Instantiation | |||
------------ | |||
readPins parameter is port's bitwise pin configuration | |||
1=configure as input (for pins connected to column) | |||
0=configure as output (for LED or not connected to a column) | |||
Example instantiation for column port 0, with pins 2 and 3 connected to columns: | |||
PortIOE port0(0, 0); | |||
PortRead_MCP23S17 colPort0(port0, 2<<0 | 1<<3 ); | |||
Example instantiation for column port 1, with pins 2 and 3 connected to columns: | |||
PortIOE port1(1, 0); | |||
PortRead_MCP23S17 colPort1(port1, 2<<0 | 1<<3 ); | |||
readPins are read from pin 0 on up. | |||
*/ | |||
class PortRead_MCP23S17 : public PortRead | |||
{ | |||
private: | |||
PortIOE& port; | |||
public: | |||
/* | |||
todo not all PortRead_ classes need a readPins | |||
move PortRead::readPins from PortRead to PortRead_PCA9655E | |||
remove PortRead(0) initialization from this constructor | |||
*/ | |||
//The constructor initialization list is in .cpp | |||
PortRead_MCP23S17(PortIOE& port) : PortRead(0), port(port) {} | |||
virtual uint8_t read(); | |||
}; | |||
#endif |
@@ -0,0 +1,50 @@ | |||
#include "PortWrite_MCP23S17.h" | |||
void PortWrite_MCP23S17::writePort(const uint8_t registerAddr, const uint8_t data) | |||
{ | |||
//slower clock | |||
//SPI.beginTransaction(SPISettings (SPI_CLOCK_DIV8, MSBFIRST, SPI_MODE0)); //control SPI bus todo move to begin() | |||
digitalWrite(SS, LOW); //enable Slave Select | |||
SPI.transfer(port.ADDR << 1); //write command | |||
SPI.transfer(registerAddr); //register address to write data to | |||
SPI.transfer(data); //data | |||
digitalWrite(SS, HIGH); //disable Slave Select | |||
//SPI.endTransaction(); //release the SPI bus | |||
} | |||
/* | |||
If PortRead_MCP23S17 is instantiated on the same port, do NOT use PortWrite_MCP23S17::begin(). | |||
Otherwise readPins could be overwritten. | |||
Output pins can be used for strobe pins and LEDs. | |||
SPI.endTransaction() is not called because keyboard only has one SPI device, so no need to release the SPI bus | |||
*/ | |||
void PortWrite_MCP23S17::begin() | |||
{ | |||
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 | |||
writePort(port.num, 0); //configure port direction (port.num) to output (0) | |||
} | |||
/* | |||
pin is bitwise, where pin being strobed is 1. | |||
strobe is HIGH or LOW (for active high or active low). | |||
port.outputVal can be shared by LEDs. | |||
The functions does not reset the other pins so that they can be used for LEDs. | |||
*/ | |||
void PortWrite_MCP23S17::write(const uint8_t pin, const bool strobe) | |||
{ | |||
if (strobe == LOW) //if active low | |||
{ | |||
port.outputVal &= ~pin; //set pin output to low | |||
} | |||
else //if active high | |||
{ | |||
port.outputVal |= pin; //set pin output to high | |||
} | |||
writePort(port.num + 0x12, port.outputVal); //set GPIO port pins for stobe and LEDs | |||
} |
@@ -0,0 +1,46 @@ | |||
#ifndef PORTWRITE_MCP23S17_H | |||
#define PORTWRITE_MCP23S17_H | |||
#include <Arduino.h> | |||
#include <inttypes.h> | |||
#include <SPI.h> | |||
#include <PortWrite.h> | |||
#include "PortIOE.h" | |||
/* One MCP23S17 I/O expander port connected to matrix rows. | |||
MCP23S17 does not have internal pull-up resistors (PCA9535E does). | |||
begin() configures column port's configuration and output. | |||
This should normally be called once in sketch's setup(). | |||
If PortRead_MCP23S17 is instantiated on the same port, do NOT use PortWrite_MCP23S17::begin(). | |||
Otherwise readPins could be overwritten. | |||
Instantiation | |||
------------ | |||
Example instantiation for row port 0: | |||
PortIOE port0(0, 0); | |||
PortWrite_MCP23S17 rowPort0(port0); | |||
Example instantiation for row port 1: | |||
PortIOE port1(1, 0); | |||
PortWrite_MCP23S17 rowPort1(port1); | |||
Diode orientation | |||
---------------- | |||
Diode orientation is explained in keybrd_library_user_guide.md > Diode orientation | |||
MCP23S17 data sheet | |||
---------------- | |||
http://www.onsemi.com/pub_link/Collateral/MCP23S17-D.PDF | |||
*/ | |||
class PortWrite_MCP23S17 : public PortWrite | |||
{ | |||
private: | |||
PortIOE& port; | |||
void writePort(const uint8_t registerAddr, const uint8_t data); | |||
public: | |||
PortWrite_MCP23S17(PortIOE& port) : port(port) {} | |||
void begin(); | |||
virtual void write(const uint8_t pin, const bool level); | |||
}; | |||
#endif |
@@ -14,8 +14,7 @@ class Row | |||
Key *const *const ptrsKeys; //array of Key pointers | |||
virtual void keyWasPressed(); | |||
protected: | |||
read_pins_t debounced; //bitwise state of keys after debouncing | |||
// 1 means pressed, 0 means released | |||
read_pins_t debounced; //bitwise state of keys after debouncing, 1=pressed, 0=released | |||
void send(const uint8_t readPinCount, const read_pins_t debouncedChanged); | |||
public: | |||
Row(Key* const ptrsKeys[]) : ptrsKeys(ptrsKeys), debounced(0) { } |
@@ -0,0 +1,12 @@ | |||
#include "Row_IOE.h" | |||
void Row_IOE::process() | |||
{ | |||
//these variables are all bitwise, one bit per key | |||
uint8_t readState; //1 means pressed, 0 means released | |||
uint8_t debouncedChanged; //1 means debounced changed | |||
readState = scanner.scan(); | |||
debouncedChanged = debouncer.debounce(readState, debounced); | |||
send(readPinCount, debouncedChanged); | |||
} |
@@ -0,0 +1,26 @@ | |||
#ifndef ROW_IOE_H | |||
#define ROW_IOE_H | |||
#include <Row.h> | |||
#include <Scanner_Port.h> | |||
#include <Debouncer_Samples.h> | |||
class PortWrite; | |||
class PortRead; | |||
/* Row_IOE is a row connected to an Input/Output Expander. | |||
Configuration and Instantiation instructions are in keybrd/src/Row_IOE.h | |||
*/ | |||
class Row_IOE : public Row | |||
{ | |||
private: | |||
Scanner_Port scanner; | |||
Debouncer_Samples debouncer; | |||
const uint8_t readPinCount; //number of read pins | |||
public: | |||
Row_IOE(PortWrite& refPortWrite, const uint8_t strobePin, | |||
PortRead& refPortRead, const uint8_t readPinCount, Key *const ptrsKeys[]) | |||
: Row(ptrsKeys), scanner(refPortWrite, strobePin, refPortRead), | |||
readPinCount(readPinCount) { } | |||
void process(); | |||
}; | |||
#endif |
@@ -13,7 +13,7 @@ shift registers 74HC165 are Parallel-In-Serial-Out (PISO) | |||
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins. | |||
For active low: | |||
Shift register parallel input pins have 10k pull-down resistors powered | |||
Shift register parallel input pins have 10k pull-up resistors powered | |||
Orient diodes with cathode (banded end) towards the write pins (row) | |||
Controller's MISO pin is connected to shift register's complementary serial output (/QH) pin | |||
Use these two lines in the sketch: |
@@ -32,7 +32,7 @@ Code_Sc s_c(KEY_C); | |||
Key* ptrsKeys_0[] = { &s_1, &s_a }; | |||
Row_uC row_0(0, readPins, READ_PIN_COUNT, ptrsKeys_0); | |||
Key* ptrsKeys_1[] = { &s_b, &s_c }; | |||
Key* ptrsKeys_1[] = { &s_b, &s_c }; | |||
Row_uC row_1(1, readPins, READ_PIN_COUNT, ptrsKeys_1); | |||
// ################### MAIN #################### |
@@ -0,0 +1,96 @@ | |||
/* tutorial_4a_split_keyboard_with_shift_registers.ino | |||
Tested on Teensy LC and two 74HC165 shift registers. | |||
The right matrix has 2 shift registers daisy chained. | |||
Layout Layout | |||
| Left |**0** | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|**7**| | |||
|:-----:|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----|-----| | |||
| **0** | x | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | |||
| **1** | y | | **1** | a | b | c | d | e | f | g | h | | |||
*/ | |||
// ################## GLOBAL ################### | |||
// ================= INCLUDES ================== | |||
#include <ScanDelay.h> | |||
#include <Code_Sc.h> | |||
//Left matrix | |||
#include <Row_uC.h> | |||
//Right matrix | |||
#include <SPI.h> | |||
#include <Row_ShiftRegisters.h> | |||
// =============== CONFIGURATION =============== | |||
ScanDelay scanDelay(9000); | |||
// =================== 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_e(KEY_E); | |||
Code_Sc s_f(KEY_F); | |||
Code_Sc s_g(KEY_G); | |||
Code_Sc s_x(KEY_X); | |||
Code_Sc s_y(KEY_Y); | |||
Code_Sc s_0(KEY_0); | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
Code_Sc s_3(KEY_3); | |||
Code_Sc s_4(KEY_4); | |||
Code_Sc s_5(KEY_5); | |||
Code_Sc s_6(KEY_6); | |||
// =============== LEFT MATRIX ================= | |||
//set left matrix for active low | |||
const bool Scanner_uC::STROBE_ON = LOW; | |||
const bool Scanner_uC::STROBE_OFF = HIGH; | |||
//column pin | |||
uint8_t readPins[] = {14}; | |||
uint8_t READ_PIN_COUNT = sizeof(readPins)/sizeof(*readPins); | |||
//rows | |||
Key* ptrsKeys_L0[] = { &s_x }; | |||
Row_uC row_L0(0, readPins, READ_PIN_COUNT, ptrsKeys_L0); | |||
Key* ptrsKeys_L1[] = { &s_y }; | |||
Row_uC row_L1(1, readPins, READ_PIN_COUNT, ptrsKeys_L1); | |||
// =============== RIGHT MATRIX ================ | |||
//set matrix to active high | |||
const bool Scanner_ShiftRegs74HC165::STROBE_ON = HIGH; | |||
const bool Scanner_ShiftRegs74HC165::STROBE_OFF = LOW; | |||
//chip select pin | |||
const uint8_t Scanner_ShiftRegs74HC165::SHIFT_LOAD = 10; | |||
//rows | |||
Key* ptrsKeys_R0[] = { &s_6, &s_5, &s_4, &s_3, //shift regiser on right | |||
&s_c, &s_d, &s_e, &s_f, | |||
&s_2, &s_1, &s_0, &s_g, //shift regiser on left | |||
&s_a, &s_b }; //unused input pins are grounded | |||
Row_ShiftRegisters row_R0(0, sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0), ptrsKeys_R0); | |||
// ################### MAIN #################### | |||
void setup() | |||
{ | |||
Keyboard.begin(); | |||
SPI.begin(); | |||
row_R0.begin(); | |||
} | |||
void loop() | |||
{ | |||
//left matrix | |||
row_L0.process(); | |||
row_L1.process(); | |||
//right matrix | |||
row_R0.process(); | |||
scanDelay.delay(); | |||
} |
@@ -0,0 +1,105 @@ | |||
/* keybrd_4c_split_with_IOE_annotated.ino | |||
| 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 | | |||
*/ | |||
// ################## GLOBAL ################### | |||
// ================= INCLUDES ================== | |||
#include <ScanDelay.h> | |||
#include <Code_Sc.h> | |||
//left matrix | |||
#include <Row_uC.h> | |||
//right matrix | |||
#include <Row_IOE.h> | |||
#include <PortIOE.h> | |||
#include <PortWrite_MCP23S17.h> | |||
#include <PortRead_MCP23S17.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 -------------------- | |||
uint8_t readPins[] = {14, 15}; | |||
// ================ RIGHT MATRIX =============== | |||
const bool Scanner_Port::STROBE_ON = HIGH; //active high | |||
const bool Scanner_Port::STROBE_OFF = LOW; | |||
const uint8_t PortIOE::ADDR = 0x18; | |||
// ------------------ PORT 1 ------------------- | |||
PortIOE port1_R(1, 0); | |||
PortWrite_MCP23S17 portWrite1_R(port1_R); | |||
// ------------------ PORT 0 ------------------- | |||
PortIOE port0_R(0, 0); | |||
PortWrite_MCP23S17 portWrite0_R(port0_R); | |||
PortRead_MCP23S17 portRead0_R(port0_R, 1<<0 | 1<<1 ); | |||
// =================== CODES =================== | |||
Code_Sc s_shiftL(MODIFIERKEY_LEFT_SHIFT); | |||
Code_Sc s_shiftR(MODIFIERKEY_RIGHT_SHIFT); | |||
Code_Sc s_a(KEY_A); | |||
Code_Sc s_b(KEY_B); | |||
Code_Sc s_c(KEY_C); | |||
Code_Sc s_1(KEY_1); | |||
Code_Sc s_2(KEY_2); | |||
Code_Sc s_3(KEY_3); | |||
// =================== ROWS ==================== | |||
// ---------------- LEFT ROWS ------------------ | |||
Key* ptrsKeys_L0[] = { &s_a, &s_b }; | |||
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0); | |||
Row_uC row_L0(0, readPins, KEY_COUNT_L0, ptrsKeys_L0); | |||
Key* ptrsKeys_L1[] = { &s_c, &s_shiftL }; | |||
const uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1); | |||
Row_uC row_L1(1, readPins, KEY_COUNT_L1, ptrsKeys_L1); | |||
// ---------------- RIGHT ROWS ----------------- | |||
Key* ptrsKeys_R0[] = { &s_1, &s_2 }; | |||
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); | |||
Key* ptrsKeys_R1[] = { &s_3, &s_shiftR }; | |||
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); | |||
// ################### MAIN #################### | |||
void setup() | |||
{ | |||
Keyboard.begin(); | |||
Wire.begin(); //Wire.begin() must be called before port begin() | |||
portWrite1_R.begin(); | |||
portRead0_R.begin(); | |||
} | |||
void loop() | |||
{ | |||
//left matrix | |||
row_L0.process(); | |||
row_L1.process(); | |||
//right matrix | |||
row_R0.process(); | |||
row_R1.process(); | |||
scanDelay.delay(); | |||
//debug.print_scans_per_second(); | |||
//debug.print_microseconds_per_scan(); | |||
} |
@@ -1,19 +1,38 @@ | |||
Tutorial 10 - writing IOE Port classes | |||
=========================================== | |||
Tutorial 10 - writing new IOE Port classes | |||
========================================== | |||
Port classes are the keybrd library's interface to I/O expander ports. | |||
To write your own Port class: | |||
To write a new Port class: | |||
1. Get a copy of the I/O expander datasheet. | |||
2. Study other keybrd Port classes. | |||
For example, the keybrd_DH library uses these keybrd classes for its PCA9655E I/O expander: | |||
* PortWrite_PCA9655E | |||
* PortRead_PCA9655E | |||
* LED_PCA9655E | |||
Debugging I/O expander code is hard because SPI or I2C protocol adds a level of indirection. | |||
If you haven't written Arduino code for an I/O expander before, learn from an Arduiono I/O expander tutorial before attempting it here. | |||
1. Get a copy of the I/O expander's datasheet. | |||
2. An I/O expander will use one of two communication protocols: [http://www.byteparadigm.com/applications/introduction-to-i2c-and-spi-protocols/](SPI or I2C). | |||
Refer to the [Arduino SPI](https://www.arduino.cc/en/Reference/SPI) | |||
or [Arduino Wire (I2C)](https://www.arduino.cc/en/Reference/Wire) library | |||
3. Get familiar with your I/O expander. | |||
Different I/O expanders use different commands (a.k.a. operation codes). | |||
Refer to your I/O expander's datasheet for read and write commands. | |||
Search for Arduino sketch examples containing your I/O expander | |||
([sumotoy](https://github.com/sumotoy/gpio_expander) has a large gpio expander library). | |||
Write very simple read and write examples for your I/O expander. | |||
Simple SPI I/O expander examples: | |||
todo link, pictures | |||
/home/wolfv/Documents/Arduino/demo/IOE_MCP23S17_read/ | |||
/home/wolfv/Documents/Arduino/demo/IOE_MCP23S17_write/ | |||
Simple I2C I/O expander examples: | |||
todo link, pictures | |||
read | |||
write | |||
4. Study other keybrd Port classes. | |||
Port classes for SPI MCP23S17 I/O expander: | |||
*todo | |||
* | |||
* | |||
Port classes for I2C PCA9655E I/O expander: | |||
* PortWrite_PCA9655E todo link | |||
* PortRead_PCA9655E | |||
* LED_PCA9655E | |||
5. Write similar Port classes for your I/O expander. | |||
Debugging I/O expander code is hard because SPI or I2C protocol adds a level of indirection. | |||
<br> | |||
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>. |
@@ -1,12 +1,12 @@ | |||
Tutorial 8b - creating and publishing your own keybrd extension library | |||
======================================================================= | |||
Tutorial 8b - sharing your keybrd extension library | |||
=================================================== | |||
Publishing and listing your keybrd extension library allows others to find and install your library. | |||
The keybrd extension library name should start with "keybrd_" so that it is easy for other people to find. | |||
There are two ways to publish and list an Arduino library. | |||
Publishing anywhere with listing on Arduino Playground LibraryList | |||
------------------------------------------------------------------ | |||
Publish anywhere and list on Arduino Playground | |||
----------------------------------------------- | |||
Publishing your keybrd extension library with the following directory structure makes it easy for others to understand. | |||
keybrd_MyKeyboard/ | |||
@@ -25,16 +25,13 @@ Publishing your keybrd extension library with the following directory structure | |||
instantiations_codes.h | |||
instantiations_rows.h | |||
When your ready to list your keybrd extension library, go to the [Arduino Playground keybrd page](http://playground.arduino.cc/Main/keybrd). | |||
When your ready to list your keybrd extension library, | |||
add a link and short description of your keybrd extension library to the [Arduino Playground keybrd page](http://playground.arduino.cc/Main/keybrd) under "keybrd extension libraries". | |||
Arduino playground is a wiki. | |||
Links on how to edit the wiki are on the bottom left under "Participate". | |||
You can also add a picture of a keyboard that uses your keybrd extension library. | |||
Uploading files to the Playground is not allowed for standard users. | |||
So if you want to add a picture, it will need to be hosted somewhere else. | |||
Publishing on GitHub with listing on Arduino Library-Manager and Arduino Playground LibraryList | |||
----------------------------------------------------------------------------------------------- | |||
Publish on GitHub and list on Arduino Library-Manager and Arduino Playground | |||
---------------------------------------------------------------------------- | |||
The advantage of using GitHub is that users can submit pull requests. | |||
The advantage of using Arduino Library-Manager is that users can easily find and install your library through the Arduino IDE. | |||
@@ -78,14 +75,11 @@ Example library.properties file: | |||
Instructions for listing a library on Arduino Library Manager are at: | |||
https://github.com/arduino/Arduino/wiki/Library-Manager-FAQ | |||
After it has been accepted into the Arduino IDE Library Manager, add your keybrd extension library to the [Arduino Playground keybrd page](http://playground.arduino.cc/Main/keybrd). | |||
After it has been accepted into the Arduino IDE Library Manager, | |||
add a link and short description of your keybrd extension library to the [Arduino Playground keybrd page](http://playground.arduino.cc/Main/keybrd) under "keybrd extension libraries". | |||
Arduino playground is a wiki. | |||
Links on how to edit the wiki are on the bottom left under "Participate". | |||
You can also add a picture of a keyboard that uses your keybrd extension library. | |||
Uploading files to the Playground is not allowed for standard users. | |||
So if you want to add a picture, it will need to be hosted somewhere else. | |||
To publish a new release of a library that is already listed on Arduino Library Manager | |||
1. Update the version in your library.properties file: |
@@ -0,0 +1,17 @@ | |||
Tutorial 8c - sharing your keybrd sketch | |||
======================================== | |||
keybrd sketches that use a keybrd extension library should be published in the extension library's examples directory. | |||
keybrd sketches that do not use a keybrd extension library can be published anywhere. | |||
Publishing and listing your keybrd sketch allows others to find your sketch. | |||
Publish anywhere and list on Arduino Playground | |||
----------------------------------------------- | |||
Publish your sketch anywhere. Some free places are: | |||
* GitHub repository | |||
* [GitHub Gist](https://help.github.com/categories/gists/) | |||
* [geekhack Making Stuff Together!](https://geekhack.org/index.php?board=117.0) | |||
Then add a link and short description of your keybrd sketch to the [Arduino Playground keybrd page](http://playground.arduino.cc/Main/keybrd) under "keybrd sketches". | |||
Arduino playground is a wiki. | |||
Links on how to edit the wiki are on the bottom left under "Participate". |
@@ -0,0 +1,42 @@ | |||
/* this works | |||
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 <SPI.h> | |||
const uint8_t ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||
const uint8_t OPCODE_READ = (ADDR << 1 | 0x01); //MCP23S17 opcode read has LSB set | |||
const uint8_t IODIRB = 0x01; | |||
const uint8_t GPIOB = 0x13; | |||
uint8_t portBState = 0; //bit wise | |||
void setup() | |||
{ | |||
Serial.begin(9600); | |||
delay(1000); | |||
pinMode(SS, OUTPUT); //configure controller's Slave Select pin to output | |||
digitalWrite(SS, HIGH); //disable Slave Select | |||
SPI.begin(); | |||
//IODIRB register is already configured to input by default | |||
SPI.beginTransaction(SPISettings (SPI_CLOCK_DIV8, MSBFIRST, SPI_MODE0)); //gain control of SPI bus | |||
digitalWrite(SS, LOW); //enable Slave Select | |||
SPI.transfer(OPCODE_READ); //read command | |||
SPI.transfer(GPIOB); //register address to read data from | |||
portBState = SPI.transfer(0); //save the data (0 is dummy data to send) | |||
digitalWrite(SS, HIGH); //disable Slave Select | |||
SPI.endTransaction(); //release the SPI bus | |||
Serial.println(portBState, BIN); //should print 10101010 | |||
} | |||
void loop() { } |
@@ -0,0 +1,54 @@ | |||
/* this works with volt meter (MCP23S17 on 3.3v does not output enough power for LEDs) | |||
LED lights w/o resistor, not light with 56 ohm resistor | |||
blink LED on MCP23S17 port A pin | |||
from Example 41.1 - Microchip MCP23017 with Arduino | |||
http://tronixstuff.com/tutorials > chapter 41 | |||
http://tronixstuff.com/2011/08/26/tutorial-maximising-your-arduinos-io-ports/ | |||
John Boxall | CC by-sa-nc | |||
from http://69.5.26.215/forum/?id=10945&page=3 #35 | |||
modified to test MCP23S17 (SPI) using syntax from | |||
http://arduino.stackexchange.com/questions/16348/how-do-you-use-spi-on-an-arduino | |||
> | |||
SPISettings from http://arduino.stackexchange.com/questions/14191/mcp23s17-programming-iodirx-register-works-in-loop-but-not-in-setup | |||
*/ | |||
#include <SPI.h> | |||
const uint8_t ADDR = 0x20; //MCP23S17 address, all ADDR pins are grounded | |||
const uint8_t OPCODE_WRITE = (ADDR << 1); //MCP23S17 opcode write has LSB clear | |||
const uint8_t IODIRA = 0x00; //LEDs are on port A | |||
const uint8_t GPIOA = 0x12; | |||
uint8_t LED_state = 0; //bit wise | |||
void IOEWrite(const uint8_t registerAddr, const uint8_t data) | |||
{ | |||
SPI.beginTransaction(SPISettings (SPI_CLOCK_DIV8, MSBFIRST, SPI_MODE0)); //slower clock | |||
digitalWrite(SS, LOW); //enable Slave Select | |||
SPI.transfer(OPCODE_WRITE); //write command | |||
SPI.transfer(registerAddr); //register address to write data to | |||
SPI.transfer(data); //data | |||
digitalWrite(SS, HIGH); //disable Slave Select | |||
SPI.endTransaction(); //release the SPI bus | |||
} | |||
void setup() | |||
{ | |||
Serial.begin(9600); | |||
pinMode(SS, OUTPUT); //configure controller's Slave Select pin to output | |||
digitalWrite(SS, HIGH); //disable Slave Select | |||
SPI.begin(); | |||
IOEWrite(IODIRA, 0x00); //configure IODIRA register to output | |||
} | |||
void loop() | |||
{ | |||
IOEWrite(GPIOA, LED_state); //set all GPIOA pins | |||
delay(2000); | |||
//Serial.println(LED_state, BIN); //prints alternating 0 and 11111111 | |||
LED_state = ~LED_state; //toggle LED on/off | |||
} |
@@ -0,0 +1,32 @@ | |||
/* unit test for PortRead_MCP23S17 | |||
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 "PortWrite_MCP23S17.h" | |||
const uint8_t PortIOE::ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||
PortIOE portB(1, 0); | |||
PortRead_MCP23S17 portBRead(portB); | |||
PortWrite_MCP23S17 portBWrite(portB); //PortBWrite needed for begin() | |||
void setup() | |||
{ | |||
uint8_t portBState; //bit wise | |||
delay(6000); | |||
portBWrite.begin(); | |||
portBState = portBRead.read(); | |||
Keyboard.print("portBState = "); | |||
Keyboard.println(portBState, BIN); //should print 10101010 | |||
} | |||
void loop() { } |
@@ -0,0 +1,35 @@ | |||
/* unit test for PortRead_MCP23S17 | |||
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. | |||
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 | |||
*/ | |||
#include "PortIOE.h" | |||
#include "PortWrite_MCP23S17.h" | |||
const uint8_t PortIOE::ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded | |||
PortIOE portA(0, 0); | |||
PortWrite_MCP23S17 portAWrite(portA); //PortAWrite needed for begin() | |||
const uint8_t GPIOA = 0x12; //LEDs are on port A | |||
void setup() | |||
{ | |||
delay(6000); | |||
portAWrite.begin(); | |||
//Keyboard.print("start blinking"); | |||
} | |||
void loop() | |||
{ | |||
portAWrite.write(~0, HIGH); //set all GPIOA pins HIGH | |||
delay(2000); | |||
portAWrite.write(~0, LOW); //set all GPIOA pins LOW | |||
delay(2000); | |||
} |