snapshot, working on perf

pull/18/head
Jesse Vincent 10 years ago
parent bc2516607e
commit 3b6cc9f0b9

@ -1,6 +1,6 @@
#ifndef KeyboardIO_H_
#define KeyboardIO_H_
#include "Arduino.h"
#include <Arduino.h>
//add your includes for the project KeyboardIO here
#include <EEPROM.h>
@ -25,14 +25,13 @@ void setup();
#include "keymaps_generated.h"
#include "debouncing.h"
#include "led_control.h"
//extern int usbMaxPower;
#define DEBUG_SERIAL 0
byte matrixState[ROWS][COLS];
byte matrixState[ROWS][COLS];
byte charsBeingReported[KEYS_HELD_BUFFER]; // A bit vector for the 256 keys we might conceivably be holding down
byte charsReportedLastTime[KEYS_HELD_BUFFER]; // A bit vector for the 256 keys we might conceivably be holding down
@ -73,6 +72,8 @@ void warp_mouse(Key key);
// hardware keymap interaction
void setup_pins();
void setup_input_pins();
void setup_output_pins();
void scan_matrix();
// key matrix

@ -3,22 +3,34 @@
// Copyright 2013 Jesse Vincent <jesse@fsck.com>
// All Rights Reserved. (To be licensed under an opensource license
// before the release of the keyboard.io model 01
#define DEBUG_SERIAL false
/**
* TODO:
TEST
TEST2
#left IO Expander found at 0x00
add mouse inertia
add series-of-character macros
add series of keystroke macros
use a lower-level USB API
*
**/
*/
#include "ArduinoKeyboard.h"
#include <EEPROM.h> // Don't need this for CLI compilation, but do need it in the IDE
#include <digitalWriteFast.h>
#include "digitalWriteFast.h"
#include <Wire.h>
#include "sx1509_library.h"
const byte LEFT_SX1509_ADDRESS = 0x70; // SX1509 I2C address (10)
const byte RIGHT_SX1509_ADDRESS = 0x71; // SX1509 I2C address (11)
sx1509Class leftsx1509(LEFT_SX1509_ADDRESS);
sx1509Class rightsx1509(RIGHT_SX1509_ADDRESS);
void setup_matrix()
{
@ -33,7 +45,6 @@ void reset_matrix()
{
for (byte col = 0; col < COLS; col++) {
for (byte row = 0; row < ROWS; row++) {
matrixState[row][col] <<= 1;
}
}
}
@ -70,16 +81,33 @@ void set_keymap(Key keymapEntry, byte matrixStateEntry) {
void scan_matrix()
{
//scan the Keyboard matrix looking for connections
for (byte row = 0; row < ROWS; row++) {
digitalWriteFast(rowPins[row], LOW);
for (byte col = 0; col < COLS; col++) {
for (byte row = 0; row < LEFT_ROWS; row++) {
leftsx1509.rawWritePin(left_rowpins[row], LOW);
rightsx1509.rawWritePin(right_rowpins[row], LOW);
for (byte col = 0; col < LEFT_COLS; col++) {
//If we see an electrical connection on I->J,
if (digitalReadFast(colPins[col])) {
matrixState[row][col] |= 0;
matrixState[row][col] <<= 1;
matrixState[row][(COLS-1)-col] <<= 1;
if (leftsx1509.rawReadPin(left_colpins[col])) {
matrixState[row][col] |= 0;
} else {
matrixState[row][col] |= 1;
matrixState[row][col] |= 1;
}
if (rightsx1509.rawReadPin(right_colpins[col])) {
matrixState[row][(COLS - 1) - col] |= 0;
} else {
matrixState[row][(COLS - 1) - col] |= 1;
}
// while we're inspecting the electrical matrix, we look
// to see if the Key being held is a firmware level
// metakey, so we can act on it, lest we only discover
@ -87,10 +115,14 @@ void scan_matrix()
// through the matrix scan
set_keymap(keymaps[active_keymap][row][col], matrixState[row][col]);
// set_keymap(keymaps[active_keymap][row][col], matrixState[row][col]);
// set_keymap(keymaps[active_keymap][row][(COLS - 1) - col], matrixState[row][(COLS - 1) - col]);
}
digitalWriteFast(rowPins[row], HIGH);
leftsx1509.rawWritePin(left_rowpins[row], HIGH);
rightsx1509.rawWritePin(right_rowpins[row], HIGH);
}
}
@ -99,124 +131,127 @@ void scan_matrix()
void command_reboot_bootloader() {
Keyboard.println("Rebooting to bootloader");
Serial.end();
Keyboard.println("Rebooting to bootloader");
Serial.end();
// Set the magic bits to get a Caterina-based device
// to reboot into the bootloader and stay there, rather
// than run move onward
//
// These values are the same as those defined in
// Caterina.c
uint16_t bootKey = 0x7777;
uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
// Set the magic bits to get a Caterina-based device
// to reboot into the bootloader and stay there, rather
// than run move onward
//
// These values are the same as those defined in
// Caterina.c
uint16_t bootKey = 0x7777;
uint16_t *const bootKeyPtr = (uint16_t *)0x0800;
// Stash the magic key
*bootKeyPtr = bootKey;
// Stash the magic key
*bootKeyPtr = bootKey;
// Set a watchdog timer
wdt_enable(WDTO_120MS);
// Set a watchdog timer
wdt_enable(WDTO_120MS);
while(1) {} // This infinite loop ensures nothing else
// happens before the watchdog reboots us
while (1) {} // This infinite loop ensures nothing else
// happens before the watchdog reboots us
}
void command_plugh() {
commandMode = !commandMode;
if (commandMode) {
Keyboard.println("");
Keyboard.println("Entering command mode!");
} else {
Keyboard.println("Leaving command mode!");
Keyboard.println("");
}
commandMode = !commandMode;
if (commandMode) {
Keyboard.println("");
Keyboard.println("Entering command mode!");
} else {
Keyboard.println("Leaving command mode!");
Keyboard.println("");
}
}
void setup_command_mode() {
commandBufferSize=0;
commandMode = false;
commandPromptPrinted = false;
commandBufferSize = 0;
commandMode = false;
commandPromptPrinted = false;
}
boolean command_ends_in_return() {
if (
commandBuffer[commandBufferSize-1] == KEY_ENTER ||
commandBuffer[commandBufferSize-1] == KEY_RETURN ) {
return true;
commandBuffer[commandBufferSize - 1] == KEY_ENTER ||
commandBuffer[commandBufferSize - 1] == KEY_RETURN ) {
return true;
} else {
return false;
return false;
}
}
boolean is_command_buffer(byte* myCommand) {
if (!command_ends_in_return()) {
if (!command_ends_in_return()) {
return false;
}
int i = 0;
do {
if (commandBuffer[i] != myCommand[i]) {
return false;
}
int i = 0;
do {
if (commandBuffer[i] != myCommand[i]) {
return false;
}
} while (myCommand[++i] != NULL);
return true;
} while (myCommand[++i] != NULL);
return true;
}
void process_command_buffer(){
void process_command_buffer() {
if (!command_ends_in_return()) {
return;
return;
}
// This is the only command we might want to execute when
// we're not in command mode, as it's the only way to toggle
// This is the only command we might want to execute when
// we're not in command mode, as it's the only way to toggle
// command mode on
static byte cmd_plugh[] = {KEY_P,KEY_L,KEY_U,KEY_G,KEY_H,NULL};
static byte cmd_plugh[] = {KEY_P, KEY_L, KEY_U, KEY_G, KEY_H, NULL};
if (is_command_buffer(cmd_plugh)) {
command_plugh();
command_plugh();
}
// if we've toggled command mode off, get out of here.
if (!commandMode) {
commandBufferSize=0;
return;
commandBufferSize = 0;
return;
}
// Handle all the other commands here
static byte cmd_reboot_bootloader[] = { KEY_B, KEY_O, KEY_O, KEY_T, KEY_L, KEY_O, KEY_A, KEY_D, KEY_E, KEY_R, NULL};
static byte cmd_version[] = { KEY_V, KEY_E, KEY_R, KEY_S, KEY_I, KEY_O, KEY_N, NULL};
if(is_command_buffer(cmd_reboot_bootloader)) {
command_reboot_bootloader();
} else if (is_command_buffer(cmd_version)) {
Keyboard.println("");
Keyboard.print("This is Keyboardio Firmware ");
Keyboard.println(VERSION);
}
// Handle all the other commands here
static byte cmd_reboot_bootloader[] = { KEY_B, KEY_O, KEY_O, KEY_T, KEY_L, KEY_O, KEY_A, KEY_D, KEY_E, KEY_R, NULL};
static byte cmd_version[] = { KEY_V, KEY_E, KEY_R, KEY_S, KEY_I, KEY_O, KEY_N, NULL};
if (!commandPromptPrinted ){
if (is_command_buffer(cmd_reboot_bootloader)) {
command_reboot_bootloader();
} else if (is_command_buffer(cmd_version)) {
Keyboard.println("");
Keyboard.print("This is Keyboardio Firmware ");
Keyboard.println(VERSION);
}
if (!commandPromptPrinted ) {
Keyboard.print(">>> ");
commandPromptPrinted = true;
commandBufferSize=0;
commandBufferSize = 0;
}
}
void setup()
{
wdt_disable();
wdt_disable();
delay(5000);
Serial.begin(9600);
//usbMaxPower = 100;
Keyboard.begin();
Mouse.begin();
setup_leds();
update_leds();
setup_command_mode();
setup_matrix();
setup_pins();
Serial.begin(9600);
primary_keymap = load_primary_keymap();
}
@ -224,14 +259,13 @@ String myApp;
void loop()
{
if(Serial.available()) {
myApp = Serial.readString();
myApp.trim();
}
// if(Serial.available()) {
// myApp = Serial.readString();
// myApp.trim();
// }
active_keymap = primary_keymap;
scan_matrix();
send_key_events();
reset_matrix();
reset_key_report();
}
@ -348,10 +382,9 @@ void record_key_being_pressed(byte character)
void reset_key_report()
{
for (byte i = 0; i < KEYS_HELD_BUFFER; i++) {
charsReportedLastTime[i] = charsBeingReported[i];
charsBeingReported[i] = 0x00;
}
memcpy( charsReportedLastTime,charsBeingReported, KEYS_HELD_BUFFER);
memset(charsBeingReported,0,KEYS_HELD_BUFFER);
}
@ -419,21 +452,21 @@ void send_key_events()
}
else {
if (String("Slack") == myApp) {
if (key_is_pressed(switchState)) {
record_key_being_pressed(mappedKey.rawKey);
if (key_is_pressed(switchState)) {
record_key_being_pressed(mappedKey.rawKey);
if (key_toggled_on (switchState)) {
Keyboard.print("Never gonna give you up!");
Keyboard.print("Never gonna give you up!");
}
}
} else {
if (key_is_pressed(switchState)) {
record_key_being_pressed(mappedKey.rawKey);
if (key_toggled_on (switchState)) {
press_key(mappedKey);
}
} else if (key_toggled_off (switchState)) {
} else {
if (key_is_pressed(switchState)) {
record_key_being_pressed(mappedKey.rawKey);
if (key_toggled_on (switchState)) {
press_key(mappedKey);
}
} else if (key_toggled_off (switchState)) {
release_key(mappedKey);
}
}
}
}
}
@ -443,47 +476,71 @@ void send_key_events()
}
void press_key(Key mappedKey) {
Keyboard.press(mappedKey.rawKey);
if (commandBufferSize>=31){
commandBufferSize=0;
}
commandBuffer[commandBufferSize++]=mappedKey.rawKey;
Keyboard.press(mappedKey.rawKey);
if (commandBufferSize >= 31) {
commandBufferSize = 0;
}
commandBuffer[commandBufferSize++] = mappedKey.rawKey;
if( mappedKey.rawKey == KEY_ENTER ||
mappedKey.rawKey == KEY_RETURN ) {
commandPromptPrinted=false;
process_command_buffer();
commandBufferSize=0;
}
if ( mappedKey.rawKey == KEY_ENTER ||
mappedKey.rawKey == KEY_RETURN ) {
commandPromptPrinted = false;
process_command_buffer();
commandBufferSize = 0;
}
}
void release_key(Key mappedKey){
Keyboard.release(mappedKey.rawKey);
void release_key(Key mappedKey) {
Keyboard.release(mappedKey.rawKey);
}
// Hardware initialization
void setup_pins()
{
setup_output_pins();
setup_input_pins();
void make_input(sx1509Class sx1509, int pin) {
sx1509.pinDir(pin, INPUT); // Set SX1509 pin 1 as an input
sx1509.writePin(pin, HIGH); // Activate pull-up
}
void setup_output_pins() {
//set up the row pins as outputs
for (byte row = 0; row < ROWS; row++) {
pinMode(rowPins[row], OUTPUT);
digitalWriteFast(rowPins[row], HIGH);
}
void make_output(sx1509Class sx1509, int pin) {
sx1509.pinDir(pin, OUTPUT);
sx1509.writePin(pin, HIGH);
}
void setup_input_pins {
for (byte col = 0; col < COLS; col++) {
pinMode(colPins[col], INPUT);
digitalWriteFast(colPins[col], HIGH);
//drive em high by default s it seems to be more reliable than driving em low
void setup_pins() {
if (rightsx1509.init()) { // init ok
for (int i = 0; i < RIGHT_ROWS; i++) {
make_output(rightsx1509, right_rowpins[i]);
}
for (int j = 0; j < RIGHT_COLS; j++) {
make_input(rightsx1509, right_colpins[j]);
}
}
if (leftsx1509.init()) { // init ok
for (int i = 0; i < LEFT_ROWS; i++) {
make_output(leftsx1509, left_rowpins[i]);
}
for (int j = 0; j < LEFT_COLS; j++) {
make_input(leftsx1509, left_colpins[j]);
}
}
}

@ -1,112 +1,53 @@
//#define DEBUG_SERIAL false
#ifndef KEYBOARD_CONFIG_H
#define KEYBOARD_CONFIG_H
#include "WS2812.h"
#define EEPROM_KEYMAP_LOCATION 0
#define MODEL01keytest true
#define MODEL01 true
#ifdef MODEL00
#define COLS 14
#ifdef SYMMETRIC60
#define ROWS 5
static const byte colPins[COLS] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, A0 };
static const byte rowPins[ROWS] = { A5, A4, A3, A2, A1 };
#define COLS 14
static const byte colPins[COLS] = {
A0, 3,13, 5, 10, 9, 8, 6, 12, 4, 11, 1, 0, 2 };
static const byte rowPins[ROWS] = { A5,A4,A3,A2,A1};
#define LED_DATA_PIN 7
#define LED_COUNT 0
static const int key_led_map[ROWS][COLS] = {};
#endif
#ifdef MODEL00bis
#define COLS 14
#define ROWS 5
static const byte colPins[COLS] = { 0,1, 2, 3, 4, 5,6,7, 8, 9, 10,11,12, A0};
#ifdef MODEL01
static const byte rowPins[ROWS] = { A1,A2,A3,A4,A5};
#endif
int RIGHT_COLS=8;
int RIGHT_ROWS=4;
#ifdef MODEL00piersjesse
#define COLS 16
#define ROWS 4
static const byte colPins[COLS] = {
MOSI,
SCK,
1,
0,
2,
3,
4,
9,
8,
5,
6,
7,
MISO,
12,
A5,
A4
};
static const byte rowPins[ROWS] = { A0, A1,A2,A3 };
int LEFT_COLS=8;
int LEFT_ROWS=4;
int left_colpins[]={7,6,5,4,3,2,1,0};
int left_rowpins[]={8,9,10,11};
#endif
int right_colpins[]={0,1,2,3,4,5,6,7};
int right_rowpins[]={8,9,10,11};
#ifdef MODEL01keytest
#define COLS 16
#define ROWS 4
static const byte colPins[COLS] = {
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
SCK,
MISO,
A5,
A4,
};
static const byte rowPins[ROWS] = { A0, A1,A2,A3 };
#endif
#ifdef MODEL00piers
#define COLS 16
#define ROWS 5
static const byte colPins[COLS] = {
3,
A4,
A5,
MISO,
SCK,
1,
MOSI,
2,
4,
5,
7,
8,
9,
10,
0,
12,
};
static const byte rowPins[ROWS] = { A0, A1,A2,A3 };
#define ROWS 4
#endif
//#static const byte colPins[COLS] = { 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
//#static const byte rowPins[ROWS] = { A2, A3, A4, A5, 15 };
// if we're sticking to boot protocol, these could all be 6 + mods
// but *mumble*
#define KEYS_HELD_BUFFER 12
#endif

@ -1,15 +1,15 @@
# Arduino Make file. Refer to https://github.com/sudar/Arduino-Makefile
#BOARD_TAG = keyboardio
BOARD = micro
BOARD = symmetric60
PORT = /dev/cu.usbmodem1421
ARDUINO_LIBS =
THIRD_PARTY_HARDWARE=hardware/keyboardio/avr
#ARDUINO_CORE_PATH = hardware/keyboardio/cores/keyboardio
#ALTERNATE_CORE = keyboardio
GIT_VERSION := $(shell git describe --abbrev=4 --dirty --always)
include _Makefile.Master
include ./_Makefile.Master
include ./blank
astyle:
astyle --style=linux ArduinoKeyboard.ino *.h

@ -700,4 +700,4 @@ upload_monitor : upload monitor
upmonitor: upload_monitor
-include $(wildcard $(BUILD_DIR)/.*.dep))
#-include $(wildcard $(BUILD_DIR)/.*.dep))

@ -6,7 +6,7 @@
boolean key_was_pressed (byte keyState)
{
if ( byte((keyState >> 4)) ^ B00001111 ) {
if ( byte((keyState >> 7)) ^ B00000001 ) {
return false;
} else {
return true;
@ -16,18 +16,16 @@ boolean key_was_pressed (byte keyState)
boolean key_was_not_pressed (byte keyState)
{
if ( byte((keyState >> 4)) ^ B00000000 ) {
return false;
} else {
return true;
}
return !key_was_pressed(keyState);
}
boolean key_is_pressed (byte keyState)
{
if ( byte((keyState << 4)) ^ B11110000 ) {
if ( byte((keyState << 7)) ^ B10000000 ) {
return false;
} else {
return true;
@ -35,12 +33,8 @@ boolean key_is_pressed (byte keyState)
}
boolean key_is_not_pressed (byte keyState)
{
return(!key_is_pressed(keyState));
if ( byte((keyState << 4)) ^ B00000000 ) {
return false;
} else {
return true;
}
}
boolean key_toggled_on(byte keyState)

@ -0,0 +1,572 @@
/*
sx1509_library.cpp
Code file for the SX1509 Arduino library.
by: Jim Lindblom
SparkFun Electronics
date: December 13, 2012
license: Beerware. Feel free to use it, with or without attribution, in
your own projects. If you find it helpful, buy me a beer next time you
see me at the local pub.
In here you'll find the Arduino code used to interface with the SX1509 I2C
16 I/O expander. There are functions to take advantage of everything the
SX1509 provides - input/output setting, writing pins high/low, reading
the input value of pins, LED driver utilities (blink, breath, pwm), and
keypad engine utilites.
See the header file (sx1509_library.h) for detailed descriptions of each of
the sx1509Class methods.
For example uses of these functions, see the Arduino example codes in the
./examples/ folder.
*/
#include <Wire.h>
#include "Arduino.h"
#include "sx1509_library.h"
#include "sx1509_registers.h"
sx1509Class::sx1509Class(byte address, byte resetPin, byte interruptPin, byte oscillatorPin)
{
// Store the received parameters into member variables
deviceAddress = address;
pinInterrupt = interruptPin;
pinOscillator = oscillatorPin;
pinReset = resetPin;
}
byte sx1509Class::init(void)
{
if (pinInterrupt != 255)
{
pinMode(pinInterrupt, INPUT_PULLUP);
}
// Begin I2C
Wire.begin();
// If the reset pin is connected
if (pinReset != 255)
reset(1);
else
reset(0);
// Communication test. We'll read from two registers with different
// default values to verify communication.
unsigned int testRegisters = 0;
testRegisters = readWord(REG_INTERRUPT_MASK_A); // This should return 0xFF00
// Then read a byte that should be 0x00
if (testRegisters == 0xFF00)
return 1;
else
return 0;
}
void sx1509Class::reset(bool hardware)
{
// if hardware bool is set
if (hardware)
{
// Check if bit 2 of REG_MISC is set
// if so nReset will not issue a POR, we'll need to clear that bit first
byte regMisc = readByte(REG_MISC);
if (regMisc & (1<<2))
{
regMisc &= ~(1<<2);
writeByte(REG_MISC, regMisc);
}
// Reset the SX1509, the pin is active low
pinMode(pinReset, OUTPUT); // set reset pin as output
digitalWrite(pinReset, LOW); // pull reset pin low
delay(1); // Wait for the pin to settle
digitalWrite(pinReset, HIGH); // pull reset pin back high
}
else
{
// Software reset command sequence:
writeByte(REG_RESET, 0x12);
writeByte(REG_RESET, 0x34);
}
}
void sx1509Class::pinDir(byte pin, byte inOut)
{
unsigned int tempRegDir = readWord(REG_DIR_B);
// The SX1509 RegDir registers: REG_DIR_B, REG_DIR_A
// 0: IO is configured as an output
// 1: IO is configured as an input
// Flip inOut, in arduino.h INPUT = 0, OUTPUT = 1
if (!inOut) tempRegDir |= (1<<pin);
else tempRegDir &= ~(1<<pin);
writeWord(REG_DIR_B, tempRegDir);
}
void sx1509Class::rawWritePin(byte pin, byte highLow)
{
if (highLow)
writeWord(REG_DATA_B, readWord(REG_DATA_B) | (1 <<pin));
else
writeWord(REG_DATA_B, readWord(REG_DATA_B) & ~(1<<pin));
}
void sx1509Class::writePin(byte pin, byte highLow)
{
if ((0xFFFF^readWord(REG_DIR_B))&(1<<pin)) // If the pin is an output, write high/low
{
unsigned int tempRegData = readWord(REG_DATA_B);
if (highLow) tempRegData |= (1<<pin);
else tempRegData &= ~(1<<pin);
writeWord(REG_DATA_B, tempRegData);
}
else // Otherwise the pin is an input, pull-up/down
{
unsigned int tempPullUp = readWord(REG_PULL_UP_B);
unsigned int tempPullDown = readWord(REG_PULL_DOWN_B);
if (highLow) // if HIGH, do pull-up, disable pull-down
{
tempPullUp |= (1<<pin);
tempPullDown &= ~(1<<pin);
writeWord(REG_PULL_UP_B, tempPullUp);
writeWord(REG_PULL_DOWN_B, tempPullDown);
}
else // If LOW do pull-down, disable pull-up
{
tempPullDown |= (1<<pin);
tempPullUp &= ~(1<<pin);
writeWord(REG_PULL_UP_B, tempPullUp);
writeWord(REG_PULL_DOWN_B, tempPullDown);
}
}
}
byte sx1509Class::rawReadPin(byte pin)
{
return (readWord(REG_DATA_B) & (1<<pin));
}
byte sx1509Class::readPin(byte pin)
{
if (readWord(REG_DIR_B) & (1<<pin)) // If the pin is an input
{
unsigned int tempRegData = readWord(REG_DATA_B);
if (tempRegData & (1<<pin))
return 1;
}
return 0;
}
void sx1509Class::ledDriverInit(byte pin, byte freq, bool log)
{
unsigned int tempWord;
byte tempByte;
// Disable input buffer
// Writing a 1 to the pin bit will disable that pins input buffer
tempWord = readWord(REG_INPUT_DISABLE_B);
tempWord |= (1<<pin);
writeWord(REG_INPUT_DISABLE_B, tempWord);
// Disable pull-up
// Writing a 0 to the pin bit will disable that pull-up resistor
tempWord = readWord(REG_PULL_UP_B);
tempWord &= ~(1<<pin);
writeWord(REG_PULL_UP_B, tempWord);
// Enable open-drain
// Writing a 1 to the pin bit will enable open drain on that pin
tempWord = readWord(REG_OPEN_DRAIN_B);
tempWord |= (1<<pin);
writeWord(REG_OPEN_DRAIN_B, tempWord);
// Set direction to output (REG_DIR_B)
pinDir(pin, OUTPUT);
// Enable oscillator (REG_CLOCK)
tempByte = readByte(REG_CLOCK);
tempByte |= (1<<6); // Internal 2MHz oscillator part 1 (set bit 6)
tempByte &= ~(1<<5); // Internal 2MHz oscillator part 2 (clear bit 5)
writeByte(REG_CLOCK, tempByte);
// Configure LED driver clock and mode (REG_MISC)
tempByte = readByte(REG_MISC);
if (log)
{
tempByte |= (1<<7); // set logarithmic mode bank B
tempByte |= (1<<3); // set logarithmic mode bank A
}
else
{
tempByte &= ~(1<<7); // set linear mode bank B
tempByte &= ~(1<<3); // set linear mode bank A
}
if (freq == 0) // don't want it to be 0, that'll disable all led drivers
freq = 1;
freq = (freq & 0x07) << 4; // freq should only be 3 bits from 6:4
tempByte |= freq;
writeByte(REG_MISC, tempByte);
// Enable LED driver operation (REG_LED_DRIVER_ENABLE)
tempWord = readWord(REG_LED_DRIVER_ENABLE_B);
tempWord |= (1<<pin);
writeWord(REG_LED_DRIVER_ENABLE_B, tempWord);
// Set REG_DATA bit low ~ LED driver started
tempWord = readWord(REG_DATA_B);
tempWord &= ~(1<<pin);
writeWord(REG_DATA_B, tempWord);
}
void sx1509Class::pwm(byte pin, byte iOn)
{
// Write the on intensity of pin
// Linear mode: Ion = iOn
// Log mode: Ion = f(iOn)
writeByte(REG_I_ON[pin], iOn);
}
void sx1509Class::blink(byte pin, byte tOn, byte tOff,
byte offIntensity, byte onIntensity,
byte tRise, byte tFall)
{
// Keep parameters within their limits:
tOn &= 0x1F; // tOn should be a 5-bit value
tOff &= 0x1F; // tOff should be a 5-bit value
offIntensity &= 0x07;
// Write the time on
// 1-15: TON = 64 * tOn * (255/ClkX)
// 16-31: TON = 512 * tOn * (255/ClkX)
writeByte(REG_T_ON[pin], tOn);
// Write the time/intensity off register
// 1-15: TOFF = 64 * tOff * (255/ClkX)
// 16-31: TOFF = 512 * tOff * (255/ClkX)
// linear Mode - IOff = 4 * offIntensity
// log mode - Ioff = f(4 * offIntensity)
writeByte(REG_OFF[pin], (tOff<<3) | offIntensity);
// Write the on intensity:
writeByte(REG_I_ON[pin], onIntensity);
// Prepare tRise and tFall
tRise &= 0x1F; // tRise is a 5-bit value
tFall &= 0x1F; // tFall is a 5-bit value
// Write regTRise
// 0: Off
// 1-15: TRise = (regIOn - (4 * offIntensity)) * tRise * (255/ClkX)
// 16-31: TRise = 16 * (regIOn - (4 * offIntensity)) * tRise * (255/ClkX)
if (REG_T_RISE[pin] != 0xFF)
writeByte(REG_T_RISE[pin], tRise);
// Write regTFall
// 0: off
// 1-15: TFall = (regIOn - (4 * offIntensity)) * tFall * (255/ClkX)
// 16-31: TFall = 16 * (regIOn - (4 * offIntensity)) * tFall * (255/ClkX)
if (REG_T_FALL[pin] != 0xFF)
writeByte(REG_T_FALL[pin], tFall);
}
void sx1509Class::keypad(byte rows, byte columns, byte sleepTime, byte scanTime)
{
unsigned int tempWord;
byte tempByte;
// Set regDir 0:7 outputs, 8:15 inputs:
tempWord = readWord(REG_DIR_B);
for (int i=0; i<rows; i++)
tempWord &= ~(1<<i);
for (int i=8; i<(columns * 2); i++)
tempWord |= (1<<i);
writeWord(REG_DIR_B, tempWord);
// Set regOpenDrain on 0:7:
tempByte = readByte(REG_OPEN_DRAIN_A);
for (int i=0; i<rows; i++)
tempByte |= (1<<i);
writeByte(REG_OPEN_DRAIN_A, tempByte);
// Set regPullUp on 8:15:
tempByte = readByte(REG_PULL_UP_B);
for (int i=0; i<columns; i++)
tempByte |= (1<<i);
writeByte(REG_PULL_UP_B, tempByte);
// Enable and configure debouncing on 8:15:
tempByte = readByte(REG_DEBOUNCE_ENABLE_B);
for (int i=0; i<columns; i++)
tempByte |= (1<<i);
writeByte(REG_DEBOUNCE_ENABLE_B, tempByte);
writeByte(REG_DEBOUNCE_CONFIG, (scanTime & 0b111)); // Debounce must be less than scan time
// RegKeyConfig1 sets the auto sleep time and scan time per row
sleepTime = (sleepTime & 0b111)<<4;
scanTime &= 0b111; // Scan time is bits 2:0
tempByte = sleepTime | scanTime;
writeByte(REG_KEY_CONFIG_1, tempByte);
// RegKeyConfig2 tells the SX1509 how many rows and columns we've got going
rows = (rows - 1) & 0b111; // 0 = off, 0b001 = 2 rows, 0b111 = 8 rows, etc.
columns = (columns - 1) & 0b111; // 0b000 = 1 column, ob111 = 8 columns, etc.
writeByte(REG_KEY_CONFIG_2, (rows << 3) | columns);
}
unsigned int sx1509Class::readKeyData()
{
return (0xFFFF ^ readWord(REG_KEY_DATA_1));
}
void sx1509Class::sync(void)
{
// First check if nReset functionality is set
byte regMisc = readByte(REG_MISC);
if (!(regMisc & 0x04))
{
regMisc |= (1<<2);
writeByte(REG_MISC, regMisc);
}
// Toggle nReset pin to sync LED timers
pinMode(pinReset, OUTPUT); // set reset pin as output
digitalWrite(pinReset, LOW); // pull reset pin low
delay(1); // Wait for the pin to settle
digitalWrite(pinReset, HIGH); // pull reset pin back high
// Return nReset to POR functionality
writeByte(REG_MISC, (regMisc & ~(1<<2)));
}
void sx1509Class::debounceConfig(byte configValue)
{
// First make sure clock is configured
byte tempByte = readByte(REG_MISC);
if ((tempByte & 0x70) == 0)
{
tempByte |= (1<<4); // Just default to no divider if not set
writeByte(REG_MISC, tempByte);
}
tempByte = readByte(REG_CLOCK);
if ((tempByte & 0x60) == 0)
{
tempByte |= (1<<6); // default to internal osc.
writeByte(REG_CLOCK, tempByte);
}
configValue &= 0b111; // 3-bit value
writeByte(REG_DEBOUNCE_CONFIG, configValue);
}
void sx1509Class::debounceEnable(byte pin)
{
unsigned int debounceEnable = readWord(REG_DEBOUNCE_ENABLE_B);
debounceEnable |= (1<<pin);
writeWord(REG_DEBOUNCE_ENABLE_B, debounceEnable);
}
void sx1509Class::enableInterrupt(byte pin, byte riseFall)
{
// Set REG_INTERRUPT_MASK
unsigned int tempWord = readWord(REG_INTERRUPT_MASK_B);
tempWord &= ~(1<<pin); // 0 = event on IO will trigger interrupt
writeWord(REG_INTERRUPT_MASK_B, tempWord);
byte sensitivity = 0;
switch (riseFall)
{
case CHANGE:
sensitivity = 0b11;
break;
case FALLING:
sensitivity = 0b10;
break;
case RISING:
sensitivity = 0b01;
break;
}
// Set REG_SENSE_XXX
// Sensitivity is set as follows:
// 00: None
// 01: Rising
// 10: Falling
// 11: Both
byte pinMask = (pin & 0x07) * 2;
byte senseRegister;
// Need to select between two words. One for bank A, one for B.
if (pin >= 8) senseRegister = REG_SENSE_HIGH_B;
else senseRegister = REG_SENSE_HIGH_A;
tempWord = readWord(senseRegister);
tempWord &= ~(0b11<<pinMask); // Mask out the bits we want to write
tempWord |= (sensitivity<<pinMask); // Add our new bits
writeWord(senseRegister, tempWord);
}
unsigned int sx1509Class::interruptSource(void)
{
unsigned int intSource = readWord(REG_INTERRUPT_SOURCE_B);
writeWord(REG_INTERRUPT_SOURCE_B, 0xFFFF); // Clear interrupts
return intSource;
}
void sx1509Class::configClock(byte oscSource, byte oscPinFunction, byte oscFreqOut, byte oscDivider)
{
// RegClock constructed as follows:
// 6:5 - Oscillator frequency souce
// 00: off, 01: external input, 10: internal 2MHz, 1: reserved
// 4 - OSCIO pin function
// 0: input, 1 ouptut
// 3:0 - Frequency of oscout pin
// 0: LOW, 0xF: high, else fOSCOUT = FoSC/(2^(RegClock[3:0]-1))
oscSource = (oscSource & 0b11)<<5; // 2-bit value, bits 6:5
oscPinFunction = (oscPinFunction & 1)<<4; // 1-bit value bit 4
oscFreqOut = (oscFreqOut & 0b1111); // 4-bit value, bits 3:0
byte regClock = oscSource | oscPinFunction | oscFreqOut;
writeByte(REG_CLOCK, regClock);
// Config RegMisc[6:4] with oscDivider
// 0: off, else ClkX = fOSC / (2^(RegMisc[6:4] -1))
oscDivider = (oscDivider & 0b111)<<4; // 3-bit value, bits 6:4
byte regMisc = readByte(REG_MISC);
regMisc &= ~(0b111<<4);
regMisc |= oscDivider;
writeByte(REG_MISC, regMisc);
}
// readByte(byte registerAddress)
// This function reads a single byte located at the registerAddress register.
// - deviceAddress should already be set by the constructor.
// - Return value is the byte read from registerAddress
// - Currently returns 0 if communication has timed out
byte sx1509Class::readByte(byte registerAddress)
{
byte readValue;
unsigned int timeout = RECEIVE_TIMEOUT_VALUE;
Wire.beginTransmission(deviceAddress);
Wire.write(registerAddress);
Wire.endTransmission();
Wire.requestFrom(deviceAddress, (byte) 1);
while ((Wire.available() < 1) && (timeout != 0))
timeout--;
if (timeout == 0)
return 0;
readValue = Wire.read();
return readValue;
}
// readWord(byte registerAddress)
// This function will read a two-byte word beginning at registerAddress
// - A 16-bit unsigned int will be returned.
// - The msb of the return value will contain the value read from registerAddress
// - The lsb of the return value will contain the value read from registerAddress + 1
unsigned int sx1509Class::readWord(byte registerAddress)
{
unsigned int readValue;
unsigned int msb, lsb;
unsigned int timeout = RECEIVE_TIMEOUT_VALUE * 2;
Wire.beginTransmission(deviceAddress);
Wire.write(registerAddress);
Wire.endTransmission();
Wire.requestFrom(deviceAddress, (byte) 2);
while ((Wire.available() < 2) && (timeout != 0))
timeout--;
if (timeout == 0)
return 0;
msb = (Wire.read() & 0x00FF) << 8;
lsb = (Wire.read() & 0x00FF);
readValue = msb | lsb;
return readValue;
}
// readBytes(byte firstRegisterAddress, byte * destination, byte length)
// This function reads a series of bytes incrementing from a given address
// - firstRegsiterAddress is the first address to be read
// - destination is an array of bytes where the read values will be stored into
// - length is the number of bytes to be read
// - No return value.
void sx1509Class::readBytes(byte firstRegisterAddress, byte * destination, byte length)
{
byte readValue;
Wire.beginTransmission(deviceAddress);
Wire.write(firstRegisterAddress);
Wire.endTransmission();
Wire.requestFrom(deviceAddress, length);
while (Wire.available() < length)
;
for (int i=0; i<length; i++)
{
destination[i] = Wire.read();
}
}
// writeByte(byte registerAddress, byte writeValue)
// This function writes a single byte to a single register on the SX509.
// - writeValue is written to registerAddress
// - deviceAddres should already be set from the constructor
// - No return value.
void sx1509Class::writeByte(byte registerAddress, byte writeValue)
{
Wire.beginTransmission(deviceAddress);
Wire.write(registerAddress);
Wire.write(writeValue);
Wire.endTransmission();
}
// writeWord(byte registerAddress, ungisnged int writeValue)
// This function writes a two-byte word to registerAddress and registerAddress + 1
// - the upper byte of writeValue is written to registerAddress
// - the lower byte of writeValue is written to registerAddress + 1
// - No return value.
void sx1509Class::writeWord(byte registerAddress, unsigned int writeValue)
{
Wire.beginTransmission(deviceAddress);
Wire.write(registerAddress);
Wire.write((writeValue & 0xFF00) >> 8);
Wire.write(writeValue & 0x00FF);
Wire.endTransmission();
}
// writeBytes(byte firstRegisterAddress, byte * writeArray, byte length)
// This function writes an array of bytes, beggining at a specific adddress
// - firstRegisterAddress is the initial register to be written.
// - All writes following will be at incremental register addresses.
// - writeArray should be an array of byte values to be written.
// - length should be the number of bytes to be written.
// - no return value.
void sx1509Class::writeBytes(byte firstRegisterAddress, byte * writeArray, byte length)
{
Wire.beginTransmission(deviceAddress);
Wire.write(firstRegisterAddress);
for (int i=0; i<length; i++)
{
Wire.write(writeArray[i]);
}
Wire.endTransmission();
}

@ -0,0 +1,337 @@
/*
sx1509_library.h
Header file for the SX1509 Arduino library.
by: Jim Lindblom
SparkFun Electronics
date: December 13, 2012
license: Beerware. Feel free to use it, with or without attribution, in
your own projects. If you find it helpful, buy me a beer next time you
see me at the local pub.
In here you'll find the Arduino code used to interface with the SX1509 I2C
16 I/O expander. There are functions to take advantage of everything the
SX1509 provides - input/output setting, writing pins high/low, reading
the input value of pins, LED driver utilities (blink, breath, pwm), and
keypad engine utilites.
This file includes detailed descriptions of each of the sx1509Class's
public methods.
For example uses of these functions, see the Arduino example codes in the
./examples/ folder.
*/
#include "Arduino.h"
#ifndef sx1509_library_H
#define sx1509_library_H
#define RECEIVE_TIMEOUT_VALUE 1000 // Timeout for I2C receive
// These are used for setting LED driver to linear or log mode:
#define LINEAR 0
#define LOGARITHMIC 1
// These are used for clock config:
#define INTERNAL_CLOCK 2
#define EXTERNAL_CLOCK 1
class sx1509Class
{
private: // These private functions are not available to Arduino sketches.
// If you need to read or write directly to registers, consider
// putting the writeByte, readByte functions in the public section
byte deviceAddress; // I2C Address of SX1509
// Pin definitions:
byte pinInterrupt;
byte pinOscillator;
byte pinReset;
// Read Functions:
byte readByte(byte registerAddress);
unsigned int readWord(byte registerAddress);
void readBytes(byte firstRegisterAddress, byte * destination, byte length);
// Write functions:
void writeByte(byte registerAddress, byte writeValue);
void writeWord(byte registerAddress, unsigned int writeValue);
void writeBytes(byte firstRegisterAddress, byte * writeArray, byte length);
public:
// -----------------------------------------------------------------------------
// Constructor - sx1509Class: This function sets up the pins connected to the
// SX1509, and sets up the private deviceAddress variable.
//
// Inputs:
// - address: should be the 7-bit address of the SX1509. This should be
// one of four values - 0x3E, 0x3F, 0x70, 0x71 - all depending on what the
// ADDR0 and ADDR1 pins ar se to. This variable is required.
// - resetPin: This is the Arduino pin tied to the SX1509 RST pin. This
// pin is optional. If not declared, the library will attempt to
// software reset the SX1509.
// - interruptPin: This is the Arduino pin tied to the SX1509 active-low
// interrupt output. Only necessary if you're planning on using
// the interrupt capabilities.
// - oscillatorPin: This is the Arduino pin tied to the SX1509's OSCIO
// pin. This pin can be an output or an input. This parameter is optional.
// -----------------------------------------------------------------------------
sx1509Class(byte address, byte resetPin = 255,
byte interruptPin = 255, byte oscillatorPin = 255);
// -----------------------------------------------------------------------------
// init(void): This function initializes the SX1509. It begins the Wire
// library, resets the IC, and tries to read some registers to prove it's
// connected.
//
// Output: Returns a 1 if communication is successful, 0 on error.
// -----------------------------------------------------------------------------
byte init(void);
// -----------------------------------------------------------------------------
// reset(bool hardware): This function resets the SX1509 - either a hardware
// reset or software. A hardware reset (hardware parameter = 1) pulls the
// reset line low, pausing, then pulling the reset line high. A software
// reset writes a 0x12 then 0x34 to the REG_RESET as outlined in the
// datasheet.
//
// Input:
// - hardware: 0 executes a software reset, 1 executes a hardware reset
// -----------------------------------------------------------------------------
void reset(bool hardware);
// -----------------------------------------------------------------------------
// pinDir(byte pin, byte inOut): This function sets one of the SX1509's 16
// outputs to either an INPUT or OUTPUT.
//
// Inputs:
// - pin: should be a value between 0 and 15
// - inOut: The Arduino INPUT and OUTPUT constants should be used for the
// inOut parameter. They do what they say!
// -----------------------------------------------------------------------------
void pinDir(byte pin, byte inOut);
// -----------------------------------------------------------------------------
// writePin(byte pin, byte highLow): This function writes a pin to either high
// or low if it's configured as an OUTPUT. If the pin is configured as an
// INPUT, this method will activate either the PULL-UP or PULL-DOWN
// resistor (HIGH or LOW respectively).
//
// Inputs:
// - pin: The SX1509 pin number. Should be a value between 0 and 15.
// - highLow: should be Arduino's defined HIGH or LOW constants.
// -----------------------------------------------------------------------------
void writePin(byte pin, byte highLow);
void rawWritePin(byte pin, byte highLow);
// -----------------------------------------------------------------------------
// readPin(byte pin): This function reads the HIGH/LOW status of a pin.
// The pin should be configured as an INPUT, using the pinDir function.
//
// Inputs:
// - pin: The SX1509 pin to be read. should be a value between 0 and 15.
// Outputs:
// This function returns a 1 if HIGH, 0 if LOW
// -----------------------------------------------------------------------------
byte readPin(byte pin);
byte rawReadPin(byte pin);
// -----------------------------------------------------------------------------
// ledDriverInit(byte pin, byte freq, bool log): This function initializes LED
// driving on a pin. It must be called if you want to use the pwm or blink
// functions on that pin.
//
// Inputs:
// - pin: The SX1509 pin connected to an LED. Should be 0-15.
// - freq: decides ClkX, and should be a value between 1-7
// - ClkX = 2MHz / (2^(freq - 1)
// - freq defaults to 1, which makes ClkX = 2MHz
// - log: selects either linear or logarithmic mode on the LED drivers
// - log defaults to 0, linear mode
// - currently log sets both bank A and B to the same mode
// Note: this function automatically decides to use the internal 2MHz osc.
// -----------------------------------------------------------------------------
void ledDriverInit(byte pin, byte freq = 1, bool log = 0);
// -----------------------------------------------------------------------------
// pwm(byte pin, byte iOn): This function can be used to control the intensity
// of an output pin connected to an LED.
//
// Inputs:
// - pin: The SX1509 pin connecte to an LED.Should be 0-15.
// - iOn: should be a 0-255 value setting the intensity of the LED
// - 0 is completely off, 255 is 100% on.
//
// Note: ledDriverInit should be called on the pin before calling this.
// -----------------------------------------------------------------------------
void pwm(byte pin, byte iOn);
// -----------------------------------------------------------------------------
// blink(byte pin, byte tOn, byte tOff, byte offIntensity, byte tRise, byte
// tFall): blink performs both the blink and breath LED driver functions.
//
// Inputs:
// - pin: the SX1509 pin (0-15) you want to set blinking/breathing.
// - tOn: the amount of time the pin is HIGH
// - This value should be between 1 and 31. 0 is off.
// - tOff: the amount of time the pin is at offIntensity
// - This value should be between 1 and 31. 0 is off.
// - offIntensity: How dim the LED is during the off period.
// - This value should be between 0 and 7. 0 is completely off.
// - onIntensity: How bright the LED will be when completely on.
// - This value can be between 0 (0%) and 255 (100%).
// - tRise: This sets the time the LED takes to fade in.
// - This value should be between 1 and 31. 0 is off.
// - This value is used with tFall to make the LED breath.
// - tFall: This sets the time the LED takes to fade out.
// - This value should be between 1 and 31. 0 is off.
// Notes:
// - The breathable pins are 4, 5, 6, 7, 12, 13, 14, 15 only. If tRise and
// tFall are set on 0-3 or 8-11 those pins will still only blink.
// - ledDriverInit should be called on the pin to be blinked before this.
// -----------------------------------------------------------------------------
void blink(byte pin, byte tOn, byte toff, byte offIntensity = 0,
byte onIntensity = 255, byte tRise = 0, byte tFall = 0);
// -----------------------------------------------------------------------------
// keypad(byte rows, byte columns, byte sleepTime, byte scanTime): This function
// will initialize the keypad function on the SX1509.
//
// Inputs:
// - rows: The number of rows in the button matrix.
// - This value must be between 1 and 7. 0 will turn it off.
// - eg: 1 = 2 rows, 2 = 3 rows, 7 = 8 rows, etc.
// - columns: The number of columns in the button matrix
// - This value should be between 0 and 7.
// - 0 = 1 column, 7 = 8 columns, etc.
// - sleepTime: Sets the auto-sleep time of the keypad engine. 3-bit value:
// 0 : OFF
// 1 : 128ms x 2MHz/fOSC
// 2 : 256ms x 2MHz/fOSC
// 3 : 512ms x 2MHz/fOSC
// 4 : 1sec x 2MHz/fOSC
// 5 : 2sec x 2MHz/fOSC
// 6 : 4sec x 2MHz/fOSC
// 7 : 8sec x 2MHz/fOSC
// - scanTime: Sets the scan time per row. Must be set above debounce
// time. 3-bit value:
// 0 : 1ms x 2MHz/fOSC
// 1 : 2ms x 2MHz/fOSC
// 2 : 4ms x 2MHz/fOSC
// 3 : 8ms x 2MHz/fOSC
// 4 : 16ms x 2MHz/fOSC
// 5 : 32ms x 2MHz/fOSC
// 6 : 64ms x 2MHz/fOSC
// 7 : 128ms x 2MHz/fOSC
// -----------------------------------------------------------------------------
void keypad(byte rows, byte columns, byte sleepTime = 0, byte scanTime = 0);
// -----------------------------------------------------------------------------
// readKeyData(): This function returns a 16-bit value containing the status of
// keypad engine.
//
// Output:
// A 16-bit value is returned. The lower 8 bits represent the up-to 8 rows,
// while the MSB represents the up-to 8 columns. Bit-values of 1 indicate a
// button in that row or column is being pressed. As such, at least two
// bits should be set.
// -----------------------------------------------------------------------------
unsigned int readKeyData();
// -----------------------------------------------------------------------------
// sync(void): this function resets the PWM/Blink/Fade counters, syncing any
// blinking LEDs. Bit 2 of REG_MISC is set, which alters the functionality
// of the nReset pin. The nReset pin is toggled low->high, which should
// reset all LED counters. Bit 2 of REG_MISC is again cleared, returning
// nReset pin to POR functionality
// -----------------------------------------------------------------------------
void sync(void);
// -----------------------------------------------------------------------------
// debounceConfig(byte configValue): This method configures the debounce time of
// every input.
//
// Input:
// - configValue: A 3-bit value configuring the debounce time.
// 000: 0.5ms * 2MHz/fOSC
// 001: 1ms * 2MHz/fOSC
// 010: 2ms * 2MHz/fOSC
// 011: 4ms * 2MHz/fOSC
// 100: 8ms * 2MHz/fOSC
// 101: 16ms * 2MHz/fOSC
// 110: 32ms * 2MHz/fOSC
// 111: 64ms * 2MHz/fOSC
//
// Note: fOSC is set with the configClock function. It defaults to 2MHz.
// -----------------------------------------------------------------------------
void debounceConfig(byte configVaule);
// -----------------------------------------------------------------------------
// debounceEnable(byte pin): This method enables debounce on SX1509 input pin.
//
// Input:
// - pin: The SX1509 pin to be debounced. Should be between 0 and 15.
//
// Note: debounceConfig() should be called before this, to configure the clock
// and other debounce parameters.
// -----------------------------------------------------------------------------
void debounceEnable(byte pin);
// -----------------------------------------------------------------------------
// enableInterrupt(byte pin, byte riseFall): This function sets up an interrupt
// on a pin. Interrupts can occur on all SX1509 pins, and can be generated
// on rising, falling, or both.
//
// Inputs:
// -pin: SX1509 input pin that will generate an input. Should be 0-15.
// -riseFall: Configures if you want an interrupt generated on rise fall or
// both. For this param, send the pin-change values previously defined
// by Arduino:
// #define CHANGE 1 <-Both
// #define FALLING 2 <- Falling
// #define RISING 3 <- Rising
//
// Note: This function does not set up a pin as an input, or configure its
// pull-up/down resistors! Do that before (or after).
// -----------------------------------------------------------------------------
void enableInterrupt(byte pin, byte riseFall);
// -----------------------------------------------------------------------------
// interruptSource(void): Returns an unsigned int representing which pin caused
// an interrupt.
//
// Output: 16-bit value, with a single bit set representing the pin(s) that
// generated an interrupt. E.g. a return value of 0x0104 would mean pins 8
// and 3 (bits 8 and 3) have generated an interrupt.
//
// Note: This function also clears all interrupts
// -----------------------------------------------------------------------------
unsigned int interruptSource(void);
// -----------------------------------------------------------------------------
// configClock(byte oscSource, byte oscPinFunction, byte oscFreqOut,
// byte oscDivider): This function configures the oscillator source/speed
// and the clock, which is used to drive LEDs and time debounces.
//
// Inputs:
// - oscSource: Choose either internal 2MHz oscillator or an external signal
// applied to the OSCIO pin.
// - INTERNAL_CLOCK and EXTERNAL_CLOCK are defined in the header file.
// Use those.
// - This value defaults to internal.
// - oscPinFunction: Allows you to set OSCIO as an input or output.
// - You can use Arduino's INPUT, OUTPUT defines for this value
// - This value defaults to input
// - oscFreqOut: If oscio is configured as an output, this will set the output
// frequency
// - This should be a 4-bit value. 0=0%, 0xF=100%, else
// fOSCOut = FOSC / (2^(RegClock[3:0]-1))
// - This value defaults to 0.
// - oscDivider: Sets the clock divider in REG_MISC.
// - ClkX = fOSC / (2^(RegMisc[6:4] -1))
// - This value defaults to 1.
// -----------------------------------------------------------------------------
void configClock(byte oscSource = 2, byte oscPinFunction = 0,
byte oscFreqOut = 0, byte oscDivider = 1);
};
#endif // SX1509_library_H

@ -0,0 +1,152 @@
/*
sx1509_registers.h
Register definitions for SX1509.
by: Jim Lindblom
SparkFun Electronics
date: December 13, 2012
license: Beerware. Feel free to use it, with or without attribution, in
your own projects. If you find it helpful, buy me a beer next time you
see me at the local pub.
*/
#define REG_INPUT_DISABLE_B 0x00 // RegInputDisableB Input buffer disable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_INPUT_DISABLE_A 0x01 // RegInputDisableA Input buffer disable register _ I/O[7_0] (Bank A) 0000 0000
#define REG_LONG_SLEW_B 0x02 // RegLongSlewB Output buffer long slew register _ I/O[15_8] (Bank B) 0000 0000
#define REG_LONG_SLEW_A 0x03 // RegLongSlewA Output buffer long slew register _ I/O[7_0] (Bank A) 0000 0000
#define REG_LOW_DRIVE_B 0x04 // RegLowDriveB Output buffer low drive register _ I/O[15_8] (Bank B) 0000 0000
#define REG_LOW_DRIVE_A 0x05 // RegLowDriveA Output buffer low drive register _ I/O[7_0] (Bank A) 0000 0000
#define REG_PULL_UP_B 0x06 // RegPullUpB Pull_up register _ I/O[15_8] (Bank B) 0000 0000
#define REG_PULL_UP_A 0x07 // RegPullUpA Pull_up register _ I/O[7_0] (Bank A) 0000 0000
#define REG_PULL_DOWN_B 0x08 // RegPullDownB Pull_down register _ I/O[15_8] (Bank B) 0000 0000
#define REG_PULL_DOWN_A 0x09 // RegPullDownA Pull_down register _ I/O[7_0] (Bank A) 0000 0000
#define REG_OPEN_DRAIN_B 0x0A // RegOpenDrainB Open drain register _ I/O[15_8] (Bank B) 0000 0000
#define REG_OPEN_DRAIN_A 0x0B // RegOpenDrainA Open drain register _ I/O[7_0] (Bank A) 0000 0000
#define REG_POLARITY_B 0x0C // RegPolarityB Polarity register _ I/O[15_8] (Bank B) 0000 0000
#define REG_POLARITY_A 0x0D // RegPolarityA Polarity register _ I/O[7_0] (Bank A) 0000 0000
#define REG_DIR_B 0x0E // RegDirB Direction register _ I/O[15_8] (Bank B) 1111 1111
#define REG_DIR_A 0x0F // RegDirA Direction register _ I/O[7_0] (Bank A) 1111 1111
#define REG_DATA_B 0x10 // RegDataB Data register _ I/O[15_8] (Bank B) 1111 1111*
#define REG_DATA_A 0x11 // RegDataA Data register _ I/O[7_0] (Bank A) 1111 1111*
#define REG_INTERRUPT_MASK_B 0x12 // RegInterruptMaskB Interrupt mask register _ I/O[15_8] (Bank B) 1111 1111
#define REG_INTERRUPT_MASK_A 0x13 // RegInterruptMaskA Interrupt mask register _ I/O[7_0] (Bank A) 1111 1111
#define REG_SENSE_HIGH_B 0x14 // RegSenseHighB Sense register for I/O[15:12] 0000 0000
#define REG_SENSE_LOW_B 0x15 // RegSenseLowB Sense register for I/O[11:8] 0000 0000
#define REG_SENSE_HIGH_A 0x16 // RegSenseHighA Sense register for I/O[7:4] 0000 0000
#define REG_SENSE_LOW_A 0x17 // RegSenseLowA Sense register for I/O[3:0] 0000 0000
#define REG_INTERRUPT_SOURCE_B 0x18 // RegInterruptSourceB Interrupt source register _ I/O[15_8] (Bank B) 0000 0000
#define REG_INTERRUPT_SOURCE_A 0x19 // RegInterruptSourceA Interrupt source register _ I/O[7_0] (Bank A) 0000 0000
#define REG_EVENT_STATUS_B 0x1A // RegEventStatusB Event status register _ I/O[15_8] (Bank B) 0000 0000
#define REG_EVENT_STATUS_A 0x1B // RegEventStatusA Event status register _ I/O[7_0] (Bank A) 0000 0000
#define REG_LEVEL_SHIFTER_1 0x1C // RegLevelShifter1 Level shifter register 0000 0000
#define REG_LEVEL_SHIFTER_2 0x1D // RegLevelShifter2 Level shifter register 0000 0000
#define REG_CLOCK 0x1E // RegClock Clock management register 0000 0000
#define REG_MISC 0x1F // RegMisc Miscellaneous device settings register 0000 0000
#define REG_LED_DRIVER_ENABLE_B 0x20 // RegLEDDriverEnableB LED driver enable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_LED_DRIVER_ENABLE_A 0x21 // RegLEDDriverEnableA LED driver enable register _ I/O[7_0] (Bank A) 0000 0000
// Debounce and Keypad Engine
#define REG_DEBOUNCE_CONFIG 0x22 // RegDebounceConfig Debounce configuration register 0000 0000
#define REG_DEBOUNCE_ENABLE_B 0x23 // RegDebounceEnableB Debounce enable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_DEBOUNCE_ENABLE_A 0x24 // RegDebounceEnableA Debounce enable register _ I/O[7_0] (Bank A) 0000 0000
#define REG_KEY_CONFIG_1 0x25 // RegKeyConfig1 Key scan configuration register 0000 0000
#define REG_KEY_CONFIG_2 0x26 // RegKeyConfig2 Key scan configuration register 0000 0000
#define REG_KEY_DATA_1 0x27 // RegKeyData1 Key value (column) 1111 1111
#define REG_KEY_DATA_2 0x28 // RegKeyData2 Key value (row) 1111 1111
// LED Driver (PWM, blinking, breathing)
#define REG_T_ON_0 0x29 // RegTOn0 ON time register for I/O[0] 0000 0000
#define REG_I_ON_0 0x2A // RegIOn0 ON intensity register for I/O[0] 1111 1111
#define REG_OFF_0 0x2B // RegOff0 OFF time/intensity register for I/O[0] 0000 0000
#define REG_T_ON_1 0x2C // RegTOn1 ON time register for I/O[1] 0000 0000
#define REG_I_ON_1 0x2D // RegIOn1 ON intensity register for I/O[1] 1111 1111
#define REG_OFF_1 0x2E // RegOff1 OFF time/intensity register for I/O[1] 0000 0000
#define REG_T_ON_2 0x2F // RegTOn2 ON time register for I/O[2] 0000 0000
#define REG_I_ON_2 0x30 // RegIOn2 ON intensity register for I/O[2] 1111 1111
#define REG_OFF_2 0x31 // RegOff2 OFF time/intensity register for I/O[2] 0000 0000
#define REG_T_ON_3 0x32 // RegTOn3 ON time register for I/O[3] 0000 0000
#define REG_I_ON_3 0x33 // RegIOn3 ON intensity register for I/O[3] 1111 1111
#define REG_OFF_3 0x34 // RegOff3 OFF time/intensity register for I/O[3] 0000 0000
#define REG_T_ON_4 0x35 // RegTOn4 ON time register for I/O[4] 0000 0000
#define REG_I_ON_4 0x36 // RegIOn4 ON intensity register for I/O[4] 1111 1111
#define REG_OFF_4 0x37 // RegOff4 OFF time/intensity register for I/O[4] 0000 0000
#define REG_T_RISE_4 0x38 // RegTRise4 Fade in register for I/O[4] 0000 0000
#define REG_T_FALL_4 0x39 // RegTFall4 Fade out register for I/O[4] 0000 0000
#define REG_T_ON_5 0x3A // RegTOn5 ON time register for I/O[5] 0000 0000
#define REG_I_ON_5 0x3B // RegIOn5 ON intensity register for I/O[5] 1111 1111
#define REG_OFF_5 0x3C // RegOff5 OFF time/intensity register for I/O[5] 0000 0000
#define REG_T_RISE_5 0x3D // RegTRise5 Fade in register for I/O[5] 0000 0000
#define REG_T_FALL_5 0x3E // RegTFall5 Fade out register for I/O[5] 0000 0000
#define REG_T_ON_6 0x3F // RegTOn6 ON time register for I/O[6] 0000 0000
#define REG_I_ON_6 0x40 // RegIOn6 ON intensity register for I/O[6] 1111 1111
#define REG_OFF_6 0x41 // RegOff6 OFF time/intensity register for I/O[6] 0000 0000
#define REG_T_RISE_6 0x42 // RegTRise6 Fade in register for I/O[6] 0000 0000
#define REG_T_FALL_6 0x43 // RegTFall6 Fade out register for I/O[6] 0000 0000
#define REG_T_ON_7 0x44 // RegTOn7 ON time register for I/O[7] 0000 0000
#define REG_I_ON_7 0x45 // RegIOn7 ON intensity register for I/O[7] 1111 1111
#define REG_OFF_7 0x46 // RegOff7 OFF time/intensity register for I/O[7] 0000 0000
#define REG_T_RISE_7 0x47 // RegTRise7 Fade in register for I/O[7] 0000 0000
#define REG_T_FALL_7 0x48 // RegTFall7 Fade out register for I/O[7] 0000 0000
#define REG_T_ON_8 0x49 // RegTOn8 ON time register for I/O[8] 0000 0000
#define REG_I_ON_8 0x4A // RegIOn8 ON intensity register for I/O[8] 1111 1111
#define REG_OFF_8 0x4B // RegOff8 OFF time/intensity register for I/O[8] 0000 0000
#define REG_T_ON_9 0x4C // RegTOn9 ON time register for I/O[9] 0000 0000
#define REG_I_ON_9 0x4D // RegIOn9 ON intensity register for I/O[9] 1111 1111
#define REG_OFF_9 0x4E // RegOff9 OFF time/intensity register for I/O[9] 0000 0000
#define REG_T_ON_10 0x4F // RegTOn10 ON time register for I/O[10] 0000 0000
#define REG_I_ON_10 0x50 // RegIOn10 ON intensity register for I/O[10] 1111 1111
#define REG_OFF_10 0x51 // RegOff10 OFF time/intensity register for I/O[10] 0000 0000
#define REG_T_ON_11 0x52 // RegTOn11 ON time register for I/O[11] 0000 0000
#define REG_I_ON_11 0x53 // RegIOn11 ON intensity register for I/O[11] 1111 1111
#define REG_OFF_11 0x54 // RegOff11 OFF time/intensity register for I/O[11] 0000 0000
#define REG_T_ON_12 0x55 // RegTOn12 ON time register for I/O[12] 0000 0000
#define REG_I_ON_12 0x56 // RegIOn12 ON intensity register for I/O[12] 1111 1111
#define REG_OFF_12 0x57 // RegOff12 OFF time/intensity register for I/O[12] 0000 0000
#define REG_T_RISE_12 0x58 // RegTRise12 Fade in register for I/O[12] 0000 0000
#define REG_T_FALL_12 0x59 // RegTFall12 Fade out register for I/O[12] 0000 0000
#define REG_T_ON_13 0x5A // RegTOn13 ON time register for I/O[13] 0000 0000
#define REG_I_ON_13 0x5B // RegIOn13 ON intensity register for I/O[13] 1111 1111
#define REG_OFF_13 0x5C // RegOff13 OFF time/intensity register for I/O[13] 0000 0000
#define REG_T_RISE_13 0x5D // RegTRise13 Fade in register for I/O[13] 0000 0000
#define REG_T_FALL_13 0x5E // RegTFall13 Fade out register for I/O[13] 0000 0000
#define REG_T_ON_14 0x5F // RegTOn14 ON time register for I/O[14] 0000 0000
#define REG_I_ON_14 0x60 // RegIOn14 ON intensity register for I/O[14] 1111 1111
#define REG_OFF_14 0x61 // RegOff14 OFF time/intensity register for I/O[14] 0000 0000
#define REG_T_RISE_14 0x62 // RegTRise14 Fade in register for I/O[14] 0000 0000
#define REG_T_FALL_14 0x63 // RegTFall14 Fade out register for I/O[14] 0000 0000
#define REG_T_ON_15 0x64 // RegTOn15 ON time register for I/O[15] 0000 0000
#define REG_I_ON_15 0x65 // RegIOn15 ON intensity register for I/O[15] 1111 1111
#define REG_OFF_15 0x66 // RegOff15 OFF time/intensity register for I/O[15] 0000 0000
#define REG_T_RISE_15 0x67 // RegTRise15 Fade in register for I/O[15] 0000 0000
#define REG_T_FALL_15 0x68 // RegTFall15 Fade out register for I/O[15] 0000 0000
// Miscellaneous
#define REG_HIGH_INPUT_B 0x69 // RegHighInputB High input enable register _ I/O[15_8] (Bank B) 0000 0000
#define REG_HIGH_INPUT_A 0x6A // RegHighInputA High input enable register _ I/O[7_0] (Bank A) 0000 0000
// Software Reset
#define REG_RESET 0x7D // RegReset Software reset register 0000 0000
#define REG_TEST_1 0x7E // RegTest1 Test register 0000 0000
#define REG_TEST_2 0x7F // RegTest2 Test register 0000 0000
byte REG_I_ON[16] = {REG_I_ON_0, REG_I_ON_1, REG_I_ON_2, REG_I_ON_3,
REG_I_ON_4, REG_I_ON_5, REG_I_ON_6, REG_I_ON_7,
REG_I_ON_8, REG_I_ON_9, REG_I_ON_10, REG_I_ON_11,
REG_I_ON_12, REG_I_ON_13, REG_I_ON_14, REG_I_ON_15};
byte REG_T_ON[16] = {REG_T_ON_0, REG_T_ON_1, REG_T_ON_2, REG_T_ON_3,
REG_T_ON_4, REG_T_ON_5, REG_T_ON_6, REG_T_ON_7,
REG_T_ON_8, REG_T_ON_9, REG_T_ON_10, REG_T_ON_11,
REG_T_ON_12, REG_T_ON_13, REG_T_ON_14, REG_T_ON_15};
byte REG_OFF[16] = {REG_OFF_0, REG_OFF_1, REG_OFF_2, REG_OFF_3,
REG_OFF_4, REG_OFF_5, REG_OFF_6, REG_OFF_7,
REG_OFF_8, REG_OFF_9, REG_OFF_10, REG_OFF_11,
REG_OFF_12, REG_OFF_13, REG_OFF_14, REG_OFF_15};
byte REG_T_RISE[16] = {0xFF, 0xFF, 0xFF, 0xFF,
REG_T_RISE_4, REG_T_RISE_5, REG_T_RISE_6, REG_T_RISE_7,
0xFF, 0xFF, 0xFF, 0xFF,
REG_T_RISE_12, REG_T_RISE_13, REG_T_RISE_14, REG_T_RISE_15};
byte REG_T_FALL[16] = {0xFF, 0xFF, 0xFF, 0xFF,
REG_T_FALL_4, REG_T_FALL_5, REG_T_FALL_6, REG_T_FALL_7,
0xFF, 0xFF, 0xFF, 0xFF,
REG_T_FALL_12, REG_T_FALL_13, REG_T_FALL_14, REG_T_FALL_15};
Loading…
Cancel
Save