mostly working on mcp23018.c; init() and update() might be ready :)

also, moved the twi code to lib/teensy-2-0/twi*
partial-rewrite
Ben Blazak 2012-04-02 01:59:00 -07:00
parent b0b9335651
commit f41502ba3c
12 changed files with 275 additions and 139 deletions

View File

@ -40,6 +40,13 @@
## C Stuff
* [comp.lang.c Frequently Asked Questions]
(http://c-faq.com/index.html)
* [The C Preprocessor]
(http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC1)
(on <http://gcc.gnu.org/>)
* [C Library Reference]
(http://www.cplusplus.com/reference/)
(on <http://cplusplus.com>)

View File

@ -14,27 +14,31 @@
#define KB_LAYERS 1 // anything >= 1, as long as there's memory
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
extern const uint8_t kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
// TODO (before release): put more effort into this
// ------- layer 0: default -------
// --- right hand ---
/* 0 ---------- 1 --------------- 2 -------------- 3 ----------------- 4 --------------------- 5 -------------------------- 6 -------------------------- */
/* 0 */ 0, KEY_6_Caret, KEY_7_Ampersand, KEY_8_Asterisk, KEY_9_LeftParenthesis, KEY_0_RightParenthesis, KEY_Dash_Underscore, /* 0 */
/* 1 */ 0, KEY_y_Y, KEY_u_U, KEY_i_I, KEY_o_O, KEY_p_P, KEY_LeftBracket_LeftBrace, /* 1 */
/* 2 */ 0,/*unused*/ KEY_h_H, KEY_j_J, KEY_k_K, KEY_l_L, KEY_Semicolon_Colon, KEY_SingleQuote_DoubleQuote, /* 2 */
/* 3 */ 0, KEY_n_N, KEY_m_M, KEY_Comma_LessThan, KEY_Period_GreaterThan, KEY_Slash_Question, KEY_RightShift, /* 3 */
/* 4 */ 0,/*unused*/ 0,/*unused*/ KEY_UpArrow, KEY_DownArrow, KEY_Backslash_Pipe, KEY_RightBracket_RightBrace, 0, /* 4 */
/* 5 */ 0,/*unused*/ KEY_RightControl, KEY_RightAlt, KEY_PageUp, KEY_PageDown, KEY_ReturnEnter, KEY_Spacebar, /* 5 */
/* 0 ---------- 1 --------------- 2 -------------- 3 ----------------- 4 --------------------- 5 -------------------------- 6 -------------------------- */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
/* 0 */ 0, KEY_6_Caret, KEY_7_Ampersand, KEY_8_Asterisk, KEY_9_LeftParenthesis, KEY_0_RightParenthesis, KEY_Dash_Underscore, /* 0 */
/* 1 */ 0, KEY_y_Y, KEY_u_U, KEY_i_I, KEY_o_O, KEY_p_P, KEY_LeftBracket_LeftBrace, /* 1 */
/* 2 */ 0,/*unused*/ KEY_h_H, KEY_j_J, KEY_k_K, KEY_l_L, KEY_Semicolon_Colon, KEY_SingleQuote_DoubleQuote, /* 2 */
/* 3 */ 0, KEY_n_N, KEY_m_M, KEY_Comma_LessThan, KEY_Period_GreaterThan, KEY_Slash_Question, KEY_RightShift, /* 3 */
/* 4 */ 0,/*unused*/ 0,/*unused*/ KEY_UpArrow, KEY_DownArrow, KEY_Backslash_Pipe, KEY_RightBracket_RightBrace, 0, /* 4 */
/* 5 */ 0,/*unused*/ KEY_RightControl, KEY_RightAlt, KEY_PageUp, KEY_PageDown, KEY_ReturnEnter, KEY_Spacebar, /* 5 */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
// --- left hand ---
/* 0 ------------------ 1 -------------------- 2 ----------------- 3 ------------ 4 -------------- 5 ------------ 6 ----------- */
/* 6 */ KEY_Equal_Plus, KEY_1_Exclamation, KEY_2_At, KEY_3_Pound, KEY_4_Dollar, KEY_5_Percent, 0, /* 6 */
/* 7 */ KEY_Tab, KEY_q_Q, KEY_w_W, KEY_e_E, KEY_r_R, KEY_t_T, 0, /* 7 */
/* 8 */ KEY_CapsLock, KEY_a_A, KEY_s_S, KEY_d_D, KEY_f_F, KEY_g_G, 0,/*unused*/ /* 8 */
/* 9 */ KEY_LeftShift, KEY_z_Z, KEY_x_X, KEY_c_C, KEY_v_V, KEY_b_B, 0, /* 9 */
/* A */ 0, KEY_GraveAccent_Tilde, KEY_Backslash_Pipe, KEY_LeftArrow, KEY_RightArrow, 0,/*unused*/ 0,/*unused*/ /* A */
/* B */ KEY_DeleteBackspace, KEY_DeleteForward, KEY_End, KEY_Home, KEY_LeftAlt, KEY_LeftControl, 0, 0 /*unused*/ /* B */
/* 0 ------------------ 1 -------------------- 2 ----------------- 3 ------------ 4 -------------- 5 ------------ 6 ----------- */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
/* 6 */ KEY_Equal_Plus, KEY_1_Exclamation, KEY_2_At, KEY_3_Pound, KEY_4_Dollar, KEY_5_Percent, 0, /* 6 */
/* 7 */ KEY_Tab, KEY_q_Q, KEY_w_W, KEY_e_E, KEY_r_R, KEY_t_T, 0, /* 7 */
/* 8 */ KEY_CapsLock, KEY_a_A, KEY_s_S, KEY_d_D, KEY_f_F, KEY_g_G, 0,/*unused*/ /* 8 */
/* 9 */ KEY_LeftShift, KEY_z_Z, KEY_x_X, KEY_c_C, KEY_v_V, KEY_b_B, 0, /* 9 */
/* A */ 0, KEY_GraveAccent_Tilde, KEY_Backslash_Pipe, KEY_LeftArrow, KEY_RightArrow, 0,/*unused*/ 0,/*unused*/ /* A */
/* B */ KEY_DeleteBackspace, KEY_DeleteForward, KEY_End, KEY_Home, KEY_LeftAlt, KEY_LeftControl, 0, 0 /*unused*/ /* B */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
}
#endif

View File

@ -15,7 +15,7 @@
#define KB_ROWS 12 // must match real life
#define KB_COLUMNS 7 // must match real life
extern bool kb_is_pressed[KB_ROWS][KB_COLUMNS] = {};
extern bool kb_is_pressed[KB_ROWS][KB_COLUMNS] = {false};
#endif

View File

@ -6,33 +6,16 @@
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
// TODO: this is not working yet
// see if the device is ready
// - success: set `mcp23018_ready = true` and continue initializing
// - failure: return `error`; we can try again later
// set pin direction
// - unused : input : 1
// - rows : output : 0
// - columns : input : 1
// set pull-up
// - unused : on : 1
// - rows : on : 1
// - columns : on : 1
// set output pins high
// - rows : high : 1
// - other : low : 0 (or ignored)
#include <util/twi.h>
#include "lib/data-types.h"
#define TWI_FREQ 400000
#include "lib/teensy-2-0/twi.h"
#include "matrix.h"
#define MCP23018_h_INCLUDE_PRIVATE
#include "mcp23018.h"
#include "teensy-2-0.h"
#include "lib/data-types.h"
// register addresses (see "mcp23018.md")
@ -45,83 +28,106 @@
#define OLATA 0x14 // output latch register
#define OLATB 0x15
// TWI aliases
#define TWI_ADDR_WRITE ( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE )
#define TWI_ADDR_READ ( (MCP23018_TWI_ADDRESS<<1) | TW_READ )
// ----------------------------------------------------------------------------
// dbg
// ----------------------------------------------------------------------------
#include <avr/io.h>
#include <util/delay.h>
// error check
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
#define blink_led(time1, time2) { \
/* Teensy 2.0 onboard LED on PD6
on high, off low */ \
PORTD |= (1<<6); \
_delay_ms(time1); \
PORTD &= ~(1<<6); \
_delay_ms(time2); \
}
void blink_hex(uint8_t num) {
// initial blink (get ready)
blink_led(700, 200);
// 1st hex number
for (uint8_t i=0; i<(num/0x10); i++) {
blink_led(200, 100);
}
_delay_ms(400);
// 2nd hex number
for (uint8_t i=0; i<(num%0x10); i++) {
blink_led(200, 100);
}
}
// ---------------------------------------------------------------------------- // TWI
// ----------------------------------------------------------------------------
void twi_init(void) {
TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
TWBR = ((F_CPU / 400000) - 16) / 2;
// TWSR |= (1<<TWPS1)|(1<<TWPS0); //dbg
// TWBR = 0xFF; //dbg
}
uint8_t twi_start(void) {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTA);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_START)
return TWSR & 0xF8; // error
}
void twi_stop(void) {
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
while (TWCR & (1<<TWSTO));
}
uint8_t twi_send(uint8_t data) {
TWDR = data;
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));
if ((TWSR & 0xF8) != TW_MT_SLA_ACK)
return TWSR & 0xF8; // error
}
// ----------------------------------------------------------------------------
// init function
// ----------------------------------------------------------------------------
/*
* returns:
* - success: 0
* - failure: twi status code
*/
uint8_t mcp23018_init(void) {
uint8_t ret;
twi_init();
// quick check to see if the device is responding; if it is, we'll
// assume things are going to work
twi_start();
ret = twi_send( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE );
ret = twi_send(IODIRA);
ret = twi_send(0);
ret = twi_send(0);
ret = twi_send(0);
ret = twi_send(TWI_ADDR_WRITE);
if (ret) {
twi_stop();
return ret;
}
blink_hex(ret);
// set pin direction
// - unused : input : 1
// - rows : output : 0
// - columns : input : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(IODIRA);
twi_send(0b11000000); // IODIRA
twi_send(0b11111111); // IODIRB
// set pull-up
// - unused : on : 1
// - rows : on : 1
// - columns : on : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPPUA);
twi_send(0b11111111); // GPPUA
twi_send(0b11111111); // GPPUB
// set output pins high
// - unused : low : 0
// - rows : high : 1
// - columns : low : 0
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send(0b00111111); //GPIOA
twi_send(0b00000000); //GPIOB
twi_stop();
}
/* args:
* - `matrix[][]`: `KB_ROWS` and `KB_COLUMNS` must be what we're expecting (see
* 'error check' in the `#include` section)
*
* returns:
* - success: 0
* - failure: twi status code
*/
uint8_t mcp23018_update_matrix(uint8_t matrix[KB_ROWS][KB_COLUMNS]) {
uint8_t ret, data;
// quick check to see if the device is responding; if it is, we'll
// assume things are going to work
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) {
twi_stop();
return ret;
}
for (uint8_t row=0x6; row<=0xB; row++) {
// set row low : 0
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send( 0b00111111 & ~(1<<(row-6)) ); // GPIOA
// get column data
twi_start();
twi_send(TWI_ADDR_READ);
twi_read(&data); // GPIOB TODO: confirm
// update matrix
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = !( data & (1<<col) );
}
twi_stop();
}

