lots and lots; now writing/debugging keyboard logic

also, mcp23018_init() needs fixing: `twi_stop()` needs to be at the end
of transmission blocks.  i wouldn't think that would be necessary, but
it seems to be the only thing that'll make it work, and it also seems
consistent with the protocol diagram in the datasheet (lol, imagine
that), so i think that's what i'll have to do.  not as though it matters
much i guess, since it's a single master / single slave system anyway, i
was just hoping not to release the bus till i was finished..
partial-rewrite
Ben Blazak 2012-04-10 01:44:27 -07:00
parent 92c3d541f1
commit 57e82aebcf
27 changed files with 662 additions and 120 deletions

View File

@ -70,12 +70,28 @@
(http://www.ibiblio.org/pub/languages/fortran/append-c.html)
(on <http://www.ibiblio.org/>)
* [how to use array of function pointers?]
(http://stackoverflow.com/questions/252748/how-to-use-array-of-function-pointers)
(on <http://stackoverflow.com/>)
* [The Function Pointer Tutorials]
(http://www.newty.de/fpt/index.html)
* [C preprocessor and concatenation]
(http://stackoverflow.com/questions/1489932/c-preprocessor-and-concatenation)
(on <http://stackoverflow.com/>)
* [The New C: Inline Functions]
(http://drdobbs.com/184401540)
by Randy Meyers
(on <http://drdobbs.com/>)
### For the AVR
* [AVR Newbie guide]
(http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=70673)
by stu_san (on <http://www.avrfreaks.net/>)
* [AVR Libc Library Reference]
(http://www.nongnu.org/avr-libc/user-manual/modules.html)
@ -83,8 +99,9 @@
(http://svn.savannah.nongnu.org/viewvc/trunk/avr-libc/include/avr/iom32u4.h?revision=2288&root=avr-libc&view=markup)
: list of registers and associated bit numbers for ATmega32U4
* [A Brief Tutorial on Programming the AVR without Arduino] by Chris Kuethe
* [A Brief Tutorial on Programming the AVR without Arduino]
(https://www.mainframe.cx/~ckuethe/avr-c-tutorial/)
by Chris Kuethe
## Protocol Stuff
@ -137,13 +154,22 @@
(http://geekhack.org/showwiki.php?title=Island:26742)
article (on <http://geekhack.org/>)
* github: [tmk / tmk_keyboard]
(https://github.com/tmk/tmk_keyboard)
* github: [Pyrolistical / tmk_keyboard]
(https://github.com/Pyrolistical/tmk_keyboard/tree/master/fourway)
* forked by [Pyrolistical / tmk_keyboard]
(https://github.com/Pyrolistical/tmk_keyboard/tree/master/fourway)
* mentioned in the [KeyPoard]
(http://geekhack.org/showwiki.php?title=Island:26845)
article (on <http://geekhack.org/>)
* mentioned in the [KeyPoard]
(http://geekhack.org/showwiki.php?title=Island:26845)
article on <http://geekhack.org/>
* forked by [riffautae / tmk_keyboard]
(https://github.com/riffautae/tmk_keyboard)
* mentioned on the [Teensy Keyboard Firmware Discussion]
(http://geekhack.org/showthread.php?26730-Teensy-Keyboard-Firmware-Discussion/page2)
thread on <http://geekhack.org/>
* github: [humblehacker / keyboard]
(https://github.com/humblehacker/keyboard)

View File

@ -1,18 +0,0 @@
/* ----------------------------------------------------------------------------
* main()
* ----------------------------------------------------------------------------
* 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 "lib/pjrc/print.h"
// #include "keyboard.h"
// TODO
int main(void) {
}

90
src/key-functions.c Normal file
View File

@ -0,0 +1,90 @@
/* ----------------------------------------------------------------------------
* key functions: code
* ----------------------------------------------------------------------------
* 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 "lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "lib/data-types.h"
#include "lib/usb/keyboard-usage-page.h"
#include "keyboard.h"
// ----------------------------------------------------------------------------
#if 0 // not being used right now
static uint8_t _inc_current_layer(uint8_t * current_layer) {
if (*current_layer < (KB_LAYERS-1))
(*current_layer)++;
else
return 1; // error: can't increase
return 0; // success
}
static uint8_t _dec_current_layer(uint8_t * current_layer) {
if (*current_layer > 0)
(*current_layer)--;
else
return 1; // error: can't decrease
return 0; // success
}
#endif
// ----------------------------------------------------------------------------
void kbfun_press(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col ) {
for (uint8_t i=0; i<6; i++)
if (keyboard_keys[i] == 0)
keyboard_keys[i] = *keycode;
}
void kbfun_release(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col ) {
for (uint8_t i=0; i<6; i++)
if (keyboard_keys[i] == *keycode)
keyboard_keys[i] = 0;
}
void kbfun_mod_press(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col ) {
switch (*keycode) {
case KEY_LeftControl: keyboard_modifier_keys |= (1<<0); break;
case KEY_LeftShift: keyboard_modifier_keys |= (1<<1); break;
case KEY_LeftAlt: keyboard_modifier_keys |= (1<<2); break;
case KEY_LeftGUI: keyboard_modifier_keys |= (1<<3); break;
case KEY_RightControl: keyboard_modifier_keys |= (1<<4); break;
case KEY_RightShift: keyboard_modifier_keys |= (1<<5); break;
case KEY_RightAlt: keyboard_modifier_keys |= (1<<6); break;
case KEY_RightGUI: keyboard_modifier_keys |= (1<<7); break;
}
}
void kbfun_mod_release(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col ) {
switch (*keycode) {
case KEY_LeftControl: keyboard_modifier_keys &= ~(1<<0); break;
case KEY_LeftShift: keyboard_modifier_keys &= ~(1<<1); break;
case KEY_LeftAlt: keyboard_modifier_keys &= ~(1<<2); break;
case KEY_LeftGUI: keyboard_modifier_keys &= ~(1<<3); break;
case KEY_RightControl:keyboard_modifier_keys &= ~(1<<4); break;
case KEY_RightShift: keyboard_modifier_keys &= ~(1<<5); break;
case KEY_RightAlt: keyboard_modifier_keys &= ~(1<<6); break;
case KEY_RightGUI: keyboard_modifier_keys &= ~(1<<7); break;
}
}

31
src/key-functions.h Normal file
View File

@ -0,0 +1,31 @@
/* ----------------------------------------------------------------------------
* key functions: 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 KEY_FUNCTIONS_h
#define KEY_FUNCTIONS_h
#include "lib/data-types.h"
typedef void (*kbfun_funptr_t)(uint8_t*, uint8_t*, uint8_t*, uint8_t*);
void kbfun_press(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col );
void kbfun_release(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col );
void kbfun_mod_press(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col );
void kbfun_mod_release(
uint8_t * keycode, uint8_t * current_layer,
uint8_t * row, uint8_t * col );
#endif

View File

@ -0,0 +1,12 @@
/* ----------------------------------------------------------------------------
* keyboard specific exports
* use this file to include the keyboard you're compiling for
* ----------------------------------------------------------------------------
* 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 "keyboard/ergodox.h" // only supported keyboard right now

View File

@ -0,0 +1,43 @@
/* ----------------------------------------------------------------------------
* ergoDOX specific code: tying it all together
* ----------------------------------------------------------------------------
* 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 "lib/data-types.h"
#define KEYBOARD_INCLUDE_PRIVATE
#include "ergodox/matrix.h"
#include "ergodox/mcp23018.h"
#include "ergodox/teensy-2-0.h"
/* returns
* - success: 0
* - error: number of the function that failed
*/
uint8_t kb_init(void) {
if (teensy_init()) // must be first
return 1;
if (mcp23018_init()) // must be second
return 2;
return 0; // success
}
/* returns
* - success: 0
* - error: number of the function that failed
*/
uint8_t kb_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
if (teensy_update_matrix(matrix)) // must be first
return 1;
if (mcp23018_update_matrix(matrix)) // must be second
return 2;
return 0; // success
}

View File

@ -0,0 +1,24 @@
/* ----------------------------------------------------------------------------
* ergoDOX specific 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 ERGODOX_h
#define ERGODOX_h
#include "lib/data-types.h"
#include "ergodox/layout.h" // number of layers, layout
#include "ergodox/matrix.h" // kb dimensions, matrix status
#include "ergodox/mcp23018.h" // (nothing right now)
#include "ergodox/teensy-2-0.h" // LED controls
uint8_t kb_init(void);
uint8_t kb_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]);
#endif

View File

@ -10,15 +10,20 @@
#include "lib/data-types.h"
#include "lib/usb/keyboard-usage-page.h"
#include "key-functions.h"
#include "matrix.h"
#include "layout.h"
// TODO (before release): put more effort into this
#if KB_ROWS != 12 || KB_COLUMNS != 7
// error check; everything below assumes these dimensions
#if KB_LAYERS != 1 || KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
uint8_t const kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
// TODO (before release): put more effort into this
uint8_t kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
{ // layer 0: default
// right hand
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
@ -39,6 +44,51 @@ uint8_t const kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
/* B */ { KEY_DeleteBackspace, KEY_DeleteForward, KEY_End, KEY_Home, KEY_LeftAlt, KEY_LeftControl, 0/*unused*/ } /* B */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
}
};
kbfun_funptr_t kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
{ // layer 0: default
// right hand
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
/* 0 */ { NULL, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press }, /* 0 */
/* 1 */ { NULL, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press }, /* 1 */
/* 2 */ { NULL,/*unused*/ &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press }, /* 2 */
/* 3 */ { NULL, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_mod_press }, /* 3 */
/* 4 */ { NULL,/*unused*/ NULL,/*unused*/ &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, NULL }, /* 4 */
/* 5 */ { NULL,/*unused*/ &kbfun_mod_press, &kbfun_mod_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press }, /* 5 */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
// left hand
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
/* 6 */ { &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, NULL }, /* 6 */
/* 7 */ { &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, NULL }, /* 7 */
/* 8 */ { &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, NULL/*unused*/ }, /* 8 */
/* 9 */ { &kbfun_mod_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, NULL }, /* 9 */
/* A */ { NULL, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, NULL,/*unused*/ NULL/*unused*/ }, /* A */
/* B */ { &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_press, &kbfun_mod_press, &kbfun_mod_press, NULL/*unused*/ } /* B */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
}
};
kbfun_funptr_t kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
{ // layer 0: default
// right hand
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
/* 0 */ { NULL, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release }, /* 0 */
/* 1 */ { NULL, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release }, /* 1 */
/* 2 */ { NULL,/*unused*/ &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release }, /* 2 */
/* 3 */ { NULL, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_mod_release }, /* 3 */
/* 4 */ { NULL,/*unused*/ NULL,/*unused*/ &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, NULL }, /* 4 */
/* 5 */ { NULL,/*unused*/ &kbfun_mod_release, &kbfun_mod_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release }, /* 5 */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
// left hand
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
/* 6 */ { &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, NULL }, /* 6 */
/* 7 */ { &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, NULL }, /* 7 */
/* 8 */ { &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, NULL/*unused*/ }, /* 8 */
/* 9 */ { &kbfun_mod_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, NULL }, /* 9 */
/* A */ { NULL, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, NULL,/*unused*/ NULL/*unused*/ }, /* A */
/* B */ { &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_release, &kbfun_mod_release, &kbfun_mod_release, NULL/*unused*/ } /* B */
/* 0 -------------------------- 1 -------------------------- 2 -------------------------- 3 -------------------------- 4 -------------------------- 5 -------------------------- 6 -------------------------- */
}
};

View File

@ -11,11 +11,18 @@
#include "lib/data-types.h"
#include "key-functions.h"
#include "matrix.h"
#define KB_LAYERS 1 // anything >= 1, as long as there's memory
#define KB_LAYERS 1 // must match what's defined in "layout.c"
extern uint8_t const kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS];
extern uint8_t
kb_layout [KB_LAYERS][KB_ROWS][KB_COLUMNS];
extern kbfun_funptr_t
kb_layout_press [KB_LAYERS][KB_ROWS][KB_COLUMNS];
extern kbfun_funptr_t
kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#endif

View File

@ -12,5 +12,9 @@
#include "matrix.h"
bool kb_is_pressed[KB_ROWS][KB_COLUMNS] = {{false}};
static bool _kb_is_pressed[KB_ROWS][KB_COLUMNS];
static bool _kb_was_pressed[KB_ROWS][KB_COLUMNS];
bool (*kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_is_pressed;
bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_was_pressed;

View File

@ -15,7 +15,9 @@
#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];
extern bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS];
#endif

View File

@ -6,15 +6,19 @@
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
// TODO: still working on all this
// - need to separate the 'check if everything's all right' function, i think
// - do more error checking in update_matrix() ?
// - does update_matrix() really need a helper function? can it be conditional?
// - [and lots of stuff, just need to clean it up] :)
#include <util/twi.h>
#include "lib/data-types.h"
#define TWI_FREQ 400000
#include "lib/teensy-2-0/twi.h"
#include "lib/teensy-2-0/twi.h" // `TWI_FREQ` defined in "teensy-2-0.c"
#define KEYBOARD_INCLUDE_PRIVATE
#include "matrix.h"
#define MCP23018_h_INCLUDE_PRIVATE
#include "mcp23018.h"
@ -23,7 +27,7 @@
#define IODIRB 0x01
#define GPPUA 0x0C // GPIO pull-up resistor register
#define GPPUB 0x0D
#define GPIOA 0x12 // general purpose i/o port register
#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
#define GPIOB 0x13
#define OLATA 0x14 // output latch register
#define OLATB 0x15
@ -33,24 +37,36 @@
#define TWI_ADDR_READ ( (MCP23018_TWI_ADDRESS<<1) | TW_READ )
/*
* returns:
// ----------------------------------------------------------------------------
/* returns:
* - success: 0
* - failure: twi status code
*
* notes:
* - this checks whether the device is initialized by reading from it. not the
* most efficient method, but easy and fairly reliable.
*/
uint8_t mcp23018_init(void) {
uint8_t ret;
static uint8_t _init(bool release_twi_bus) {
static bool initialized;
uint8_t ret, data;
twi_init();
// check for errors and previous initialization
// 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;
}
if (ret) goto out; // address write failed (no ACK)
twi_send(OLATA);
twi_start();
twi_send(TWI_ADDR_READ);
ret = twi_read(&data);
if (ret) goto out; // read failed
if (data == 0xFF) goto out; // already initialized (OLATA == 0xFF)
// initialize things, if we need to and we can
// set pin direction
// - unused : input : 1
@ -78,13 +94,28 @@ uint8_t mcp23018_init(void) {
// - columns : high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send(0b11111111); //GPIOA
twi_send(0b11111111); //GPIOB
twi_stop();
twi_send(OLATA);
twi_send(0b11111111); //OLATA
twi_send(0b11111111); //OLATB
return 0; // success
out:
if (release_twi_bus)
twi_stop();
if (ret) initialized = false;
else initialized = true;
return ret;
}
// ----------------------------------------------------------------------------
/* returns:
* - success: 0
* - failure: twi status code
*/
uint8_t mcp23018_init(void) {
return _init(true);
}
/* returns:
@ -94,44 +125,53 @@ uint8_t mcp23018_init(void) {
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
uint8_t mcp23018_update_matrix(uint8_t matrix[KB_ROWS][KB_COLUMNS]) {
uint8_t mcp23018_update_matrix(bool 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);
// initialize things if necessary
ret = _init(false);
// if there was an error
if (ret) {
// clear the matrix
for (uint8_t row=0x6; row<=0xB; row++)
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = 0;
// release the twi bus and return
twi_stop();
return ret;
}
// update our part of the matrix
for (uint8_t row=0x6; row<=0xB; row++) {
// set row low : 0
// set other rows high : 1
// set active row low : 0
// set other rows high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send( 0b11111111 & ~(1<<(row-6)) ); // GPIOA
twi_send(OLATA);
twi_send( 0b11111111 & ~(1<<(row-6)) ); // OLATA
// get column data
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOB);
twi_send(TWI_ADDR_READ);
twi_read(&data); // GPIOB TODO: confirm
twi_read(&data); // GPIOB
// update matrix
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = !( data & (1<<col) );
}
// set all rows high : 1
// set all rows high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send(0b11111111);
// release the twi bus and return
twi_stop();
return 0; // success
}

View File

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

View File

@ -1,6 +1,6 @@
# Documentation : MCP23018
## Pinouts and Pin assignments
## Pinout and Pin assignments
* `+` indicates pin
* `o` indicates unused pin
@ -66,7 +66,7 @@
OLATB 0x15 / write: modifies the output latches that control the
pins configured as output
* IOCON (see datasheet section 1.6, table 1-5, register 1-8)
* IOCON register (see datasheet section 1.6, table 1-5, register 1-8)
* BANK: bit 7; read/write; default = 0
* 1: The registers associated with each port are separated into different
banks

View File

@ -10,9 +10,11 @@
#include <avr/io.h>
#include "lib/data-types.h"
#define TWI_FREQ 400000
#include "lib/teensy-2-0/twi.h"
#define KEYBOARD_INCLUDE_PRIVATE
#include "matrix.h"
#define TEENSY_2_0_h_INCLUDE_PRIVATE
#include "teensy-2-0.h"
@ -77,9 +79,8 @@
#define COLUMN_6 B, 0
/* returns:
/* returns
* - success: 0
* + will never return failure
*/
uint8_t teensy_init(void) {
CPU_PRESCALE(CPU_16MHz); // speed should match F_CPU in makefile
@ -93,9 +94,12 @@ uint8_t teensy_init(void) {
TCCR1A = 0b10101001; // set and configure fast PWM
TCCR1B = 0b00001001; // set and configure fast PWM
KB_LED1_SET_PERCENT(0.5); KB_LED1_OFF;
KB_LED2_SET_PERCENT(0.5); KB_LED2_OFF;
KB_LED3_SET_PERCENT(0.5); KB_LED3_OFF;
// I2C (TWI)
// on pins D(1,0); leave them alone here so the TWI library can do as
// it wishes
twi_init(); // on pins D(1,0)
// unused pins
// --- set as input
@ -150,15 +154,14 @@ uint8_t teensy_init(void) {
return 0; // success
}
/* returns:
/* returns
* - success: 0
* + will never return failure
*/
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
static inline void _update_columns(
uint8_t matrix[KB_ROWS][KB_COLUMNS], uint8_t row ) {
bool matrix[KB_ROWS][KB_COLUMNS], uint8_t row ) {
matrix[row][0] = ! TEENSYPIN_READ(COLUMN_0);
matrix[row][1] = ! TEENSYPIN_READ(COLUMN_1);
matrix[row][2] = ! TEENSYPIN_READ(COLUMN_2);
@ -167,30 +170,30 @@ static inline void _update_columns(
matrix[row][5] = ! TEENSYPIN_READ(COLUMN_5);
matrix[row][6] = ! TEENSYPIN_READ(COLUMN_6);
}
uint8_t teensy_update_matrix(uint8_t matrix[KB_ROWS][KB_COLUMNS]) {
TEENSYPIN_WRITE(DDR, CLEAR, ROW_0); // set row low (as output)
uint8_t teensy_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
TEENSYPIN_WRITE(DDR, SET, ROW_0); // set row low (set as output)
_update_columns(matrix, 0); // read col 0..6 and update matrix
TEENSYPIN_WRITE(DDR, SET, ROW_0); // set row hi-Z (as input)
TEENSYPIN_WRITE(DDR, CLEAR, ROW_0); // set row hi-Z (set as input)
TEENSYPIN_WRITE(DDR, CLEAR, ROW_1);
_update_columns(matrix, 1);
TEENSYPIN_WRITE(DDR, SET, ROW_1);
_update_columns(matrix, 1);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_1);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_2);
_update_columns(matrix, 2);
TEENSYPIN_WRITE(DDR, SET, ROW_2);
_update_columns(matrix, 2);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_2);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_3);
_update_columns(matrix, 3);
TEENSYPIN_WRITE(DDR, SET, ROW_3);
_update_columns(matrix, 3);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_3);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_4);
_update_columns(matrix, 4);
TEENSYPIN_WRITE(DDR, SET, ROW_4);
_update_columns(matrix, 4);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_4);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_5);
_update_columns(matrix, 5);
TEENSYPIN_WRITE(DDR, SET, ROW_5);
_update_columns(matrix, 5);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_5);
return 0; // success
}

View File

@ -14,6 +14,8 @@
#include "lib/data-types.h"
#include "matrix.h"
// LED control
#define KB_LED1_ON (DDRB |= (1<<5))
#define KB_LED1_OFF (DDRB &= ~(1<<5))
@ -29,11 +31,11 @@
#define KB_LED3_SET_PERCENT(n) (OCR1C = (uint8_t)((n) * 0xFF))
#ifdef TEENSY_2_0_h_INCLUDE_PRIVATE
#ifdef KEYBOARD_INCLUDE_PRIVATE
uint8_t teensy_init(void);
uint8_t teensy_update_matrix(
uint8_t matrix[KB_ROWS][KB_COLUMNS] );
bool matrix[KB_ROWS][KB_COLUMNS] );
#endif

View File

@ -1,6 +1,6 @@
# Documentation : Teensy 2.0
## Pinouts and Pin assignments
## Pinout and Pin assignments
* `+` indicates pin
* `o` indicates unused pin
@ -38,12 +38,13 @@
column3 PD2 + + OC1A LED1
column4 PD3 + + PB4 column0
column1 PC6 + + PD7 column5
column2 PC7 +-o-o-o-o-o-o
column2 PC7 +-o-o-o-o-o-+ PD6 onboardLED
* notes:
* SCL and SDA: Need external pull-up resistors. Sometimes the Teensy
internal pull-ups are enough (see datasheet section 20.5.1), but i think
for this project we'll want external ones.
for this project we'll want external ones. The general recommendation for
400kHz I&sup2;C seems to be 2.2kΩ.
## Notes about Registers
@ -61,11 +62,11 @@
read returns the logical value (1|0) of the pin
* notes:
* Unused pins should be set as input with internal pullup enabled (see
datasheet section 10.2.6) in order to give them a defined level.
* PD6 already has a defined level (low) since it's hooked up to the onboard
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.
* Unused pins should be set as input, with internal pullup enabled in order
to give them a defined level (see datasheet section 10.2.6).
* PD6 (the onboard LED) already has a defined level (low), 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 'hi-Z' initially (set as input with pull-up disabled),
and the column pins set as input with internal pull-up enabled. We'll
cycle through driving the row pins low (setting them as output) and
@ -86,7 +87,8 @@
"Clear OCnA/OCnB/OCnC on compare match, set OCnA/OCnB/OCnC at TOP"
(see table 14-3)
this way higher values of `OCR1(A|B|C)` will mean longer 'on' times for the
LEDs
LEDs (provided they're hooked up to GND; other way around if they're hooked
up to Vcc)
* when in a fast PWM mode, set `TCCR1A[7,6,5,4,3,2]` to `1,0,1,0,1,0`
* we want "Clock Select Bit Description" to be `0b001`
"clkI/O/1 (No prescaling)"

View File

@ -349,7 +349,8 @@ int8_t usb_keyboard_send(void)
//
ISR(USB_GEN_vect)
{
uint8_t intbits, t, i;
uint8_t intbits, i; // used to declare `t` as well, but it wasn't used
// ::Blazak, 2012::
static uint8_t div4=0;
intbits = UDINT;

View File

@ -19,6 +19,8 @@ extern volatile uint8_t keyboard_leds;
#define usb_debug_flush_output()
#if 0 // removed in favor of equilivent code elsewhere ::Ben Blazak, 2012::
#define KEY_CTRL 0x01
#define KEY_SHIFT 0x02
#define KEY_ALT 0x04
@ -129,6 +131,8 @@ extern volatile uint8_t keyboard_leds;
#define KEYPAD_0 98
#define KEYPAD_PERIOD 99
#endif

View File

@ -10,6 +10,7 @@
#ifndef DATA_TYPES_h
#define DATA_TYPES_h
#include <stddef.h>
#include <stdint.h>
#define bool _Bool

View File

@ -39,8 +39,8 @@ uint8_t twi_start(void) {
// 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) )
if ( (TW_STATUS != TW_START) &&
(TW_STATUS != TW_REP_START) )
return TW_STATUS; // error
return 0; // success
}
@ -60,9 +60,9 @@ uint8_t twi_send(uint8_t data) {
// 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) )
if ( (TW_STATUS != TW_MT_SLA_ACK) &&
(TW_STATUS != TW_MT_DATA_ACK) &&
(TW_STATUS != TW_MR_SLA_ACK) )
return TW_STATUS; // error
return 0; // success
}

View File

@ -11,7 +11,7 @@
#define TWI_h
#ifndef TWI_FREQ
#define TWI_FREQ 100000
#define TWI_FREQ 100000 // in Hz
#endif

98
src/main.c Normal file
View File

@ -0,0 +1,98 @@
// vim: ts=4 sw=4 sts=4
/* ----------------------------------------------------------------------------
* main()
* ----------------------------------------------------------------------------
* 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/delay.h>
#include "lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "lib/data-types.h"
#include "keyboard.h"
//dbg
int main(void) {
kb_init(); // does controller initialization too
usb_init();
while (!usb_configured());
_delay_ms(1000); // make sure the OS has had time to load drivers, etc.
for (;;) {
// int current_layer = 0;
KB_LED1_ON; _delay_ms(200); KB_LED1_OFF; _delay_ms(200);
KB_LED1_ON; _delay_ms(200); KB_LED1_OFF; _delay_ms(200);
// for (int row=0; row<KB_ROWS; row++)
// for (int col=0; col<KB_COLUMNS; col++)
// (*kb_is_pressed)[row][col] = 0;
// kb_update_matrix(*kb_is_pressed);
//
// for (int row=0; row<KB_ROWS; row++) {
// for (int col=0; col<KB_COLUMNS; col++) {
// if ((*kb_is_pressed)[row][col]) {
// usb_keyboard_press(kb_layout[current_layer][row][col], 0);
// }
// }
// }
}
}
#if 0 //dbg
int main(void) {
kb_init(); // does controller initialization too
usb_init();
while (!usb_configured());
_delay_ms(1000); // make sure the OS has had time to load drivers, etc.
for (;;) {
static uint8_t current_layer = 0;
// swap `kb_is_pressed` and `kb_was_pressed`, then update
bool (*temp)[KB_ROWS][KB_COLUMNS] = kb_was_pressed;
kb_was_pressed = kb_is_pressed;
kb_is_pressed = temp;
kb_update_matrix(*kb_is_pressed);
// call the appropriate function for each key, then send the report
for (uint8_t row=0; row<KB_ROWS; row++)
for (uint8_t col=0; col<KB_COLUMNS; col++)
if (*kb_is_pressed[row][col] != *kb_was_pressed[row][col]) {
if (!*kb_is_pressed[row][col])
if (*kb_layout_press[current_layer][row][col])
(*kb_layout_press[current_layer][row][col])(
&kb_layout[current_layer][row][col],
&current_layer, &row, &col );
} else
if (*kb_layout_release[current_layer][row][col])
(*kb_layout_release[current_layer][row][col])(
&kb_layout[current_layer][row][col],
&current_layer, &row, &col );
}
usb_keyboard_send();
// update LEDs
(keyboard_leds & (1<<0)) ? KB_LED1_ON : KB_LED1_OFF; // num lock
(keyboard_leds & (1<<1)) ? KB_LED2_ON : KB_LED2_OFF; // caps lock
(keyboard_leds & (1<<2)) ? KB_LED3_ON : KB_LED3_OFF; // scroll lock
#if 0 // not implemented right now
(keyboard_leds & (1<<3)) ? KB_LED4_ON : KB_LED4_OFF; // compose
(keyboard_leds & (1<<4)) ? KB_LED5_ON : KB_LED5_OFF; // kana
#endif
}
return 0;
}
#endif

View File

@ -12,8 +12,9 @@ TARGET = ergodox-firmware
SRC = $(shell find -maxdepth 1 -name '*.c') \
$(shell find ./keyboard -name '*.c') \
$(shell find ./lib -name '*.c')
$(shell find ./lib -name '*.c') \
'./lib-other/pjrc/usb_keyboard/usb_keyboard.c'
EXTRAINCDIRS = .
@ -23,7 +24,7 @@ TEENSY_MAKE = $(MAKE) -f 'lib-other/pjrc/blinky/Makefile' \
EXTRAINCDIRS='$(EXTRAINCDIRS)'
.PHONY: all clean
.PHONY: all clean debug
all:
$(TEENSY_MAKE) all
@ -32,3 +33,6 @@ clean:
$(TEENSY_MAKE) clean
git clean -X
debug:
$(TEENSY_MAKE) debug

View File

@ -10,13 +10,13 @@
TARGET = test
EXTRAINCDIRS = .
EXTRAINCDIRS = ..
TEENSY_MAKE = $(MAKE) -f '../lib-other/pjrc/blinky/Makefile' \
TARGET='$(TARGET)' \
EXTRAINCDIRS='$(EXTRAINCDIRS)'
.PHONY: test_pwm test_twi
.PHONY: test_pwm test_twi test_twi_2
test_pwm:
$(TEENSY_MAKE) all \
@ -26,6 +26,10 @@ test_twi:
$(TEENSY_MAKE) all \
SRC='test_twi.c'
test_twi_2:
$(TEENSY_MAKE) all \
SRC='test_twi_2.c'
.PHONY: clean
clean:

View File

@ -8,19 +8,39 @@
#include <util/delay.h>
#define TEENSY_2_0_h_INCLUDE_PRIVATE
#include "../keyboard/ergodox/teensy-2-0.h"
#include "../keyboard/ergodox/teensy-2-0.c"
#include <avr/io.h>
#define bool uint8_t
#define bool _Bool
#define true 1
#define false 0
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
// LED control
#define KB_LED1_ON (DDRB |= (1<<5))
#define KB_LED1_OFF (DDRB &= ~(1<<5))
#define KB_LED1_SET(n) (OCR1A = (uint8_t)(n))
#define KB_LED1_SET_PERCENT(n) (OCR1A = (uint8_t)((n) * 0xFF))
#define KB_LED2_ON (DDRB |= (1<<6))
#define KB_LED2_OFF (DDRB &= ~(1<<6))
#define KB_LED2_SET(n) (OCR1B = (uint8_t)(n))
#define KB_LED2_SET_PERCENT(n) (OCR1B = (uint8_t)((n) * 0xFF))
#define KB_LED3_ON (DDRB |= (1<<7))
#define KB_LED3_OFF (DDRB &= ~(1<<7))
#define KB_LED3_SET(n) (OCR1C = (uint8_t)(n))
#define KB_LED3_SET_PERCENT(n) (OCR1C = (uint8_t)((n) * 0xFF))
int main(void) {
CPU_PRESCALE(0); // set for 16MHz
// pwm init for keyboard LEDs
// (see "PWM on ports OC1(A|B|C)" in "teensy-2-0.md")
DDRB |= 0b11100000; // set B(7,6,5) as output
TCCR1A = 0b10101001; // set and configure fast PWM
TCCR1B = 0b00001001; // set and configure fast PWM
void main(void) {
teensy_init();
for (uint8_t i=0; i<3; i++) {
KB_LED1_SET(0x10);

92
src/test/test_twi_2.c Normal file
View File

@ -0,0 +1,92 @@
/* ----------------------------------------------------------------------------
* Test TWI write (with a Teensy 2.0 and I/O expander)
* ----------------------------------------------------------------------------
* 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 <avr/io.h>
#include <util/twi.h>
#include <util/delay.h>
#define TWI_FREQ 400000
#include "../lib/teensy-2-0/twi.c"
// processor frequency (from <http://www.pjrc.com/teensy/prescaler.html>)
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------
#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); \
}
// ---------------------------------------------------------------------------- // TWI
// ----------------------------------------------------------------------------
#define IODIRA 0x00
#define IODIRB 0x01
#define GPPUA 0x0C
#define GPPUB 0x0D
#define GPIOA 0x12
#define GPIOB 0x13
#define OLATA 0x14
#define OLATB 0x15
#define TWI_ADDR_WRITE (0b0100000<<1)|TW_WRITE
#define TWI_ADDR_READ (0b0100000<<1)|TW_READ
// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------
/* notes:
* - won't work without the `twi_stop()`s after each block
*/
int main(void) {
CPU_PRESCALE(CPU_16MHz);
twi_init();
// set all gpio pins as:
// output
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(IODIRA);
twi_send(0);
twi_send(0);
twi_stop();
// with pull-up
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPPUA);
twi_send(0xff);
twi_send(0xff);
twi_stop();
// logical 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(OLATA);
twi_send(0xff);
twi_send(0xff);
twi_stop();
return 0;
}