View File

@ -10,15 +10,13 @@
#ifndef MCP23018_h
#define MCP23018_h
#include "lib/data-types.h"
#ifdef MCP23018_h_INCLUDE_PRIVATE
#define MCP23018_TWI_ADDRESS 0b0100000
extern bool mcp23018_ready;
uint8_t mcp23018_init(void);
uint8_t mcp23018_update_matrix(
uint8_t matrix[KB_ROWS][KB_COLUMNS] );
#endif

View File

@ -43,9 +43,11 @@
* notes:
* ADDR (pin15): Set slave address to `0b0100000` by connecting to Vss(GND).
(The user-defined bits are the three least significant).
* RESET (pin16) must be externally biased. At least, this is true on the
MCP23017, so it seems like it should be true with the MCP23018. Since
we're not going to trigger it ourselves, we'll tie it high.
* RESET (pin16) must be externally biased.Since we're not going to trigger it
ourselves, we'll tie it high.
* This is not noted in the I2C Pinout Description section of the MCP23018
datasheet, but it's true (empirically), and it is noted in the SPI Pinout
Description section, and in the MCP23017 datasheet.
* <http://davidn.org/wp/?p=89>
* <http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293498979>
@ -76,6 +78,9 @@
* All addresses given for IOCON.BANK = 0, since that's the default value of
the bit, and that's what we'll be using.
* Outputs are open drain, so we want pull-up resistors set for everything.
* We want the row pins set as output high initially, and the column pins set
as input. We'll cycle through driving the row pins low and checking the
column pins in the update function.
* abbreviations:
* IODIR = I/O Direction Register

View File

@ -26,6 +26,10 @@
#define CPU_62kHz 0x08
/* returns:
* - success: 0
* + will never return failure
*/
uint8_t teensy_init(void) {
CPU_PRESCALE(CPU_16MHz); // speed should match F_CPU in makefile

View File

@ -1,6 +1,5 @@
# Documentation : Teensy 2.0
## Pinouts and Pin assignments
* `+` indicates pin
@ -68,7 +67,7 @@
LED, so there's no reason to set internal pull-up enabled on it. If we
do, it will source current to the LED, which is fine, but unnecessary.
* We want the row pins 'drive high' initially, and the column pins set as
input with internal pull-up. We'll cycle through driving the row pins low,
input with internal pull-up. We'll cycle through driving the row pins low
and checking the column pins in the update function.
### PWM on ports OC1(A|B|C) (see datasheet section 14.10)
@ -103,30 +102,6 @@
* OCR = Output Compare Register
* TCCR = Timer/Counter Control Register
## I&sup2;C Status Codes (for Master modes)
### Master Transmitter
* `0x08` A START condition has been transmitted
* `0x10` A repeated START condition has been transmitted
* `0x18` SLA+W has been transmitted; ACK has been received
* `0x20` SLA+W has been transmitted; NOT ACK has been received
* `0x28` Data byte has been transmitted; ACK has been received
* `0x30` Data byte has been transmitted; NOT ACK has been received
* `0x38` Arbitration lost in SLA+W or data bytes
### Master Receiver
* `0x08` A START condition has been transmitted
* `0x10` A repeated START condition has been transmitted
* `0x38` Arbitration lost in SLA+R or NOT ACK bit
* `0x40` SLA+R has been transmitted; ACK has been received
* `0x48` SLA+R has been transmitted; NOT ACK has been received
* `0x50` Data byte has been received; ACK has been returned
* `0x58` Data byte has been received; NOT ACK has been returned
-------------------------------------------------------------------------------
Copyright &copy; 2012 Ben Blazak <benblazak.dev@gmail.com>

View File

@ -1,3 +1,6 @@
<!--
TODO: move the links into references if they're going to disappear from here
-->
# src/lib-other
Files taken from other projects

79
src/lib/teensy-2-0/twi.c Normal file
View File

@ -0,0 +1,79 @@
/* ----------------------------------------------------------------------------
* Very simple Teensy 2.0 TWI library : code
*
* - This is mostly straight from the datasheet, section 20.6.6, figure 20-11
* (the code example in C), and section 20.8.1, figure 20-12
* - Also see the documentation for `<util/twi.h>` at <http://www.nongnu.org/avr-libc/user-manual/group__util__twi.html#ga8d3aca0acc182f459a51797321728168>
*
* Some other (more complete) TWI libraries for the Teensy 2.0 (and other Amtel
* processors):
* - [i2cmaster] (http://homepage.hispeed.ch/peterfleury/i2cmaster.zip)
* - written by [peter-fleury] (http://homepage.hispeed.ch/peterfleury/)
* - [the arduino twi library] (https://github.com/arduino/Arduino/tree/master/libraries/Wire/utility)
* - look for an older version if you need one that doesn't depend on all the
* other Arduino stuff
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <util/twi.h>
#include "twi.h"
void twi_init(void) {
// set the prescaler value to 0
TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
// set the bit rate
// - TWBR should be 10 or higher (datasheet section 20.5.2)
// - TWI_FREQ should be 400000 (400kHz) max (datasheet section 20.1)
TWBR = ((F_CPU / TWI_FREQ) - 16) / 2;
}
uint8_t twi_start(void) {
// send start
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTA);
// wait for transmission to complete
while (!(TWCR & (1<<TWINT)));
// if it didn't work, return the status code (else return 0)
if (! (TW_STATUS == TW_START) ||
(TW_STATUS == TW_REP_START) )
return TW_STATUS; // error
}
void twi_stop(void) {
// send stop
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
// wait for transmission to complete
while (TWCR & (1<<TWSTO));
}
uint8_t twi_send(uint8_t data) {
// load data into the data register
TWDR = data;
// send data
TWCR = (1<<TWINT)|(1<<TWEN);
// wait for transmission to complete
while (!(TWCR & (1<<TWINT)));
// if it didn't work, return the status code (else return 0)
if (! (TW_STATUS == TW_MT_SLA_ACK) ||
(TW_STATUS == TW_MT_DATA_ACK)||
(TW_STATUS == TW_MR_SLA_ACK) )
return TW_STATUS; // error
}
uint8_t twi_read(uint8_t * data) {
// read 1 byte to TWDR, send ACK
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
// wait for transmission to complete
while (!(TWCR & (1<<TWINT)));
// set data variable
data = TWDR;
// if it didn't work, return the status code (else return 0)
if (TW_STATUS != TW_MR_DATA_ACK)
return TW_STATUS; // error
}

25
src/lib/teensy-2-0/twi.h Normal file
View File

@ -0,0 +1,25 @@
/* ----------------------------------------------------------------------------
* Very simple Teensy 2.0 TWI library : exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef TWI_h
#define TWI_h
#ifndef TWI_FREQ
#define TWI_FREQ 100000
#endif
void twi_init(void);
uint8_t twi_start(void);
void twi_stop(void);
uint8_t twi_send(uint8_t data);
uint8_t twi_read(uint8_t * data);
#endif

30
src/lib/teensy-2-0/twi.md Normal file
View File

@ -0,0 +1,30 @@
# Documentation : Teensy 2.0 I&sup2;C
## I&sup2;C Status Codes (for Master modes)
### Master Transmitter (datasheet section 20.8.1, table 20-3)
* `0x08` A START condition has been transmitted
* `0x10` A repeated START condition has been transmitted
* `0x18` SLA+W has been transmitted; ACK has been received
* `0x20` SLA+W has been transmitted; NOT ACK has been received
* `0x28` Data byte has been transmitted; ACK has been received
* `0x30` Data byte has been transmitted; NOT ACK has been received
* `0x38` Arbitration lost in SLA+W or data bytes
### Master Receiver (datasheet section 20.8.2, table 20-4)
* `0x08` A START condition has been transmitted
* `0x10` A repeated START condition has been transmitted
* `0x38` Arbitration lost in SLA+R or NOT ACK bit
* `0x40` SLA+R has been transmitted; ACK has been received
* `0x48` SLA+R has been transmitted; NOT ACK has been received
* `0x50` Data byte has been received; ACK has been returned
* `0x58` Data byte has been received; NOT ACK has been returned
-------------------------------------------------------------------------------
Copyright &copy; 2012 Ben Blazak <benblazak.dev@gmail.com>
Released under The MIT License (MIT) (see "license.md")
Project located at <https://github.com/benblazak/ergodox-firmware>