first working firmware! :)

- merge from branch 'dev'

implementation / version notes:
- needs testing still (a lot), but with the little i could do on my
  breadboard it looked stable.  6-KRO looks like it works, and the key
  press/release and modifier press/release functions, and LED indicators
  look like they work.  yay!
- looks like it's scanning at about 167 Hz (as accurately as i could
  measure with a prescaling loop, an LED, and a stopwatch).  most of
  this (almost all of it, actually) is due to i2c.  it has the potential
  to get a little faster (maybe slightly past 200 Hz, if i try), but i'm
  not sure if i will since most keyboards i found speeds for online
  scanned at a little less than 100 Hz - so that should be fast enough.
- also, my method of assigning a keycode, press function, and release
  function to each key on each layer seems like it should be time and
  space consuming; but we have plenty of space (we're only using ~11%
  currently), and plenty of time apparently, since the teensy is running
  at 16MHz, and the time used by the extra function calls pales in
  comparison to the time used by the i2c functions.

other notes:
- see the *.md files for documentation about everything.  i did my best
  to make and keep them accurate with the source, so hopefully nothing
  (too important..) got past me.
- also, there's a nice circuit diagram under
  "src/keyboard/ergodox/_circuit-diagram.svg" :) .  i like it a lot, and
  it's accurate for now, but i'm not sure how maintainable it'll be if
  the pins change.

yay!! :D  i'm so happy i got it working.
f13
Ben Blazak 2012-04-11 22:35:40 -07:00
commit 201e38c576
44 changed files with 8757 additions and 18 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*~
*.swp

View File

@ -1,12 +1,20 @@
## Noob Electronics Stuff
## Electronics Stuff
* [Resistor Color Codes (picture)]
* [Resistor Color Codes]
(http://www.ladyada.net/wiki/lib/exe/fetch.php?hash=a2c6a9&w=501&h=785&media=http%3A%2F%2Fwww.ladyada.net%2Fimages%2Fmetertutorial%2Frescolorcode.jpg)
: image
* from [the Multimeter Tutorial]
(http://www.ladyada.net/learn/multimeter/resistance.html)
(on <http://ladyada.net/>)
* [Schematic Symbols]
(http://img.docstoccdn.com/thumb/orig/28066054.png)
: image
* [Vcc, Vdd, Vss, etc.]
(http://encyclobeamia.solarbotics.net/articles/vxx.html)
* [Very Basic Circuits]
(http://www.seattlerobotics.org/encoder/mar97/basics.html)
: column by Kevin Ross for Encoder
@ -23,8 +31,21 @@
-> [powering LEDs]
(http://wolfstone.halloweenhost.com/Lighting/litlpo_PoweringLEDs.html)
* [All About Circuits : Reference]
(http://www.allaboutcircuits.com/vol_5/index.html)
## Noob C Stuff
* [Effects of Varying I2C Pull-Up Resistors]
(http://dsscircuits.com/articles/effects-of-varying-i2c-pull-up-resistors.html) : article by Wayne Truchsess
## 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/)
@ -38,6 +59,9 @@
(http://www.cprogramming.com/tutorial/bitwise_operators.html)
(on <http://cprogramming.com/>)
* [AVR Tutorials - \[TUT\] \[C\] Bit manipulation (AKA "Programming 101")]
(http://www.avrfreaks.net/index.php?name=PNphpBB2&file=printview&t=37871&start=0)
* [In C++ is "const" after type ID acceptable?]
(http://stackoverflow.com/questions/988069/in-c-is-const-after-type-id-acceptable)
(on <http://stackoverflow.com/>)
@ -46,14 +70,27 @@
(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/>)
## Noob Other Stuff
* [The Function Pointer Tutorials]
(http://www.newty.de/fpt/index.html)
* [Markdown: Syntax]
(http://daringfireball.net/projects/markdown/syntax)
* [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/>)
## AVR C stuff
### 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)
@ -62,16 +99,46 @@
(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]
(https://www.mainframe.cx/~ckuethe/avr-c-tutorial/)
by Chris Kuethe
## Articles / Tutorials
## Protocol Stuff
### I&sup2;C
* [Arduino I&sup2;C Expansion IO]
(http://www.neufeld.newton.ks.us/electronics/?p=241)
(from [Keith's Electronics Blog]
(http://www.neufeld.newton.ks.us/electronics/))
* [Arduino Playground :: Wire Library, Explored]
(http://arduino.cc/playground/Main/WireLibraryDetailedReference)
## Other Firmware / Code
### USB
* About Keyboard [Scan Codes]
(http://geekhack.org/showwiki.php?title=Scan+Codes)
(on <http://geekhack.org/>)
* [USB 2.0 Specification]
(http://www.usb.org/developers/docs/usb_20_101111.zip)
: zip (from <http://www.usb.org/developers/docs/>)
* [HID Device Class Definition]
(http://www.usb.org/developers/devclass_docs/HID1_11.pdf)
: pdf (from <http://www.usb.org/developers/hidpage>)
* HID = Human Interface Device
* [HID Usage Tables]
(http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf)
: pdf (from <http://www.usb.org/developers/hidpage>)
## Other People's Code
### Keyboard Firmware
* zip: [Phantom Firmware from PrinsValium]
(http://geekhack.org/attachment.php?attachmentid=38982&d=1327895092)
@ -80,13 +147,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)
@ -100,8 +176,26 @@
* mentioned on [the designer's blog]
(http://humblehacker.com/blog/)
### TWI Libraries
* github: [TWI library in C]
(https://github.com/arduino/Arduino/tree/master/libraries/Wire/utility)
: (arduino / Arduino / libraries / Wire / utility)
* zip: [i2cmaster]
(http://homepage.hispeed.ch/peterfleury/i2cmaster.zip)
(by Peter Fleury, on [his homepage]
(http://homepage.hispeed.ch/peterfleury/))
* forum: [Interfacing MCP23018 io expander via Arduino]
(http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1282150189)
: contains a quick MCP23017 library in C++
* github: [maniacbug / Arduino / libraries / MCP23018]
(https://github.com/maniacbug/Arduino/tree/master/libraries/MCP23018)
: library in C++
### USB
* zip: [PJRC: usb_keyboard]
(http://pjrc.com/teensy/usb_keyboard.zip)
@ -109,6 +203,8 @@
* mentioned on [the PJRC website]
(http://pjrc.com/teensy/usb_keyboard.html)
### Miscellaneous
* zip: [PJRC: blinky]
(http://pjrc.com/teensy/blinky.zip)
@ -116,7 +212,7 @@
(http://pjrc.com/teensy/gcc.html)
## Chip Documentation
## Hardware Documentation
* [Microchip: Analog & Interface Product Selector Guide]
(http://ww1.microchip.com/downloads/en/DeviceDoc/21060z.pdf)
@ -160,3 +256,53 @@
* from [the PJRC website]
(http://pjrc.com/teensy/datasheets.html)
* [Cherry MX Series Keyswitches : Specifications]
(http://www.cherrycorp.com/english/switches/key/mx.htm)
## Miscellaneous
### Documentation and Design Tools
* [Markdown: Syntax]
(http://daringfireball.net/projects/markdown/syntax)
* [KiCAD Tutorial]
(http://teholabs.com/knowledge/kicad.html)
(on <http://teholabs.com/>)
* mentioned on the [circuit/block-diagram drawing]
(http://stackoverflow.com/questions/6422603/circuit-block-diagram-drawing)
question (on <http://stackoverflow.com/>)
* [Ti_k_Z and PGF]
(http://www.texample.net/tikz/)
: a TeX graphics package
* mentioned on the [circuit/block-diagram drawing]
(http://stackoverflow.com/questions/6422603/circuit-block-diagram-drawing)
question (on <http://stackoverflow.com/>)
* [Documentation (for version 2010-09-28)]
(http://www.texample.net/media/pgf/builds/pgfmanualCVS2010-09-28.pdf)
: pdf
* [Example: Block diagram line junctions]
(http://www.texample.net/tikz/examples/line-junctions/)
* [Inkscape : Connector tool tutorial]
(http://wiki.inkscape.org/wiki/index.php/UsingTheConnectorTool)
### Typical Keyboard Information
* [Keyboard Scan Rates]
(http://geekhack.org/showwiki.php?title=Keyboard+scan+rates)
list (on <http://geekhack.org/>)
-------------------------------------------------------------------------------
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>

View File

@ -1,4 +1,54 @@
# [ergodox-firmware][1]: Firmware for the [ergoDOX keyboard][2]
[1]: https://github.com/benblazak/ergodox-firmware
[2]: http://geekhack.org/showthread.php?22780-Interest-Check-Custom-split-ergo-keyboard
# [ergodox-firmware][]: Firmware for the [ergoDOX keyboard][]
[ergodox-firmware]: https://github.com/benblazak/ergodox-firmware
[ergodox keyboard]: http://geekhack.org/showthread.php?22780-Interest-Check-Custom-split-ergo-keyboard
This project is definitely in beta, but I'll do my best to keep the 'master'
branch working. Please see the source (and especially the accompanying '*.md'
files) for documentation.
## Notes
### (2012-04-11)
As of now, it looks like we have a working 6-KRO keyboard firmware for a Teensy
2.0 with a MCP23018 I/O expander. It's scanning at ~167 Hz, most of which is
spent communicating over I&sup2;C. This should be fast enough, I think.
Slight improvements might be possible (without finding a microprocessor capable
of > 400 kHz I&sup2;C or using SPI, that is, which I imagine would speed things
up a lot - but it'd also be much less convenient). I'll attempt them if I see
the need.
Also, layers are implemented, but untested, as no keymaps are written to use
them yet. Implementing on-keyboard hardware remapping seems like it'd be very
possible too, but I'd need to try it (and learn how to programmatically store
stuff in program space) to see if it'd work; and I'm not sure of a good way to
do the interface, since different people will likely have different keycap
layouts on the ergoDOX.
Getting to N-KRO is a goal, but I honestly have no idea whether it'll be
accomplished. Ideally, I'd like a variable-KRO, where the keyboard is 6-KRO
till you press the 7th key (so if you're worried about compatibility, just
don't press more than 6 keys at a time). From what I've read, it might be
possible, but I just finished everything else (so I'm slightly tired), and the
USB spec is scary.
Discussions about the project as a whole are going on at the forum page (linked
in the title) so if you have any imput (or want to participate in the group
buy!), please stop by. :) .
## Dependencies (for building from source)
* See the PJRC [Getting Started] (http://pjrc.com/teensy/first_use.html) page
for instructions on how to set up an AVR programming environment. This
project uses C (not Arduino).
-------------------------------------------------------------------------------
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>

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

@ -0,0 +1,96 @@
/* ----------------------------------------------------------------------------
* 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;
break;
}
}
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;
break;
}
}
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

12
src/keyboard.h Normal file
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

43
src/keyboard/ergodox.c Normal file
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))
return 1;
if (mcp23018_update_matrix(matrix))
return 2;
return 0; // success
}

25
src/keyboard/ergodox.h Normal file
View File

@ -0,0 +1,25 @@
/* ----------------------------------------------------------------------------
* ergoDOX specific exports
* includes (for centralization) the public exports from all subfiles
* ----------------------------------------------------------------------------
* 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

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 151 KiB

View File

@ -0,0 +1,94 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout specific 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/data-types.h"
#include "lib/usb/keyboard-usage-page.h"
#include "key-functions.h"
#include "matrix.h"
#include "layout.h"
// error check; everything below assumes these dimensions
#if KB_LAYERS != 1 || KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
// 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 -------------------------- */
/* 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/*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

@ -0,0 +1,28 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout 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 LAYOUT_h
#define LAYOUT_h
#include "lib/data-types.h"
#include "key-functions.h"
#include "matrix.h"
#define KB_LAYERS 1 // must match what's defined in "layout.c"
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

@ -0,0 +1,20 @@
/* ----------------------------------------------------------------------------
* ergoDOX: keyboard matrix specific 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/data-types.h"
#include "matrix.h"
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

@ -0,0 +1,23 @@
/* ----------------------------------------------------------------------------
* ergoDOX: keyboard matrix 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 MATRIX_h
#define MATRIX_h
#include "lib/data-types.h"
#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_was_pressed)[KB_ROWS][KB_COLUMNS];
#endif

View File

@ -0,0 +1,27 @@
# Documentation : Keyboard Matrix
## Matrix [row##column] assignments
* row and column numbers are in hex
* coordinates without brackets are unused
* left and right hands are mostly the same except that `row += 6` for the left
....... rows x columns = positions; assigned, unassigned .......
....... per hand: 6 x 7 = 42; 38, 4 .......
....... total: 12 x 7 = 84; 76, 8 .......
----------------------------------------------------------------------------
[60][61][62][63][64][65][66] [00][01][02][03][04][05][06]
[70][71][72][73][74][75][76] [10][11][12][13][14][15][16]
[80][81][82][83][84][85] 86 20 [21][22][23][24][25][26]
[90][91][92][93][94][95][96] [30][31][32][33][34][35][36]
[A0][A1][A2][A3][A4] A5 A6 40 41 [42][43][44][45][46]
[B0] B6 50 [56]
[B1] [B5] [51] [55]
[B2][B3][B4] [52][53][54]
-------------------------------------------------------------------------------
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>

View File

@ -0,0 +1,143 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: MCP23018 specific 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 <util/twi.h>
#include "lib/data-types.h"
#include "lib/teensy-2-0/twi.h" // `TWI_FREQ` defined in "teensy-2-0.c"
#define KEYBOARD_INCLUDE_PRIVATE
#include "matrix.h"
#include "mcp23018.h"
// register addresses (see "mcp23018.md")
#define IODIRA 0x00 // i/o direction register
#define IODIRB 0x01
#define GPPUA 0x0C // GPIO pull-up resistor register
#define GPPUB 0x0D
#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
#define GPIOB 0x13
#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 )
/* returns:
* - success: 0
* - failure: twi status code
*
* notes:
* - `twi_stop()` must be called *exactly once* for each twi block, the way
* things are currently set up. this may change in the future.
*/
uint8_t mcp23018_init(void) {
uint8_t ret;
// set pin direction
// - unused : input : 1
// - rows : output : 0
// - columns : input : 1
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(IODIRA);
twi_send(0b11000000); // IODIRA
twi_send(0b11111111); // IODIRB
twi_stop();
// set pull-up
// - unused : on : 1
// - rows : off : 0
// - columns : on : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPPUA);
twi_send(0b11000000); // GPPUA
twi_send(0b11111111); // GPPUB
twi_stop();
// set logical value (doesn't matter on inputs)
// - unused : high (hi-Z) : 1
// - rows : high (hi-Z) : 1
// - columns : high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(OLATA);
twi_send(0b11111111); //OLATA
twi_send(0b11111111); //OLATB
out:
twi_stop();
return ret;
}
/* returns:
* - success: 0
* - failure: twi status code
*/
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
uint8_t mcp23018_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
uint8_t ret, data;
// initialize things, just to make sure
// - it's not appreciably faster to skip this, and it takes care of the
// case when the i/o expander isn't plugged in during the first
// init()
ret = mcp23018_init();
// if there was an error
if (ret) {
// clear our part of the matrix
for (uint8_t row=0x6; row<=0xB; row++)
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = 0;
return ret;
}
// update our part of the matrix
for (uint8_t row=0x6; row<=0xB; row++) {
// set active row low : 0
// set other rows high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(OLATA);
twi_send( 0b11111111 & ~(1<<(row-6)) );
twi_stop();
// read column data
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOB);
twi_start();
twi_send(TWI_ADDR_READ);
twi_read(&data);
twi_stop();
// update matrix
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = !( data & (1<<col) );
}
// set all rows high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send(0b11111111);
twi_stop();
return ret; // success
}

View File

@ -0,0 +1,26 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: MCP23018 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 MCP23018_h
#define MCP23018_h
#include "lib/data-types.h"
#ifdef KEYBOARD_INCLUDE_PRIVATE
#define MCP23018_TWI_ADDRESS 0b0100000
uint8_t mcp23018_init(void);
uint8_t mcp23018_update_matrix(
bool matrix[KB_ROWS][KB_COLUMNS] );
#endif
#endif

View File

@ -0,0 +1,141 @@
# Documentation : MCP23018
## Pinout and Pin assignments
* `+` indicates pin
* `o` indicates unused pin
* `-`s inserted between some of the pin functions for readability
* `OC**` pins enclosed in parenthesis had lines over them in the pinout
### MCP23018
Vss(GND) +01---.---28+ NC
NC +02 27+ GPA7
GPB0 +03 26+ GPA6
GPB1 +04 25+ GPA5
GPB2 +05 24+ GPA4
GPB3 +06 23+ GPA3
GPB4 +07 22+ GPA2
GPB5 +08 21+ GPA1
GPB6 +09 20+ GPA0
GPB7 +10 19+ INTA
Vdd(Vcc) +11 18+ INTB
SCL +12 17+ NC
SDA +13 16+ RESET
NC +14-------15+ ADDR
### MCP32018 Pin Assignments
power_negative Vss(GND) +01---.---28o NC
NC o02 27o GPA7
column0 GPB0 +03 26o GPA6
column1 GPB1 +04 25+ GPA5 rowB
column2 GPB2 +05 24+ GPA4 rowA
column3 GPB3 +06 23+ GPA3 row9
column4 GPB4 +07 22+ GPA2 row8
column5 GPB5 +08 21+ GPA1 row7
column6 GPB6 +09 20+ GPA0 row6
GPB7 o10 19o INTA
power_positive Vdd(Vcc) +11 18o INTB
I2C SCL +12 17o NC
I2C SDA +13 16+ RESET (see note)
NC o14-------15+ ADDR (see note)
* notes:
* ADDR (pin15): Set slave address to `0b0100000` by connecting to Vss(GND).
* The user-defined bits are the three least significant
* I2C addresses are 7 bits long (the last bit in the byte is used for
indicating read/write)
* RESET (pin16) must be externally biased. Since we're not going to trigger
it ourselves, we can 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.
* I'm not the first person who's failed to notice ;)
* <http://davidn.org/wp/?p=89>
* <http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1293498979>
## Notes about Registers
register address function (for all bits)
-------- ------- -----------------------
IODIRA 0x00 \ 1: set corresponding pin as input
IODIRB 0x01 / 0: set ................. as output
GPPUA 0x0C \ 1: set corresponding pin internal pull-up on
GPPUB 0x0D / 0: set .......................... pull-up off
GPIOA 0x12 \ read: returns the value on the port
GPIOB 0x13 / write: modifies the OLAT register
OLATA 0x14 \ read: returns the value of this register
OLATB 0x15 / write: modifies the output latches that control the
pins configured as output
* 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
* 0: The registers are in the same bank (addresses are sequential)
* SEQOP: bit 5; read/write; default = 0
* 1: Sequential operation disabled, address pointer does not increment
* 0: Sequential operation enabled, address pointer increments
* notes:
* All addresses given for IOCON.BANK = 0, since that's the default value of
the bit, and that's what we'll be using.
* We want the row pins set as output high (hi-Z) without pull-ups initially,
and the column pins set as input with pull-ups. We'll cycle through
driving the row pins low and checking the column pins in the update
function.
* abbreviations:
* IODIR = I/O Direction Register
* IOCON = I/O Control Register
* GPPU = GPIO Pull-Up Resistor Register
* GPIO = General Purpose I/O Port Register
* OLAT = Output Latch Register
## I&sup2;C Device Protocol (see datasheet section 1.3, figure 1-1)
S : Start OP : Device opcode
SR : Restart ADDR : Device address
P : Stop Dout : Data out from MCP23018
W : Write Din : Data in to MCP23018
R : Read
S OP W ADDR ----> Din ... Din --> P
|
|--> SR OP R Dout ... Dout ---> P
|<--------------------------|
|
|--> SR OP W ADDR ... Din --> P
|
|--> P
S OP R ----> Dout ... Dout --> P
|
|--> SR OP R Dout ... Dout ---> P
|<--------------------------|
|
|--> SR OP W ADDR Din ... Din --> P
|
|--> P
Byte and Sequential Write
-------------------------
Byte : S OP W ADDR --> Din --> P
Sequential : S OP W ADDR --> Din ... Din --> P
Byte and Sequential Read
------------------------
Byte : S OP W ADDR --> SR OP R Dout --> P
Sequential : S OP W ADDR --> SR OP R Dout ... Dout --> P
* notes:
* We'll be using sequential mode (ICON.SEQOP = 0; default) (see datasheet
section 1.3.1).
-------------------------------------------------------------------------------
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>

View File

@ -0,0 +1,200 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: Teensy 2.0 specific 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 <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"
#include "teensy-2-0.h"
// processor frequency (from <http://www.pjrc.com/teensy/prescaler.html>)
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
#define CPU_8MHz 0x01
#define CPU_4MHz 0x02
#define CPU_2MHz 0x03
#define CPU_1MHz 0x04
#define CPU_500kHz 0x05
#define CPU_250kHz 0x06
#define CPU_125kHz 0x07
#define CPU_62kHz 0x08
/* pin macros
* - note: you can move the `UNUSED`, `ROW`, and `COLUMN` pins around, but be
* sure to keep the set of all the pins listed constant. other pins are not
* movable, and either are referenced explicitly or have macros defined for
* them elsewhere.
* - note: if you change pin assignments, please be sure to update
* "teensy-2-0.md".
*/
// --- helpers
#define TEENSYPIN_WRITE(register, operation, pin) \
_TEENSYPIN_WRITE(register, operation, pin)
#define _TEENSYPIN_WRITE(register, operation, pin_letter, pin_number) \
((register##pin_letter) operation (1<<(pin_number)))
#define TEENSYPIN_READ(pin) \
_TEENSYPIN_READ(pin)
#define _TEENSYPIN_READ(pin_letter, pin_number) \
((PIN##pin_letter) & (1<<(pin_number)))
#define SET |=
#define CLEAR &=~
// --- unused
#define UNUSED_0 B, 1 // SPI pin
#define UNUSED_1 B, 2 // SPI pin
#define UNUSED_2 B, 3 // SPI pin
#define UNUSED_3 D, 4 // hard to use with breadboard (on the end)
#define UNUSED_4 D, 5 // hard to use with breadboard (on the end)
#define UNUSED_5 E, 6 // hard to use with breadboard (internal)
// --- rows
#define ROW_0 F, 0
#define ROW_1 F, 1
#define ROW_2 F, 4
#define ROW_3 F, 5
#define ROW_4 F, 6
#define ROW_5 F, 7
// --- columns
#define COLUMN_0 B, 4
#define COLUMN_1 C, 6
#define COLUMN_2 C, 7
#define COLUMN_3 D, 2
#define COLUMN_4 D, 3
#define COLUMN_5 D, 7
#define COLUMN_6 B, 0
/* returns
* - success: 0
*/
uint8_t teensy_init(void) {
CPU_PRESCALE(CPU_16MHz); // speed should match F_CPU in makefile
// onboard LED
DDRD &= ~(1<<6); // set D(6) as input
PORTD &= ~(1<<6); // set D(6) internal pull-up disabled
// 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
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)
twi_init(); // on pins D(1,0)
// unused pins
// --- set as input
TEENSYPIN_WRITE(DDR, CLEAR, UNUSED_0);
TEENSYPIN_WRITE(DDR, CLEAR, UNUSED_1);
TEENSYPIN_WRITE(DDR, CLEAR, UNUSED_2);
TEENSYPIN_WRITE(DDR, CLEAR, UNUSED_3);
TEENSYPIN_WRITE(DDR, CLEAR, UNUSED_4);
TEENSYPIN_WRITE(DDR, CLEAR, UNUSED_5);
// --- set internal pull-up enabled
TEENSYPIN_WRITE(PORT, SET, UNUSED_0);
TEENSYPIN_WRITE(PORT, SET, UNUSED_1);
TEENSYPIN_WRITE(PORT, SET, UNUSED_2);
TEENSYPIN_WRITE(PORT, SET, UNUSED_3);
TEENSYPIN_WRITE(PORT, SET, UNUSED_4);
TEENSYPIN_WRITE(PORT, SET, UNUSED_5);
// rows
// --- set as input (hi-Z)
TEENSYPIN_WRITE(DDR, CLEAR, ROW_0);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_1);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_2);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_3);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_4);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_5);
// --- set internal pull-up disabled
TEENSYPIN_WRITE(PORT, CLEAR, ROW_0);
TEENSYPIN_WRITE(PORT, CLEAR, ROW_1);
TEENSYPIN_WRITE(PORT, CLEAR, ROW_2);
TEENSYPIN_WRITE(PORT, CLEAR, ROW_3);
TEENSYPIN_WRITE(PORT, CLEAR, ROW_4);
TEENSYPIN_WRITE(PORT, CLEAR, ROW_5);
// columns
// --- set as input
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_0);
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_1);
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_2);
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_3);
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_4);
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_5);
TEENSYPIN_WRITE(DDR, CLEAR, COLUMN_6);
// --- set internal pull-up enabled
TEENSYPIN_WRITE(PORT, SET, COLUMN_0);
TEENSYPIN_WRITE(PORT, SET, COLUMN_1);
TEENSYPIN_WRITE(PORT, SET, COLUMN_2);
TEENSYPIN_WRITE(PORT, SET, COLUMN_3);
TEENSYPIN_WRITE(PORT, SET, COLUMN_4);
TEENSYPIN_WRITE(PORT, SET, COLUMN_5);
TEENSYPIN_WRITE(PORT, SET, COLUMN_6);
return 0; // success
}
/* returns
* - success: 0
*/
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
static inline void _update_columns(
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);
matrix[row][3] = ! TEENSYPIN_READ(COLUMN_3);
matrix[row][4] = ! TEENSYPIN_READ(COLUMN_4);
matrix[row][5] = ! TEENSYPIN_READ(COLUMN_5);
matrix[row][6] = ! TEENSYPIN_READ(COLUMN_6);
}
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, CLEAR, ROW_0); // set row hi-Z (set as input)
TEENSYPIN_WRITE(DDR, SET, ROW_1);
_update_columns(matrix, 1);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_1);
TEENSYPIN_WRITE(DDR, SET, ROW_2);
_update_columns(matrix, 2);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_2);
TEENSYPIN_WRITE(DDR, SET, ROW_3);
_update_columns(matrix, 3);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_3);
TEENSYPIN_WRITE(DDR, SET, ROW_4);
_update_columns(matrix, 4);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_4);
TEENSYPIN_WRITE(DDR, SET, ROW_5);
_update_columns(matrix, 5);
TEENSYPIN_WRITE(DDR, CLEAR, ROW_5);
return 0; // success
}

View File

@ -0,0 +1,43 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: Teensy 2.0 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 TEENSY_2_0_h
#define TEENSY_2_0_h
#include <avr/io.h> // for the register macros
#include "lib/data-types.h"
#include "matrix.h"
// 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))
#ifdef KEYBOARD_INCLUDE_PRIVATE
uint8_t teensy_init(void);
uint8_t teensy_update_matrix(
bool matrix[KB_ROWS][KB_COLUMNS] );
#endif
#endif

View File

@ -0,0 +1,119 @@
# Documentation : Teensy 2.0
## Pinout and Pin assignments
* `+` indicates pin
* `o` indicates unused pin
* `-`s inserted between some of the pin functions for readability
* `OC**` pins enclosed in parenthesis had lines over them in the pinout
### Teensy 2.0
GND +---.....---+ Vcc
SS PB0 + + PF0 ADC0
SCLK PB1 + + PF1 ADC1
MOSI PB2 + + PF4 ADC4
MISO PB3 + + + + PF5 ADC5
RTS OC1C OC0A --------- PB7 + PE6 AREF + PF6 ADC6
OC0B INT0 SCL PD0 + AIN0 + PF7 ADC7
INT1 SDA PD1 + INT6 + PB6 ADC13 OC1B OC4B
RXD1 ----------- INT2 --- PD2 + + PB5 ADC12 OC1A (OC4B)
TXD1 ----------- INT3 --- PD3 + + PB4 ADC11
OC3A (OC4A) -------- PC6 + + PD7 ADC10 T0 -- OC4D
ICP3 ----- OC4A --------- PC7 +-+-+-+-+-+-+ PD6 ADC9 T1 - (OC4D) onboardLED
CTS XCK1 PD5 --/ | | | \-- PD4 ADC8 ------------ ICP1
Vcc ------------------/ | \-------------- RST
GND --------------------/
### Teensy 2.0 Pin Assignments
power_negative GND +---.....---+ Vcc power_positive
column6 PB0 + + PF0 row0
PB1 o + PF1 row1
PB2 o + PF4 row2
PB3 o o o + PF5 row3
(OC1C) LED3 PB7 + PE6 AREF + PF6 row4
(SCL) I2C PD0 + + PF7 row5
(SDA) I2C PD1 + + PB6 LED2 (OC1B)
column3 PD2 + + PB5 LED1 (OC1A)
column4 PD3 + + PB4 column0
column1 PC6 + + PD7 column5
column2 PC7 +-o-o-o-o-o-+ PD6 onboardLED
PD5 --/ | | | \-- PD4
Vcc ----/ | \---- RST
GND-------/
* 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. The general recommendation for
400kHz I&sup2;C seems to be 2.2kΩ.
## Notes about Registers
### General I/O (see datasheet section 10.2.1)
DDRxn function PORTxn function
1 output 1 drive high
0 drive low
0 input 1 internal pull-up on
0 internal pull-up off
PINxn action function
write 1 toggles the value of PORTxn
read returns the logical value (1|0) of the pin
* notes:
* 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
checking the column pins in the update function.
* Switching the row pins between hi-Z and drive low (treating them as if
they were open drain) seems just as good as, and a little safer than,
driving them high when the row's not active.
### PWM on ports OC1(A|B|C) (see datasheet section 14.10)
* notes: settings:
* PWM pins should be set as outputs.
* we want Waveform Generation Mode 5
(fast PWM, 8-bit)
(see table 14-5)
* set `TCCRB[4,3],TCCRA[1,0]` to `0,1,0,1`
* we want "Compare Output Mode, Fast PWM" to be `0b10`
"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 (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)"
(see table 14-6)
* set `TCCR1B[2,1,0]` to `0,0,1`
* LEDs will be at minimum brightness until OCR1(A|B|C) are changed (since
the default value of all the bits in those registers is 0)
* notes: behavior:
* The pins source current when on, and sink current when off. They aren't
set to high impediance for either.
* In Fast PWM mode setting `OCR1(A|B|C)` to `0` does not make the output on
`OC1(A|B|C)` constant low; just close. Per the datasheet, this isn't true
for every PWM mode.
* abbreviations:
* OCR = Output Compare Register
* TCCR = Timer/Counter Control Register
-------------------------------------------------------------------------------
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>

View File

@ -0,0 +1,614 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Target file name (without extension).
TARGET = blinky
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \
usb_debug_only.c \
print.c
# MCU name, you MUST set this to match the board you are using
# type "make clean" after changing this, so all files will be rebuilt
#
#MCU = at90usb162 # Teensy 1.0
MCU = atmega32u4 # Teensy 2.0
#MCU = at90usb646 # Teensy++ 1.0
#MCU = at90usb1286 # Teensy++ 2.0
# Processor frequency.
# Normally the first thing your program should do is set the clock prescaler,
# so your program will run at the correct speed. You should also set this
# variable to same clock speed. The _delay_ms() macro uses this, and many
# examples use this variable to calculate timings. Do not add a "UL" here.
F_CPU = 16000000
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
OBJDIR = .
# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC =
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS =
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL
# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)
# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS
#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
#CFLAGS += -mshort-calls
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CPPFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)
#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += -Wl,--relax
LDFLAGS += -Wl,--gc-sections
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x
#---------------- Programming Options (avrdude) ----------------
# Programming hardware
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = stk500v2
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = com1 # programmer connected to serial device
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore build sizeafter end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
@echo
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
ELFSIZE = $(SIZE) $(TARGET).elf
sizebefore:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
2>/dev/null; echo; fi
sizeafter:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
2>/dev/null; echo; fi
# Display compiler version information.
gccversion :
@$(CC) --version
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S -z $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
@echo
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C++ source files.
%.s : %.cpp
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list end
clean_list :
@echo
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
$(REMOVE) $(SRC:.c=.i)
$(REMOVEDIR) .dep
# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config

View File

@ -0,0 +1,159 @@
/* LED Blink Example with USB Debug Channel for Teensy USB Development Board
* http://www.pjrc.com/teensy/
* Copyright (c) 2008, 2010 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include "usb_debug_only.h"
#include "print.h"
// Teensy 2.0: LED is active high
#if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB1286__)
#define LED_ON (PORTD |= (1<<6))
#define LED_OFF (PORTD &= ~(1<<6))
// Teensy 1.0: LED is active low
#else
#define LED_ON (PORTD &= ~(1<<6))
#define LED_OFF (PORTD |= (1<<6))
#endif
#define LED_CONFIG (DDRD |= (1<<6))
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define DIT 80 /* unit time for morse code */
void morse_character(char c);
void morse_P(const char *s);
const unsigned char morse_code_table[];
int main(void)
{
unsigned char i;
// set for 16 MHz clock, and make sure the LED is off
CPU_PRESCALE(0);
LED_CONFIG;
LED_OFF;
// initialize the USB, but don't want for the host to
// configure. The first several messages sent will be
// lost because the PC hasn't configured the USB yet,
// but we care more about blinking than debug messages!
usb_init();
// blink morse code messages!
while (1) {
for (i=0; i<6; i++) {
morse_P(PSTR("SOS"));
_delay_ms(1500);
}
morse_P(PSTR("DOES ANYBODY STILL KNOW MORSE CODE?"));
_delay_ms(4000);
}
}
// blink a single character in Morse code
void morse_character(char c)
{
unsigned char code, count;
if (c == ' ') {
print("Space\n");
_delay_ms(DIT * 7);
return;
}
if (c < 'A' || c > 'Z') {
print("Opps, unsupported character: ");
pchar(c);
print("\n");
return;
}
print("Char ");
pchar(c);
pchar(':');
code = pgm_read_byte(morse_code_table + (c - 'A'));
for (count = code & 0x07; count > 0; count--) {
LED_ON;
if (code & 0x80) {
print(" dah");
_delay_ms(DIT * 3);
} else {
print(" dit");
_delay_ms(DIT);
}
LED_OFF;
_delay_ms(DIT);
code = code << 1;
}
print("\n");
_delay_ms(DIT * 2);
}
// blink an entire message in Morse code
// the string must be in flash memory (using PSTR macro)
void morse_P(const char *s)
{
char c;
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
morse_character(c);
}
print("\n");
}
// lookup table for all 26 letters. Upper 5 bits are the pulses
// to send (MSB first), and the lower 3 bits are the number of
// bits to send for this letter.
const unsigned char PROGMEM morse_code_table[] = {
0x40 + 2, // A: .-
0x80 + 4, // B: -...
0xA0 + 4, // C: -.-.
0x80 + 3, // D: -..
0x00 + 1, // E: .
0x20 + 4, // F: ..-.
0xC0 + 3, // G: --.
0x00 + 4, // H: ....
0x00 + 2, // I: ..
0x70 + 4, // J: .---
0xA0 + 3, // K: -.-
0x40 + 4, // L: .-..
0xC0 + 2, // M: --
0x80 + 2, // N: -.
0xE0 + 3, // O: ---
0x60 + 4, // P: .--.
0xD0 + 4, // Q: --.-
0x40 + 3, // R: .-.
0x00 + 3, // S: ...
0x80 + 1, // T: -
0x20 + 3, // U: ..-
0x10 + 4, // V: ...-
0x60 + 3, // W: .--
0x90 + 4, // X: -..-
0xB0 + 4, // Y: -.--
0xC0 + 4 // Z: --..
};

View File

@ -0,0 +1,62 @@
/* Very basic print functions, intended to be used with usb_debug_only.c
* http://www.pjrc.com/teensy/
* Copyright (c) 2008 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Version 1.0: Initial Release
#include <avr/io.h>
#include <avr/pgmspace.h>
#include "print.h"
void print_P(const char *s)
{
char c;
while (1) {
c = pgm_read_byte(s++);
if (!c) break;
if (c == '\n') usb_debug_putchar('\r');
usb_debug_putchar(c);
}
}
void phex1(unsigned char c)
{
usb_debug_putchar(c + ((c < 10) ? '0' : 'A' - 10));
}
void phex(unsigned char c)
{
phex1(c >> 4);
phex1(c & 15);
}
void phex16(unsigned int i)
{
phex(i >> 8);
phex(i);
}

View File

@ -0,0 +1,16 @@
#ifndef print_h__
#define print_h__
#include <avr/pgmspace.h>
#include "usb_debug_only.h"
// this macro allows you to write print("some text") and
// the string is automatically placed into flash memory :)
#define print(s) print_P(PSTR(s))
#define pchar(c) usb_debug_putchar(c)
void print_P(const char *s);
void phex(unsigned char c);
void phex16(unsigned int i);
#endif

View File

@ -0,0 +1,549 @@
/* USB Debug Channel Example for Teensy USB Development Board
* http://www.pjrc.com/teensy/
* Copyright (c) 2008 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Version 1.0: Initial Release
// Version 1.1: Add support for Teensy 2.0
#define USB_SERIAL_PRIVATE_INCLUDE
#include "usb_debug_only.h"
/**************************************************************************
*
* Configurable Options
*
**************************************************************************/
// You can change these to give your code its own name. On Windows,
// these are only used before an INF file (driver install) is loaded.
#define STR_MANUFACTURER L"Your Name"
#define STR_PRODUCT L"Your USB Device"
// Mac OS-X and Linux automatically load the correct drivers. On
// Windows, even though the driver is supplied by Microsoft, an
// INF file is needed to load the driver. These numbers need to
// match the INF file.
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x0479
// USB devices are supposed to implment a halt feature, which is
// rarely (if ever) used. If you comment this line out, the halt
// code will be removed, saving 102 bytes of space (gcc 4.3.0).
// This is not strictly USB compliant, but works with all major
// operating systems.
#define SUPPORT_ENDPOINT_HALT
/**************************************************************************
*
* Endpoint Buffer Configuration
*
**************************************************************************/
// you might want to change the buffer size, up to 64 bytes.
// The host reserves your bandwidth because this is an interrupt
// endpoint, so it won't be available to other interrupt or isync
// endpoints in other devices on the bus.
#define ENDPOINT0_SIZE 32
#define DEBUG_TX_ENDPOINT 3
#define DEBUG_TX_SIZE 32
#define DEBUG_TX_BUFFER EP_DOUBLE_BUFFER
static const uint8_t PROGMEM endpoint_config_table[] = {
0,
0,
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER,
0
};
/**************************************************************************
*
* Descriptor Data
*
**************************************************************************/
// Descriptors are the data that your computer reads when it auto-detects
// this USB device (called "enumeration" in USB lingo). The most commonly
// changed items are editable at the top of this file. Changing things
// in here should only be done by those who've read chapter 9 of the USB
// spec and relevant portions of any USB class specifications!
static uint8_t PROGMEM device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};
static uint8_t PROGMEM hid_report_descriptor[] = {
0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
0x09, 0x74, // Usage 0x74
0xA1, 0x53, // Collection 0x53
0x75, 0x08, // report size = 8 bits
0x15, 0x00, // logical minimum = 0
0x26, 0xFF, 0x00, // logical maximum = 255
0x95, DEBUG_TX_SIZE, // report count
0x09, 0x75, // usage
0x81, 0x02, // Input (array)
0xC0 // end collection
};
#define CONFIG1_DESC_SIZE (9+9+9+7)
#define HID_DESC2_OFFSET (9+9)
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
1, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
0, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(hid_report_descriptor), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
DEBUG_TX_SIZE, 0, // wMaxPacketSize
1 // bInterval
};
// If you're desperate for a little extra code memory, these strings
// can be completely removed if iManufacturer, iProduct, iSerialNumber
// in the device desciptor are changed to zeros.
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
int16_t wString[];
};
static struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_MANUFACTURER),
3,
STR_MANUFACTURER
};
static struct usb_string_descriptor_struct PROGMEM string2 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
};
// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, 0x0000, hid_report_descriptor, sizeof(hid_report_descriptor)},
{0x2100, 0x0000, config1_descriptor+HID_DESC2_OFFSET, 9},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
/**************************************************************************
*
* Variables - these are the only non-stack RAM usage
*
**************************************************************************/
// zero when we are not configured, non-zero when enumerated
static volatile uint8_t usb_configuration=0;
// the time remaining before we transmit any partially full
// packet, or send a zero length packet.
static volatile uint8_t debug_flush_timer=0;
/**************************************************************************
*
* Public Functions - these are the API intended for the user
*
**************************************************************************/
// initialize USB
void usb_init(void)
{
HW_CONFIG();
USB_FREEZE(); // enable USB
PLL_CONFIG(); // config PLL
while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock
USB_CONFIG(); // start USB clock
UDCON = 0; // enable attach resistor
usb_configuration = 0;
UDIEN = (1<<EORSTE)|(1<<SOFE);
sei();
}
// return 0 if the USB is not configured, or the configuration
// number selected by the HOST
uint8_t usb_configured(void)
{
return usb_configuration;
}
// transmit a character. 0 returned on success, -1 on error
int8_t usb_debug_putchar(uint8_t c)
{
static uint8_t previous_timeout=0;
uint8_t timeout, intr_state;
// if we're not online (enumerated and configured), error
if (!usb_configuration) return -1;
// interrupts are disabled so these functions can be
// used from the main program or interrupt context,
// even both in the same program!
intr_state = SREG;
cli();
UENUM = DEBUG_TX_ENDPOINT;
// if we gave up due to timeout before, don't wait again
if (previous_timeout) {
if (!(UEINTX & (1<<RWAL))) {
SREG = intr_state;
return -1;
}
previous_timeout = 0;
}
// wait for the FIFO to be ready to accept data
timeout = UDFNUML + 4;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// have we waited too long?
if (UDFNUML == timeout) {
previous_timeout = 1;
return -1;
}
// has the USB gone offline?
if (!usb_configuration) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = DEBUG_TX_ENDPOINT;
}
// actually write the byte into the FIFO
UEDATX = c;
// if this completed a packet, transmit it now!
if (!(UEINTX & (1<<RWAL))) {
UEINTX = 0x3A;
debug_flush_timer = 0;
} else {
debug_flush_timer = 2;
}
SREG = intr_state;
return 0;
}
// immediately transmit any buffered output.
void usb_debug_flush_output(void)
{
uint8_t intr_state;
intr_state = SREG;
cli();
if (debug_flush_timer) {
UENUM = DEBUG_TX_ENDPOINT;
while ((UEINTX & (1<<RWAL))) {
UEDATX = 0;
}
UEINTX = 0x3A;
debug_flush_timer = 0;
}
SREG = intr_state;
}
/**************************************************************************
*
* Private Functions - not intended for general user consumption....
*
**************************************************************************/
// USB Device Interrupt - handle all device-level events
// the transmit buffer flushing is triggered by the start of frame
//
ISR(USB_GEN_vect)
{
uint8_t intbits, t;
intbits = UDINT;
UDINT = 0;
if (intbits & (1<<EORSTI)) {
UENUM = 0;
UECONX = 1;
UECFG0X = EP_TYPE_CONTROL;
UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
UEIENX = (1<<RXSTPE);
usb_configuration = 0;
}
if (intbits & (1<<SOFI)) {
if (usb_configuration) {
t = debug_flush_timer;
if (t) {
debug_flush_timer = -- t;
if (!t) {
UENUM = DEBUG_TX_ENDPOINT;
while ((UEINTX & (1<<RWAL))) {
UEDATX = 0;
}
UEINTX = 0x3A;
}
}
}
}
}
// Misc functions to wait for ready and send/receive packets
static inline void usb_wait_in_ready(void)
{
while (!(UEINTX & (1<<TXINI))) ;
}
static inline void usb_send_in(void)
{
UEINTX = ~(1<<TXINI);
}
static inline void usb_wait_receive_out(void)
{
while (!(UEINTX & (1<<RXOUTI))) ;
}
static inline void usb_ack_out(void)
{
UEINTX = ~(1<<RXOUTI);
}
// USB Endpoint Interrupt - endpoint 0 is handled here. The
// other endpoints are manipulated by the user-callable
// functions, and the start-of-frame interrupt.
//
ISR(USB_COM_vect)
{
uint8_t intbits;
const uint8_t *list;
const uint8_t *cfg;
uint8_t i, n, len, en;
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t desc_val;
const uint8_t *desc_addr;
uint8_t desc_length;
UENUM = 0;
intbits = UEINTX;
if (intbits & (1<<RXSTPI)) {
bmRequestType = UEDATX;
bRequest = UEDATX;
wValue = UEDATX;
wValue |= (UEDATX << 8);
wIndex = UEDATX;
wIndex |= (UEDATX << 8);
wLength = UEDATX;
wLength |= (UEDATX << 8);
UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
if (bRequest == GET_DESCRIPTOR) {
list = (const uint8_t *)descriptor_list;
for (i=0; ; i++) {
if (i >= NUM_DESC_LIST) {
UECONX = (1<<STALLRQ)|(1<<EPEN); //stall
return;
}
desc_val = pgm_read_word(list);
if (desc_val != wValue) {
list += sizeof(struct descriptor_list_struct);
continue;
}
list += 2;
desc_val = pgm_read_word(list);
if (desc_val != wIndex) {
list += sizeof(struct descriptor_list_struct)-2;
continue;
}
list += 2;
desc_addr = (const uint8_t *)pgm_read_word(list);
list += 2;
desc_length = pgm_read_byte(list);
break;
}
len = (wLength < 256) ? wLength : 255;
if (len > desc_length) len = desc_length;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
UEDATX = pgm_read_byte(desc_addr++);
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
if (bRequest == SET_ADDRESS) {
usb_send_in();
usb_wait_in_ready();
UDADDR = wValue | (1<<ADDEN);
return;
}
if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
usb_configuration = wValue;
usb_send_in();
cfg = endpoint_config_table;
for (i=1; i<5; i++) {
UENUM = i;
en = pgm_read_byte(cfg++);
UECONX = en;
if (en) {
UECFG0X = pgm_read_byte(cfg++);
UECFG1X = pgm_read_byte(cfg++);
}
}
UERST = 0x1E;
UERST = 0;
return;
}
if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
usb_wait_in_ready();
UEDATX = usb_configuration;
usb_send_in();
return;
}
if (bRequest == GET_STATUS) {
usb_wait_in_ready();
i = 0;
#ifdef SUPPORT_ENDPOINT_HALT
if (bmRequestType == 0x82) {
UENUM = wIndex;
if (UECONX & (1<<STALLRQ)) i = 1;
UENUM = 0;
}
#endif
UEDATX = i;
UEDATX = 0;
usb_send_in();
return;
}
#ifdef SUPPORT_ENDPOINT_HALT
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
&& bmRequestType == 0x02 && wValue == 0) {
i = wIndex & 0x7F;
if (i >= 1 && i <= MAX_ENDPOINT) {
usb_send_in();
UENUM = i;
if (bRequest == SET_FEATURE) {
UECONX = (1<<STALLRQ)|(1<<EPEN);
} else {
UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
UERST = (1 << i);
UERST = 0;
}
return;
}
}
#endif
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
if (wIndex == 0) {
len = wLength;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
UEDATX = 0;
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
}
}
UECONX = (1<<STALLRQ) | (1<<EPEN); // stall
}

View File

@ -0,0 +1,84 @@
#ifndef usb_serial_h__
#define usb_serial_h__
#include <stdint.h>
void usb_init(void); // initialize everything
uint8_t usb_configured(void); // is the USB port configured
int8_t usb_debug_putchar(uint8_t c); // transmit a character
void usb_debug_flush_output(void); // immediately transmit any buffered output
#define USB_DEBUG_HID
// Everything below this point is only intended for usb_serial.c
#ifdef USB_SERIAL_PRIVATE_INCLUDE
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define EP_TYPE_CONTROL 0x00
#define EP_TYPE_BULK_IN 0x81
#define EP_TYPE_BULK_OUT 0x80
#define EP_TYPE_INTERRUPT_IN 0xC1
#define EP_TYPE_INTERRUPT_OUT 0xC0
#define EP_TYPE_ISOCHRONOUS_IN 0x41
#define EP_TYPE_ISOCHRONOUS_OUT 0x40
#define EP_SINGLE_BUFFER 0x02
#define EP_DOUBLE_BUFFER 0x06
#define EP_SIZE(s) ((s) == 64 ? 0x30 : \
((s) == 32 ? 0x20 : \
((s) == 16 ? 0x10 : \
0x00)))
#define MAX_ENDPOINT 4
#define LSB(n) (n & 255)
#define MSB(n) ((n >> 8) & 255)
#if defined(__AVR_AT90USB162__)
#define HW_CONFIG()
#define PLL_CONFIG() (PLLCSR = ((1<<PLLE)|(1<<PLLP0)))
#define USB_CONFIG() (USBCON = (1<<USBE))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#elif defined(__AVR_ATmega32U4__)
#define HW_CONFIG() (UHWCON = 0x01)
#define PLL_CONFIG() (PLLCSR = 0x12)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#elif defined(__AVR_AT90USB646__)
#define HW_CONFIG() (UHWCON = 0x81)
#define PLL_CONFIG() (PLLCSR = 0x1A)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#elif defined(__AVR_AT90USB1286__)
#define HW_CONFIG() (UHWCON = 0x81)
#define PLL_CONFIG() (PLLCSR = 0x16)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#endif
// standard control endpoint request types
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
// HID (human interface device)
#define HID_GET_REPORT 1
#define HID_GET_PROTOCOL 3
#define HID_SET_REPORT 9
#define HID_SET_IDLE 10
#define HID_SET_PROTOCOL 11
// CDC (communication class device)
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#endif
#endif

View File

@ -0,0 +1,614 @@
# Hey Emacs, this is a -*- makefile -*-
#----------------------------------------------------------------------------
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
#
# Released to the Public Domain
#
# Additional material for this makefile was written by:
# Peter Fleury
# Tim Henigan
# Colin O'Flynn
# Reiner Patommel
# Markus Pfaff
# Sander Pool
# Frederik Rouleau
# Carlos Lamas
#
#----------------------------------------------------------------------------
# On command line:
#
# make all = Make software.
#
# make clean = Clean out built project files.
#
# make coff = Convert ELF to AVR COFF.
#
# make extcoff = Convert ELF to AVR Extended COFF.
#
# make program = Download the hex file to the device, using avrdude.
# Please customize the avrdude settings below first!
#
# make debug = Start either simulavr or avarice as specified for debugging,
# with avr-gdb or avr-insight as the front end for debugging.
#
# make filename.s = Just compile filename.c into the assembler code only.
#
# make filename.i = Create a preprocessed source file for use in submitting
# bug reports to the GCC project.
#
# To rebuild project do "make clean" then "make all".
#----------------------------------------------------------------------------
# Target file name (without extension).
TARGET = example
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c \
usb_keyboard.c
# MCU name, you MUST set this to match the board you are using
# type "make clean" after changing this, so all files will be rebuilt
#
#MCU = at90usb162 # Teensy 1.0
MCU = atmega32u4 # Teensy 2.0
#MCU = at90usb646 # Teensy++ 1.0
#MCU = at90usb1286 # Teensy++ 2.0
# Processor frequency.
# Normally the first thing your program should do is set the clock prescaler,
# so your program will run at the correct speed. You should also set this
# variable to same clock speed. The _delay_ms() macro uses this, and many
# examples use this variable to calculate timings. Do not add a "UL" here.
F_CPU = 16000000
# Output format. (can be srec, ihex, binary)
FORMAT = ihex
# Object files directory
# To put object files in current directory, use a dot (.), do NOT make
# this an empty or blank macro!
OBJDIR = .
# List C++ source files here. (C dependencies are automatically generated.)
CPPSRC =
# List Assembler source files here.
# Make them always end in a capital .S. Files ending in a lowercase .s
# will not be considered source files but generated files (assembler
# output from the compiler), and will be deleted upon "make clean"!
# Even though the DOS/Win* filesystem matches both .s and .S the same,
# it will preserve the spelling of the filenames, and gcc itself does
# care about how the name is spelled on its command-line.
ASRC =
# Optimization level, can be [0, 1, 2, 3, s].
# 0 = turn off optimization. s = optimize for size.
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
OPT = s
# Debugging format.
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
# AVR Studio 4.10 requires dwarf-2.
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
DEBUG = dwarf-2
# List any extra directories to look for include files here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRAINCDIRS =
# Compiler flag to set the C Standard level.
# c89 = "ANSI" C
# gnu89 = c89 plus GCC extensions
# c99 = ISO C99 standard (not yet fully implemented)
# gnu99 = c99 plus GCC extensions
CSTANDARD = -std=gnu99
# Place -D or -U options here for C sources
CDEFS = -DF_CPU=$(F_CPU)UL
# Place -D or -U options here for ASM sources
ADEFS = -DF_CPU=$(F_CPU)
# Place -D or -U options here for C++ sources
CPPDEFS = -DF_CPU=$(F_CPU)UL
#CPPDEFS += -D__STDC_LIMIT_MACROS
#CPPDEFS += -D__STDC_CONSTANT_MACROS
#---------------- Compiler Options C ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CFLAGS = -g$(DEBUG)
CFLAGS += $(CDEFS)
CFLAGS += -O$(OPT)
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -ffunction-sections
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
#CFLAGS += -mshort-calls
#CFLAGS += -fno-unit-at-a-time
#CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst)
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
CFLAGS += $(CSTANDARD)
#---------------- Compiler Options C++ ----------------
# -g*: generate debugging information
# -O*: optimization level
# -f...: tuning, see GCC manual and avr-libc documentation
# -Wall...: warning level
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns...: create assembler listing
CPPFLAGS = -g$(DEBUG)
CPPFLAGS += $(CPPDEFS)
CPPFLAGS += -O$(OPT)
CPPFLAGS += -funsigned-char
CPPFLAGS += -funsigned-bitfields
CPPFLAGS += -fpack-struct
CPPFLAGS += -fshort-enums
CPPFLAGS += -fno-exceptions
CPPFLAGS += -Wall
CPPFLAGS += -Wundef
#CPPFLAGS += -mshort-calls
#CPPFLAGS += -fno-unit-at-a-time
#CPPFLAGS += -Wstrict-prototypes
#CPPFLAGS += -Wunreachable-code
#CPPFLAGS += -Wsign-compare
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
#CPPFLAGS += $(CSTANDARD)
#---------------- Assembler Options ----------------
# -Wa,...: tell GCC to pass this to the assembler.
# -adhlns: create listing
# -gstabs: have the assembler create line number information; note that
# for use in COFF files, additional information about filenames
# and function names needs to be present in the assembler source
# files -- see avr-libc docs [FIXME: not yet described there]
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
# dump that will be displayed for a given single line of source input.
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
#---------------- Library Options ----------------
# Minimalistic printf version
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
# Floating point printf version (requires MATH_LIB = -lm below)
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
# If this is left blank, then it will use the Standard printf version.
PRINTF_LIB =
#PRINTF_LIB = $(PRINTF_LIB_MIN)
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
# Minimalistic scanf version
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
# If this is left blank, then it will use the Standard scanf version.
SCANF_LIB =
#SCANF_LIB = $(SCANF_LIB_MIN)
#SCANF_LIB = $(SCANF_LIB_FLOAT)
MATH_LIB = -lm
# List any extra directories to look for libraries here.
# Each directory must be seperated by a space.
# Use forward slashes for directory separators.
# For a directory that has spaces, enclose it in quotes.
EXTRALIBDIRS =
#---------------- External Memory Options ----------------
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# used for variables (.data/.bss) and heap (malloc()).
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
# only used for heap (malloc()).
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
EXTMEMOPTS =
#---------------- Linker Options ----------------
# -Wl,...: tell GCC to pass this to linker.
# -Map: create map file
# --cref: add cross reference to map file
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
LDFLAGS += -Wl,--relax
LDFLAGS += -Wl,--gc-sections
LDFLAGS += $(EXTMEMOPTS)
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
#LDFLAGS += -T linker_script.x
#---------------- Programming Options (avrdude) ----------------
# Programming hardware
# Type: avrdude -c ?
# to get a full listing.
#
AVRDUDE_PROGRAMMER = stk500v2
# com1 = serial port. Use lpt1 to connect to parallel port.
AVRDUDE_PORT = com1 # programmer connected to serial device
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep
# Uncomment the following if you want avrdude's erase cycle counter.
# Note that this counter needs to be initialized first using -Yn,
# see avrdude manual.
#AVRDUDE_ERASE_COUNTER = -y
# Uncomment the following if you do /not/ wish a verification to be
# performed after programming the device.
#AVRDUDE_NO_VERIFY = -V
# Increase verbosity level. Please use this when submitting bug
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude>
# to submit bug reports.
#AVRDUDE_VERBOSE = -v -v
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
#---------------- Debugging Options ----------------
# For simulavr only - target MCU frequency.
DEBUG_MFREQ = $(F_CPU)
# Set the DEBUG_UI to either gdb or insight.
# DEBUG_UI = gdb
DEBUG_UI = insight
# Set the debugging back-end to either avarice, simulavr.
DEBUG_BACKEND = avarice
#DEBUG_BACKEND = simulavr
# GDB Init Filename.
GDBINIT_FILE = __avr_gdbinit
# When using avarice settings for the JTAG
JTAG_DEV = /dev/com1
# Debugging port used to communicate between GDB / avarice / simulavr.
DEBUG_PORT = 4242
# Debugging host used to communicate between GDB / avarice / simulavr, normally
# just set to localhost unless doing some sort of crazy debugging when
# avarice is running on a different computer.
DEBUG_HOST = localhost
#============================================================================
# Define programs and commands.
SHELL = sh
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
SIZE = avr-size
AR = avr-ar rcs
NM = avr-nm
AVRDUDE = avrdude
REMOVE = rm -f
REMOVEDIR = rm -rf
COPY = cp
WINSHELL = cmd
# Define Messages
# English
MSG_ERRORS_NONE = Errors: none
MSG_BEGIN = -------- begin --------
MSG_END = -------- end --------
MSG_SIZE_BEFORE = Size before:
MSG_SIZE_AFTER = Size after:
MSG_COFF = Converting to AVR COFF:
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
MSG_FLASH = Creating load file for Flash:
MSG_EEPROM = Creating load file for EEPROM:
MSG_EXTENDED_LISTING = Creating Extended Listing:
MSG_SYMBOL_TABLE = Creating Symbol Table:
MSG_LINKING = Linking:
MSG_COMPILING = Compiling C:
MSG_COMPILING_CPP = Compiling C++:
MSG_ASSEMBLING = Assembling:
MSG_CLEANING = Cleaning project:
MSG_CREATING_LIBRARY = Creating library:
# Define all object files.
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
# Define all listing files.
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
# Compiler flags to generate dependency files.
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
# Combine all necessary flags and optional flags.
# Add target processor to flags.
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
# Default target.
all: begin gccversion sizebefore build sizeafter end
# Change the build target to build a HEX file or a library.
build: elf hex eep lss sym
#build: lib
elf: $(TARGET).elf
hex: $(TARGET).hex
eep: $(TARGET).eep
lss: $(TARGET).lss
sym: $(TARGET).sym
LIBNAME=lib$(TARGET).a
lib: $(LIBNAME)
# Eye candy.
# AVR Studio 3.x does not check make's exit code but relies on
# the following magic strings to be generated by the compile job.
begin:
@echo
@echo $(MSG_BEGIN)
end:
@echo $(MSG_END)
@echo
# Display size of file.
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
ELFSIZE = $(SIZE) $(TARGET).elf
sizebefore:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
2>/dev/null; echo; fi
sizeafter:
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
2>/dev/null; echo; fi
# Display compiler version information.
gccversion :
@$(CC) --version
# Program the device.
program: $(TARGET).hex $(TARGET).eep
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
# Generate avr-gdb config/init file which does the following:
# define the reset signal, load the target file, connect to target, and set
# a breakpoint at main().
gdb-config:
@$(REMOVE) $(GDBINIT_FILE)
@echo define reset >> $(GDBINIT_FILE)
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
@echo end >> $(GDBINIT_FILE)
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
ifeq ($(DEBUG_BACKEND),simulavr)
@echo load >> $(GDBINIT_FILE)
endif
@echo break main >> $(GDBINIT_FILE)
debug: gdb-config $(TARGET).elf
ifeq ($(DEBUG_BACKEND), avarice)
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
@$(WINSHELL) /c pause
else
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
endif
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
COFFCONVERT = $(OBJCOPY) --debugging
COFFCONVERT += --change-section-address .data-0x800000
COFFCONVERT += --change-section-address .bss-0x800000
COFFCONVERT += --change-section-address .noinit-0x800000
COFFCONVERT += --change-section-address .eeprom-0x810000
coff: $(TARGET).elf
@echo
@echo $(MSG_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
extcoff: $(TARGET).elf
@echo
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
# Create final output files (.hex, .eep) from ELF output file.
%.hex: %.elf
@echo
@echo $(MSG_FLASH) $@
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
%.eep: %.elf
@echo
@echo $(MSG_EEPROM) $@
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
# Create extended listing file from ELF output file.
%.lss: %.elf
@echo
@echo $(MSG_EXTENDED_LISTING) $@
$(OBJDUMP) -h -S -z $< > $@
# Create a symbol table from ELF output file.
%.sym: %.elf
@echo
@echo $(MSG_SYMBOL_TABLE) $@
$(NM) -n $< > $@
# Create library from object files.
.SECONDARY : $(TARGET).a
.PRECIOUS : $(OBJ)
%.a: $(OBJ)
@echo
@echo $(MSG_CREATING_LIBRARY) $@
$(AR) $@ $(OBJ)
# Link: create ELF output file from object files.
.SECONDARY : $(TARGET).elf
.PRECIOUS : $(OBJ)
%.elf: $(OBJ)
@echo
@echo $(MSG_LINKING) $@
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
# Compile: create object files from C source files.
$(OBJDIR)/%.o : %.c
@echo
@echo $(MSG_COMPILING) $<
$(CC) -c $(ALL_CFLAGS) $< -o $@
# Compile: create object files from C++ source files.
$(OBJDIR)/%.o : %.cpp
@echo
@echo $(MSG_COMPILING_CPP) $<
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
# Compile: create assembler files from C source files.
%.s : %.c
$(CC) -S $(ALL_CFLAGS) $< -o $@
# Compile: create assembler files from C++ source files.
%.s : %.cpp
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
# Assemble: create object files from assembler source files.
$(OBJDIR)/%.o : %.S
@echo
@echo $(MSG_ASSEMBLING) $<
$(CC) -c $(ALL_ASFLAGS) $< -o $@
# Create preprocessed source for use in sending a bug report.
%.i : %.c
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
# Target: clean project.
clean: begin clean_list end
clean_list :
@echo
@echo $(MSG_CLEANING)
$(REMOVE) $(TARGET).hex
$(REMOVE) $(TARGET).eep
$(REMOVE) $(TARGET).cof
$(REMOVE) $(TARGET).elf
$(REMOVE) $(TARGET).map
$(REMOVE) $(TARGET).sym
$(REMOVE) $(TARGET).lss
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
$(REMOVE) $(SRC:.c=.s)
$(REMOVE) $(SRC:.c=.d)
$(REMOVE) $(SRC:.c=.i)
$(REMOVEDIR) .dep
# Create object files directory
$(shell mkdir $(OBJDIR) 2>/dev/null)
# Include the dependency files.
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
# Listing of phony targets.
.PHONY : all begin finish end sizebefore sizeafter gccversion \
build elf hex eep lss sym coff extcoff \
clean clean_list program debug gdb-config

View File

@ -0,0 +1,124 @@
/* Keyboard example for Teensy USB Development Board
* http://www.pjrc.com/teensy/usb_keyboard.html
* Copyright (c) 2008 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usb_keyboard.h"
#define LED_CONFIG (DDRD |= (1<<6))
#define LED_ON (PORTD &= ~(1<<6))
#define LED_OFF (PORTD |= (1<<6))
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
uint8_t number_keys[10]=
{KEY_0,KEY_1,KEY_2,KEY_3,KEY_4,KEY_5,KEY_6,KEY_7,KEY_8,KEY_9};
uint16_t idle_count=0;
int main(void)
{
uint8_t b, d, mask, i, reset_idle;
uint8_t b_prev=0xFF, d_prev=0xFF;
// set for 16 MHz clock
CPU_PRESCALE(0);
// Configure all port B and port D pins as inputs with pullup resistors.
// See the "Using I/O Pins" page for details.
// http://www.pjrc.com/teensy/pins.html
DDRD = 0x00;
DDRB = 0x00;
PORTB = 0xFF;
PORTD = 0xFF;
// Initialize the USB, and then wait for the host to set configuration.
// If the Teensy is powered without a PC connected to the USB port,
// this will wait forever.
usb_init();
while (!usb_configured()) /* wait */ ;
// Wait an extra second for the PC's operating system to load drivers
// and do whatever it does to actually be ready for input
_delay_ms(1000);
// Configure timer 0 to generate a timer overflow interrupt every
// 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock
// This demonstrates how to use interrupts to implement a simple
// inactivity timeout.
TCCR0A = 0x00;
TCCR0B = 0x05;
TIMSK0 = (1<<TOIE0);
while (1) {
// read all port B and port D pins
b = PINB;
d = PIND;
// check if any pins are low, but were high previously
mask = 1;
reset_idle = 0;
for (i=0; i<8; i++) {
if (((b & mask) == 0) && (b_prev & mask) != 0) {
usb_keyboard_press(KEY_B, KEY_SHIFT);
usb_keyboard_press(number_keys[i], 0);
reset_idle = 1;
}
if (((d & mask) == 0) && (d_prev & mask) != 0) {
usb_keyboard_press(KEY_D, KEY_SHIFT);
usb_keyboard_press(number_keys[i], 0);
reset_idle = 1;
}
mask = mask << 1;
}
// if any keypresses were detected, reset the idle counter
if (reset_idle) {
// variables shared with interrupt routines must be
// accessed carefully so the interrupt routine doesn't
// try to use the variable in the middle of our access
cli();
idle_count = 0;
sei();
}
// now the current pins will be the previous, and
// wait a short delay so we're not highly sensitive
// to mechanical "bounce".
b_prev = b;
d_prev = d;
_delay_ms(2);
}
}
// This interrupt routine is run approx 61 times per second.
// A very simple inactivity timeout is implemented, where we
// will send a space character.
ISR(TIMER0_OVF_vect)
{
idle_count++;
if (idle_count > 61 * 8) {
idle_count = 0;
usb_keyboard_press(KEY_SPACE, 0);
}
}

View File

@ -0,0 +1,593 @@
/* USB Keyboard Example for Teensy USB Development Board
* http://www.pjrc.com/teensy/usb_keyboard.html
* Copyright (c) 2009 PJRC.COM, LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
// Version 1.0: Initial Release
// Version 1.1: Add support for Teensy 2.0
#define USB_SERIAL_PRIVATE_INCLUDE
#include "usb_keyboard.h"
/**************************************************************************
*
* Configurable Options
*
**************************************************************************/
// You can change these to give your code its own name.
#define STR_MANUFACTURER L"MfgName"
#define STR_PRODUCT L"Keyboard"
// Mac OS-X and Linux automatically load the correct drivers. On
// Windows, even though the driver is supplied by Microsoft, an
// INF file is needed to load the driver. These numbers need to
// match the INF file.
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x047C
// USB devices are supposed to implment a halt feature, which is
// rarely (if ever) used. If you comment this line out, the halt
// code will be removed, saving 102 bytes of space (gcc 4.3.0).
// This is not strictly USB compliant, but works with all major
// operating systems.
#define SUPPORT_ENDPOINT_HALT
/**************************************************************************
*
* Endpoint Buffer Configuration
*
**************************************************************************/
#define ENDPOINT0_SIZE 32
#define KEYBOARD_INTERFACE 0
#define KEYBOARD_ENDPOINT 3
#define KEYBOARD_SIZE 8
#define KEYBOARD_BUFFER EP_DOUBLE_BUFFER
static const uint8_t PROGMEM endpoint_config_table[] = {
0,
0,
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KEYBOARD_SIZE) | KEYBOARD_BUFFER,
0
};
/**************************************************************************
*
* Descriptor Data
*
**************************************************************************/
// Descriptors are the data that your computer reads when it auto-detects
// this USB device (called "enumeration" in USB lingo). The most commonly
// changed items are editable at the top of this file. Changing things
// in here should only be done by those who've read chapter 9 of the USB
// spec and relevant portions of any USB class specifications!
static uint8_t PROGMEM device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
0, // bDeviceClass
0, // bDeviceSubClass
0, // bDeviceProtocol
ENDPOINT0_SIZE, // bMaxPacketSize0
LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor
LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct
0x00, 0x01, // bcdDevice
1, // iManufacturer
2, // iProduct
0, // iSerialNumber
1 // bNumConfigurations
};
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
static uint8_t PROGMEM keyboard_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
0x75, 0x01, // Report Size (1),
0x95, 0x08, // Report Count (8),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0xE0, // Usage Minimum (224),
0x29, 0xE7, // Usage Maximum (231),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x01, // Logical Maximum (1),
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
0x95, 0x01, // Report Count (1),
0x75, 0x08, // Report Size (8),
0x81, 0x03, // Input (Constant), ;Reserved byte
0x95, 0x05, // Report Count (5),
0x75, 0x01, // Report Size (1),
0x05, 0x08, // Usage Page (LEDs),
0x19, 0x01, // Usage Minimum (1),
0x29, 0x05, // Usage Maximum (5),
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report
0x95, 0x01, // Report Count (1),
0x75, 0x03, // Report Size (3),
0x91, 0x03, // Output (Constant), ;LED report padding
0x95, 0x06, // Report Count (6),
0x75, 0x08, // Report Size (8),
0x15, 0x00, // Logical Minimum (0),
0x25, 0x68, // Logical Maximum(104),
0x05, 0x07, // Usage Page (Key Codes),
0x19, 0x00, // Usage Minimum (0),
0x29, 0x68, // Usage Maximum (104),
0x81, 0x00, // Input (Data, Array),
0xc0 // End Collection
};
#define CONFIG1_DESC_SIZE (9+9+9+7)
#define KEYBOARD_HID_DESC_OFFSET (9+9)
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
LSB(CONFIG1_DESC_SIZE), // wTotalLength
MSB(CONFIG1_DESC_SIZE),
1, // bNumInterfaces
1, // bConfigurationValue
0, // iConfiguration
0xC0, // bmAttributes
50, // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
9, // bLength
4, // bDescriptorType
KEYBOARD_INTERFACE, // bInterfaceNumber
0, // bAlternateSetting
1, // bNumEndpoints
0x03, // bInterfaceClass (0x03 = HID)
0x01, // bInterfaceSubClass (0x01 = Boot)
0x01, // bInterfaceProtocol (0x01 = Keyboard)
0, // iInterface
// HID interface descriptor, HID 1.11 spec, section 6.2.1
9, // bLength
0x21, // bDescriptorType
0x11, 0x01, // bcdHID
0, // bCountryCode
1, // bNumDescriptors
0x22, // bDescriptorType
sizeof(keyboard_hid_report_desc), // wDescriptorLength
0,
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
7, // bLength
5, // bDescriptorType
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
0x03, // bmAttributes (0x03=intr)
KEYBOARD_SIZE, 0, // wMaxPacketSize
1 // bInterval
};
// If you're desperate for a little extra code memory, these strings
// can be completely removed if iManufacturer, iProduct, iSerialNumber
// in the device desciptor are changed to zeros.
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
int16_t wString[];
};
static struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_MANUFACTURER),
3,
STR_MANUFACTURER
};
static struct usb_string_descriptor_struct PROGMEM string2 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
};
// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static struct descriptor_list_struct {
uint16_t wValue;
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))
/**************************************************************************
*
* Variables - these are the only non-stack RAM usage
*
**************************************************************************/
// zero when we are not configured, non-zero when enumerated
static volatile uint8_t usb_configuration=0;
// which modifier keys are currently pressed
// 1=left ctrl, 2=left shift, 4=left alt, 8=left gui
// 16=right ctrl, 32=right shift, 64=right alt, 128=right gui
uint8_t keyboard_modifier_keys=0;
// which keys are currently pressed, up to 6 keys may be down at once
uint8_t keyboard_keys[6]={0,0,0,0,0,0};
// protocol setting from the host. We use exactly the same report
// either way, so this variable only stores the setting since we
// are required to be able to report which setting is in use.
static uint8_t keyboard_protocol=1;
// the idle configuration, how often we send the report to the
// host (ms * 4) even when it hasn't changed
static uint8_t keyboard_idle_config=125;
// count until idle timeout
static uint8_t keyboard_idle_count=0;
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
volatile uint8_t keyboard_leds=0;
/**************************************************************************
*
* Public Functions - these are the API intended for the user
*
**************************************************************************/
// initialize USB
void usb_init(void)
{
HW_CONFIG();
USB_FREEZE(); // enable USB
PLL_CONFIG(); // config PLL
while (!(PLLCSR & (1<<PLOCK))) ; // wait for PLL lock
USB_CONFIG(); // start USB clock
UDCON = 0; // enable attach resistor
usb_configuration = 0;
UDIEN = (1<<EORSTE)|(1<<SOFE);
sei();
}
// return 0 if the USB is not configured, or the configuration
// number selected by the HOST
uint8_t usb_configured(void)
{
return usb_configuration;
}
// perform a single keystroke
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier)
{
int8_t r;
keyboard_modifier_keys = modifier;
keyboard_keys[0] = key;
r = usb_keyboard_send();
if (r) return r;
keyboard_modifier_keys = 0;
keyboard_keys[0] = 0;
return usb_keyboard_send();
}
// send the contents of keyboard_keys and keyboard_modifier_keys
int8_t usb_keyboard_send(void)
{
uint8_t i, intr_state, timeout;
if (!usb_configuration) return -1;
intr_state = SREG;
cli();
UENUM = KEYBOARD_ENDPOINT;
timeout = UDFNUML + 50;
while (1) {
// are we ready to transmit?
if (UEINTX & (1<<RWAL)) break;
SREG = intr_state;
// has the USB gone offline?
if (!usb_configuration) return -1;
// have we waited too long?
if (UDFNUML == timeout) return -1;
// get ready to try checking again
intr_state = SREG;
cli();
UENUM = KEYBOARD_ENDPOINT;
}
UEDATX = keyboard_modifier_keys;
UEDATX = 0;
for (i=0; i<6; i++) {
UEDATX = keyboard_keys[i];
}
UEINTX = 0x3A;
keyboard_idle_count = 0;
SREG = intr_state;
return 0;
}
/**************************************************************************
*
* Private Functions - not intended for general user consumption....
*
**************************************************************************/
// USB Device Interrupt - handle all device-level events
// the transmit buffer flushing is triggered by the start of frame
//
ISR(USB_GEN_vect)
{
uint8_t intbits, i; // used to declare `t` as well, but it wasn't used
// ::Blazak, 2012::
static uint8_t div4=0;
intbits = UDINT;
UDINT = 0;
if (intbits & (1<<EORSTI)) {
UENUM = 0;
UECONX = 1;
UECFG0X = EP_TYPE_CONTROL;
UECFG1X = EP_SIZE(ENDPOINT0_SIZE) | EP_SINGLE_BUFFER;
UEIENX = (1<<RXSTPE);
usb_configuration = 0;
}
if ((intbits & (1<<SOFI)) && usb_configuration) {
if (keyboard_idle_config && (++div4 & 3) == 0) {
UENUM = KEYBOARD_ENDPOINT;
if (UEINTX & (1<<RWAL)) {
keyboard_idle_count++;
if (keyboard_idle_count == keyboard_idle_config) {
keyboard_idle_count = 0;
UEDATX = keyboard_modifier_keys;
UEDATX = 0;
for (i=0; i<6; i++) {
UEDATX = keyboard_keys[i];
}
UEINTX = 0x3A;
}
}
}
}
}
// Misc functions to wait for ready and send/receive packets
static inline void usb_wait_in_ready(void)
{
while (!(UEINTX & (1<<TXINI))) ;
}
static inline void usb_send_in(void)
{
UEINTX = ~(1<<TXINI);
}
static inline void usb_wait_receive_out(void)
{
while (!(UEINTX & (1<<RXOUTI))) ;
}
static inline void usb_ack_out(void)
{
UEINTX = ~(1<<RXOUTI);
}
// USB Endpoint Interrupt - endpoint 0 is handled here. The
// other endpoints are manipulated by the user-callable
// functions, and the start-of-frame interrupt.
//
ISR(USB_COM_vect)
{
uint8_t intbits;
const uint8_t *list;
const uint8_t *cfg;
uint8_t i, n, len, en;
uint8_t bmRequestType;
uint8_t bRequest;
uint16_t wValue;
uint16_t wIndex;
uint16_t wLength;
uint16_t desc_val;
const uint8_t *desc_addr;
uint8_t desc_length;
UENUM = 0;
intbits = UEINTX;
if (intbits & (1<<RXSTPI)) {
bmRequestType = UEDATX;
bRequest = UEDATX;
wValue = UEDATX;
wValue |= (UEDATX << 8);
wIndex = UEDATX;
wIndex |= (UEDATX << 8);
wLength = UEDATX;
wLength |= (UEDATX << 8);
UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
if (bRequest == GET_DESCRIPTOR) {
list = (const uint8_t *)descriptor_list;
for (i=0; ; i++) {
if (i >= NUM_DESC_LIST) {
UECONX = (1<<STALLRQ)|(1<<EPEN); //stall
return;
}
desc_val = pgm_read_word(list);
if (desc_val != wValue) {
list += sizeof(struct descriptor_list_struct);
continue;
}
list += 2;
desc_val = pgm_read_word(list);
if (desc_val != wIndex) {
list += sizeof(struct descriptor_list_struct)-2;
continue;
}
list += 2;
desc_addr = (const uint8_t *)pgm_read_word(list);
list += 2;
desc_length = pgm_read_byte(list);
break;
}
len = (wLength < 256) ? wLength : 255;
if (len > desc_length) len = desc_length;
do {
// wait for host ready for IN packet
do {
i = UEINTX;
} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
if (i & (1<<RXOUTI)) return; // abort
// send IN packet
n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
for (i = n; i; i--) {
UEDATX = pgm_read_byte(desc_addr++);
}
len -= n;
usb_send_in();
} while (len || n == ENDPOINT0_SIZE);
return;
}
if (bRequest == SET_ADDRESS) {
usb_send_in();
usb_wait_in_ready();
UDADDR = wValue | (1<<ADDEN);
return;
}
if (bRequest == SET_CONFIGURATION && bmRequestType == 0) {
usb_configuration = wValue;
usb_send_in();
cfg = endpoint_config_table;
for (i=1; i<5; i++) {
UENUM = i;
en = pgm_read_byte(cfg++);
UECONX = en;
if (en) {
UECFG0X = pgm_read_byte(cfg++);
UECFG1X = pgm_read_byte(cfg++);
}
}
UERST = 0x1E;
UERST = 0;
return;
}
if (bRequest == GET_CONFIGURATION && bmRequestType == 0x80) {
usb_wait_in_ready();
UEDATX = usb_configuration;
usb_send_in();
return;
}
if (bRequest == GET_STATUS) {
usb_wait_in_ready();
i = 0;
#ifdef SUPPORT_ENDPOINT_HALT
if (bmRequestType == 0x82) {
UENUM = wIndex;
if (UECONX & (1<<STALLRQ)) i = 1;
UENUM = 0;
}
#endif
UEDATX = i;
UEDATX = 0;
usb_send_in();
return;
}
#ifdef SUPPORT_ENDPOINT_HALT
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
&& bmRequestType == 0x02 && wValue == 0) {
i = wIndex & 0x7F;
if (i >= 1 && i <= MAX_ENDPOINT) {
usb_send_in();
UENUM = i;
if (bRequest == SET_FEATURE) {
UECONX = (1<<STALLRQ)|(1<<EPEN);
} else {
UECONX = (1<<STALLRQC)|(1<<RSTDT)|(1<<EPEN);
UERST = (1 << i);
UERST = 0;
}
return;
}
}
#endif
if (wIndex == KEYBOARD_INTERFACE) {
if (bmRequestType == 0xA1) {
if (bRequest == HID_GET_REPORT) {
usb_wait_in_ready();
UEDATX = keyboard_modifier_keys;
UEDATX = 0;
for (i=0; i<6; i++) {
UEDATX = keyboard_keys[i];
}
usb_send_in();
return;
}
if (bRequest == HID_GET_IDLE) {
usb_wait_in_ready();
UEDATX = keyboard_idle_config;
usb_send_in();
return;
}
if (bRequest == HID_GET_PROTOCOL) {
usb_wait_in_ready();
UEDATX = keyboard_protocol;
usb_send_in();
return;
}
}
if (bmRequestType == 0x21) {
if (bRequest == HID_SET_REPORT) {
usb_wait_receive_out();
keyboard_leds = UEDATX;
usb_ack_out();
usb_send_in();
return;
}
if (bRequest == HID_SET_IDLE) {
keyboard_idle_config = (wValue >> 8);
keyboard_idle_count = 0;
usb_send_in();
return;
}
if (bRequest == HID_SET_PROTOCOL) {
keyboard_protocol = wValue;
usb_send_in();
return;
}
}
}
}
UECONX = (1<<STALLRQ) | (1<<EPEN); // stall
}

View File

@ -0,0 +1,210 @@
#ifndef usb_serial_h__
#define usb_serial_h__
#include <stdint.h>
void usb_init(void); // initialize everything
uint8_t usb_configured(void); // is the USB port configured
int8_t usb_keyboard_press(uint8_t key, uint8_t modifier);
int8_t usb_keyboard_send(void);
extern uint8_t keyboard_modifier_keys;
extern uint8_t keyboard_keys[6];
extern volatile uint8_t keyboard_leds;
// This file does not include the HID debug functions, so these empty
// macros replace them with nothing, so users can compile code that
// has calls to these functions.
#define usb_debug_putchar(c)
#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
#define KEY_GUI 0x08
#define KEY_LEFT_CTRL 0x01
#define KEY_LEFT_SHIFT 0x02
#define KEY_LEFT_ALT 0x04
#define KEY_LEFT_GUI 0x08
#define KEY_RIGHT_CTRL 0x10
#define KEY_RIGHT_SHIFT 0x20
#define KEY_RIGHT_ALT 0x40
#define KEY_RIGHT_GUI 0x80
#define KEY_A 4
#define KEY_B 5
#define KEY_C 6
#define KEY_D 7
#define KEY_E 8
#define KEY_F 9
#define KEY_G 10
#define KEY_H 11
#define KEY_I 12
#define KEY_J 13
#define KEY_K 14
#define KEY_L 15
#define KEY_M 16
#define KEY_N 17
#define KEY_O 18
#define KEY_P 19
#define KEY_Q 20
#define KEY_R 21
#define KEY_S 22
#define KEY_T 23
#define KEY_U 24
#define KEY_V 25
#define KEY_W 26
#define KEY_X 27
#define KEY_Y 28
#define KEY_Z 29
#define KEY_1 30
#define KEY_2 31
#define KEY_3 32
#define KEY_4 33
#define KEY_5 34
#define KEY_6 35
#define KEY_7 36
#define KEY_8 37
#define KEY_9 38
#define KEY_0 39
#define KEY_ENTER 40
#define KEY_ESC 41
#define KEY_BACKSPACE 42
#define KEY_TAB 43
#define KEY_SPACE 44
#define KEY_MINUS 45
#define KEY_EQUAL 46
#define KEY_LEFT_BRACE 47
#define KEY_RIGHT_BRACE 48
#define KEY_BACKSLASH 49
#define KEY_NUMBER 50
#define KEY_SEMICOLON 51
#define KEY_QUOTE 52
#define KEY_TILDE 53
#define KEY_COMMA 54
#define KEY_PERIOD 55
#define KEY_SLASH 56
#define KEY_CAPS_LOCK 57
#define KEY_F1 58
#define KEY_F2 59
#define KEY_F3 60
#define KEY_F4 61
#define KEY_F5 62
#define KEY_F6 63
#define KEY_F7 64
#define KEY_F8 65
#define KEY_F9 66
#define KEY_F10 67
#define KEY_F11 68
#define KEY_F12 69
#define KEY_PRINTSCREEN 70
#define KEY_SCROLL_LOCK 71
#define KEY_PAUSE 72
#define KEY_INSERT 73
#define KEY_HOME 74
#define KEY_PAGE_UP 75
#define KEY_DELETE 76
#define KEY_END 77
#define KEY_PAGE_DOWN 78
#define KEY_RIGHT 79
#define KEY_LEFT 80
#define KEY_DOWN 81
#define KEY_UP 82
#define KEY_NUM_LOCK 83
#define KEYPAD_SLASH 84
#define KEYPAD_ASTERIX 85
#define KEYPAD_MINUS 86
#define KEYPAD_PLUS 87
#define KEYPAD_ENTER 88
#define KEYPAD_1 89
#define KEYPAD_2 90
#define KEYPAD_3 91
#define KEYPAD_4 92
#define KEYPAD_5 93
#define KEYPAD_6 94
#define KEYPAD_7 95
#define KEYPAD_8 96
#define KEYPAD_9 97
#define KEYPAD_0 98
#define KEYPAD_PERIOD 99
#endif
// Everything below this point is only intended for usb_serial.c
#ifdef USB_SERIAL_PRIVATE_INCLUDE
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#define EP_TYPE_CONTROL 0x00
#define EP_TYPE_BULK_IN 0x81
#define EP_TYPE_BULK_OUT 0x80
#define EP_TYPE_INTERRUPT_IN 0xC1
#define EP_TYPE_INTERRUPT_OUT 0xC0
#define EP_TYPE_ISOCHRONOUS_IN 0x41
#define EP_TYPE_ISOCHRONOUS_OUT 0x40
#define EP_SINGLE_BUFFER 0x02
#define EP_DOUBLE_BUFFER 0x06
#define EP_SIZE(s) ((s) == 64 ? 0x30 : \
((s) == 32 ? 0x20 : \
((s) == 16 ? 0x10 : \
0x00)))
#define MAX_ENDPOINT 4
#define LSB(n) (n & 255)
#define MSB(n) ((n >> 8) & 255)
#if defined(__AVR_AT90USB162__)
#define HW_CONFIG()
#define PLL_CONFIG() (PLLCSR = ((1<<PLLE)|(1<<PLLP0)))
#define USB_CONFIG() (USBCON = (1<<USBE))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#elif defined(__AVR_ATmega32U4__)
#define HW_CONFIG() (UHWCON = 0x01)
#define PLL_CONFIG() (PLLCSR = 0x12)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#elif defined(__AVR_AT90USB646__)
#define HW_CONFIG() (UHWCON = 0x81)
#define PLL_CONFIG() (PLLCSR = 0x1A)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#elif defined(__AVR_AT90USB1286__)
#define HW_CONFIG() (UHWCON = 0x81)
#define PLL_CONFIG() (PLLCSR = 0x16)
#define USB_CONFIG() (USBCON = ((1<<USBE)|(1<<OTGPADE)))
#define USB_FREEZE() (USBCON = ((1<<USBE)|(1<<FRZCLK)))
#endif
// standard control endpoint request types
#define GET_STATUS 0
#define CLEAR_FEATURE 1
#define SET_FEATURE 3
#define SET_ADDRESS 5
#define GET_DESCRIPTOR 6
#define GET_CONFIGURATION 8
#define SET_CONFIGURATION 9
#define GET_INTERFACE 10
#define SET_INTERFACE 11
// HID (human interface device)
#define HID_GET_REPORT 1
#define HID_GET_IDLE 2
#define HID_GET_PROTOCOL 3
#define HID_SET_REPORT 9
#define HID_SET_IDLE 10
#define HID_SET_PROTOCOL 11
// CDC (communication class device)
#define CDC_SET_LINE_CODING 0x20
#define CDC_GET_LINE_CODING 0x21
#define CDC_SET_CONTROL_LINE_STATE 0x22
#endif
#endif

14
src/lib-other/readme.md Normal file
View File

@ -0,0 +1,14 @@
# src/lib-other
Files taken from other projects
## links to original files
* [pjrc] (http://pjrc.com/teensy/)
* [usb_keyboard] (http://pjrc.com/teensy/usb_keyboard.zip)
-------------------------------------------------------------------------------
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>

21
src/lib/data-types.h Normal file
View File

@ -0,0 +1,21 @@
/* ----------------------------------------------------------------------------
* Common data types
* ----------------------------------------------------------------------------
* 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 DATA_TYPES_h
#define DATA_TYPES_h
#include <stddef.h>
#include <stdint.h>
#define bool _Bool
#define true ((bool)1)
#define false ((bool)0)
#endif

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

@ -0,0 +1,83 @@
/* ----------------------------------------------------------------------------
* 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/delay.h> //dbg
#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
return 0; // success
}
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
return 0; // success
}
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
return 0; // success
}

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 // in Hz
#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>

View File

@ -0,0 +1,264 @@
/* ----------------------------------------------------------------------------
* USB Keyboard Key Codes (usage page 0x07)
*
* Taken from [the HID Usage Tables pdf][1], Section 10,
* which can be found on [the HID Page][2] at <http://www.usb.org>
*
* - `Boot Keyboard Req.` indicates that the usage code is one that should be
* supported by the listed types of keyboards (104-key, ...) on boot
*
* - `KEY_` indicates a Keyboard key
* - `KEYPAD_` indicates a Keypad key
* - Multiple names concatenated in CamelCase indicate a single value
* - Multiple names separated by `_`s indicate shifted or alternate values
*
* [1]: http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
* [2]: http://www.usb.org/developers/hidpage
* ----------------------------------------------------------------------------
* 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>
* ------------------------------------------------------------------------- */
// Name ID // PC Mac Unix Boot Keyboard Req.
// --------------------------- ---- -- --- ---- ---------------------
// (Reserved) 0x00 // √ √ √ 84/101/104
#define KEY_ErrorRollOver 0x01 // √ √ √ 84/101/104
#define KEY_POSTFail 0x02 // √ √ √ 84/101/104
#define KEY_ErrorUndefined 0x03 // √ √ √ 84/101/104
#define KEY_a_A 0x04 // √ √ √ 84/101/104
#define KEY_b_B 0x05 // √ √ √ 84/101/104
#define KEY_c_C 0x06 // √ √ √ 84/101/104
#define KEY_d_D 0x07 // √ √ √ 84/101/104
#define KEY_e_E 0x08 // √ √ √ 84/101/104
#define KEY_f_F 0x09 // √ √ √ 84/101/104
#define KEY_g_G 0x0A // √ √ √ 84/101/104
#define KEY_h_H 0x0B // √ √ √ 84/101/104
#define KEY_i_I 0x0C // √ √ √ 84/101/104
#define KEY_j_J 0x0D // √ √ √ 84/101/104
#define KEY_k_K 0x0E // √ √ √ 84/101/104
#define KEY_l_L 0x0F // √ √ √ 84/101/104
#define KEY_m_M 0x10 // √ √ √ 84/101/104
#define KEY_n_N 0x11 // √ √ √ 84/101/104
#define KEY_o_O 0x12 // √ √ √ 84/101/104
#define KEY_p_P 0x13 // √ √ √ 84/101/104
#define KEY_q_Q 0x14 // √ √ √ 84/101/104
#define KEY_r_R 0x15 // √ √ √ 84/101/104
#define KEY_s_S 0x16 // √ √ √ 84/101/104
#define KEY_t_T 0x17 // √ √ √ 84/101/104
#define KEY_u_U 0x18 // √ √ √ 84/101/104
#define KEY_v_V 0x19 // √ √ √ 84/101/104
#define KEY_w_W 0x1A // √ √ √ 84/101/104
#define KEY_x_X 0x1B // √ √ √ 84/101/104
#define KEY_y_Y 0x1C // √ √ √ 84/101/104
#define KEY_z_Z 0x1D // √ √ √ 84/101/104
#define KEY_1_Exclamation 0x1E // √ √ √ 84/101/104
#define KEY_2_At 0x1F // √ √ √ 84/101/104
#define KEY_3_Pound 0x20 // √ √ √ 84/101/104
#define KEY_4_Dollar 0x21 // √ √ √ 84/101/104
#define KEY_5_Percent 0x22 // √ √ √ 84/101/104
#define KEY_6_Caret 0x23 // √ √ √ 84/101/104
#define KEY_7_Ampersand 0x24 // √ √ √ 84/101/104
#define KEY_8_Asterisk 0x25 // √ √ √ 84/101/104
#define KEY_9_LeftParenthesis 0x26 // √ √ √ 84/101/104
#define KEY_0_RightParenthesis 0x27 // √ √ √ 84/101/104
#define KEY_ReturnEnter 0x28 // √ √ √ 84/101/104
#define KEY_Escape 0x29 // √ √ √ 84/101/104
#define KEY_DeleteBackspace 0x2A // √ √ √ 84/101/104
#define KEY_Tab 0x2B // √ √ √ 84/101/104
#define KEY_Spacebar 0x2C // √ √ √ 84/101/104
#define KEY_Dash_Underscore 0x2D // √ √ √ 84/101/104
#define KEY_Equal_Plus 0x2E // √ √ √ 84/101/104
#define KEY_LeftBracket_LeftBrace 0x2F // √ √ √ 84/101/104
#define KEY_RightBracket_RightBrace 0x30 // √ √ √ 84/101/104
#define KEY_Backslash_Pipe 0x31 // √ √ √ 84/101/104
#define KEY_NonUS_Pound_Tilde 0x32 // √ √ √ 84/101/104
#define KEY_Semicolon_Colon 0x33 // √ √ √ 84/101/104
#define KEY_SingleQuote_DoubleQuote 0x34 // √ √ √ 84/101/104
#define KEY_GraveAccent_Tilde 0x35 // √ √ √ 84/101/104
#define KEY_Comma_LessThan 0x36 // √ √ √ 84/101/104
#define KEY_Period_GreaterThan 0x37 // √ √ √ 84/101/104
#define KEY_Slash_Question 0x38 // √ √ √ 84/101/104
#define KEY_CapsLock 0x39 // √ √ √ 84/101/104
#define KEY_F1 0x3A // √ √ √ 84/101/104
#define KEY_F2 0x3B // √ √ √ 84/101/104
#define KEY_F3 0x3C // √ √ √ 84/101/104
#define KEY_F4 0x3D // √ √ √ 84/101/104
#define KEY_F5 0x3E // √ √ √ 84/101/104
#define KEY_F6 0x3F // √ √ √ 84/101/104
#define KEY_F7 0x40 // √ √ √ 84/101/104
#define KEY_F8 0x41 // √ √ √ 84/101/104
#define KEY_F9 0x42 // √ √ √ 84/101/104
#define KEY_F10 0x43 // √ √ √ 84/101/104
#define KEY_F11 0x44 // √ √ √ 101/104
#define KEY_F12 0x45 // √ √ √ 101/104
#define KEY_PrintScreen 0x46 // √ √ √ 101/104
#define KEY_ScrollLock 0x47 // √ √ √ 84/101/104
#define KEY_Pause 0x48 // √ √ √ 101/104
#define KEY_Insert 0x49 // √ √ √ 101/104
#define KEY_Home 0x4A // √ √ √ 101/104
#define KEY_PageUp 0x4B // √ √ √ 101/104
#define KEY_DeleteForward 0x4C // √ √ √ 101/104
#define KEY_End 0x4D // √ √ √ 101/104
#define KEY_PageDown 0x4E // √ √ √ 101/104
#define KEY_RightArrow 0x4F // √ √ √ 101/104
#define KEY_LeftArrow 0x50 // √ √ √ 101/104
#define KEY_DownArrow 0x51 // √ √ √ 101/104
#define KEY_UpArrow 0x52 // √ √ √ 101/104
#define KEYPAD_NumLock_Clear 0x53 // √ √ √ 101/104
#define KEYPAD_Slash 0x54 // √ √ √ 101/104
#define KEYPAD_Asterisk 0x55 // √ √ √ 84/101/104
#define KEYPAD_Minus 0x56 // √ √ √ 84/101/104
#define KEYPAD_Plus 0x57 // √ √ √ 84/101/104
#define KEYPAD_ENTER 0x58 // √ √ √ 101/104
#define KEYPAD_1_End 0x59 // √ √ √ 84/101/104
#define KEYPAD_2_DownArrow 0x5A // √ √ √ 84/101/104
#define KEYPAD_3_PageDown 0x5B // √ √ √ 84/101/104
#define KEYPAD_4_LeftArrow 0x5C // √ √ √ 84/101/104
#define KEYPAD_5 0x5D // √ √ √ 84/101/104
#define KEYPAD_6_RightArrow 0x5E // √ √ √ 84/101/104
#define KEYPAD_7_Home 0x5F // √ √ √ 84/101/104
#define KEYPAD_8_UpArrow 0x60 // √ √ √ 84/101/104
#define KEYPAD_9_PageUp 0x61 // √ √ √ 84/101/104
#define KEYPAD_0_Insert 0x62 // √ √ √ 84/101/104
#define KEYPAD_Period_Delete 0x63 // √ √ √ 84/101/104
#define KEY_NonUS_Backslash_Pipe 0x64 // √ √ √ 84/101/104
#define KEY_Application 0x65 // √ - √ 104
#define KEY_Power 0x66 // - √ √ -
#define KEYPAD_Equal 0x67 // - √ - -
#define KEY_F13 0x68 // - √ - -
#define KEY_F14 0x69 // - √ - -
#define KEY_F15 0x6A // - √ - -
#define KEY_F16 0x6B // - - - -
#define KEY_F17 0x6C // - - - -
#define KEY_F18 0x6D // - - - -
#define KEY_F19 0x6E // - - - -
#define KEY_F20 0x6F // - - - -
#define KEY_F21 0x70 // - - - -
#define KEY_F22 0x71 // - - - -
#define KEY_F23 0x72 // - - - -
#define KEY_F24 0x73 // - - - -
#define KEY_Execute 0x74 // - - √ -
#define KEY_Help 0x75 // - - √ -
#define KEY_Menu 0x76 // - - √ -
#define KEY_Select 0x77 // - - √ -
#define KEY_Stop 0x78 // - - √ -
#define KEY_Again 0x79 // - - √ -
#define KEY_Undo 0x7A // - - √ -
#define KEY_Cut 0x7B // - - √ -
#define KEY_Copy 0x7C // - - √ -
#define KEY_Paste 0x7D // - - √ -
#define KEY_Find 0x7E // - - √ -
#define KEY_Mute 0x7F // - - √ -
#define KEY_VolumeUp 0x80 // - - √ -
#define KEY_VolumeDown 0x81 // - - √ -
#define KEY_LockingCapsLock 0x82 // - - √ -
#define KEY_LockingNumLock 0x83 // - - √ -
#define KEY_LockingScrollLock 0x84 // - - √ -
#define KEYPAD_Comma 0x85 // - - - -
#define KEYPAD_EqualSign 0x86 // - - - -
#define KEY_International1 0x87 // - - - -
#define KEY_International2 0x88 // - - - -
#define KEY_International3 0x89 // - - - -
#define KEY_International4 0x8A // - - - -
#define KEY_International5 0x8B // - - - -
#define KEY_International6 0x8C // - - - -
#define KEY_International7 0x8D // - - - -
#define KEY_International8 0x8E // - - - -
#define KEY_International9 0x8F // - - - -
#define KEY_LANG1 0x90 // - - - -
#define KEY_LANG2 0x91 // - - - -
#define KEY_LANG3 0x92 // - - - -
#define KEY_LANG4 0x93 // - - - -
#define KEY_LANG5 0x94 // - - - -
#define KEY_LANG6 0x95 // - - - -
#define KEY_LANG7 0x96 // - - - -
#define KEY_LANG8 0x97 // - - - -
#define KEY_LANG9 0x98 // - - - -
#define KEY_AlternateErase 0x99 // - - - -
#define KEY_SysReq_Attention 0x9A // - - - -
#define KEY_Cancel 0x9B // - - - -
#define KEY_Clear 0x9C // - - - -
#define KEY_Prior 0x9D // - - - -
#define KEY_Return 0x9E // - - - -
#define KEY_Separator 0x9F // - - - -
#define KEY_Out 0xA0 // - - - -
#define KEY_Oper 0xA1 // - - - -
#define KEY_Clear_Again 0xA2 // - - - -
#define KEY_CrSel_Props 0xA3 // - - - -
#define KEY_ExSel 0xA4 // - - - -
// (Reserved) 0xA5..0xAF // - - - -
#define KEYPAD_00 0xB0 // - - - -
#define KEYPAD_000 0xB1 // - - - -
#define KEY_ThousandsSeparator 0xB2 // - - - -
#define KEY_DecimalSeparator 0xB3 // - - - -
#define KEY_CurrencyUnit 0xB4 // - - - -
#define KEY_CurrencySubunit 0xB5 // - - - -
#define KEYPAD_LeftParenthesis 0xB6 // - - - -
#define KEYPAD_RightParenthesis 0xB7 // - - - -
#define KEYPAD_LeftBrace 0xB8 // - - - -
#define KEYPAD_RightBrace 0xB9 // - - - -
#define KEYPAD_Tab 0xBA // - - - -
#define KEYPAD_Backspace 0xBB // - - - -
#define KEYPAD_A 0xBC // - - - -
#define KEYPAD_B 0xBD // - - - -
#define KEYPAD_C 0xBE // - - - -
#define KEYPAD_D 0xBF // - - - -
#define KEYPAD_E 0xC0 // - - - -
#define KEYPAD_F 0xC1 // - - - -
#define KEYPAD_XOR 0xC2 // - - - -
#define KEYPAD_Caret 0xC3 // - - - -
#define KEYPAD_Percent 0xC4 // - - - -
#define KEYPAD_LessThan 0xC5 // - - - -
#define KEYPAD_GreaterThan 0xC6 // - - - -
#define KEYPAD_Ampersand 0xC7 // - - - -
#define KEYPAD_AmpersandAmpersand 0xC8 // - - - -
#define KEYPAD_Pipe 0xC9 // - - - -
#define KEYPAD_PipePipe 0xCA // - - - -
#define KEYPAD_Colon 0xCB // - - - -
#define KEYPAD_Pound 0xCC // - - - -
#define KEYPAD_Space 0xCD // - - - -
#define KEYPAD_At 0xCE // - - - -
#define KEYPAD_Exclamation 0xCF // - - - -
#define KEYPAD_MemoryStore 0xD0 // - - - -
#define KEYPAD_MemoryRecall 0xD1 // - - - -
#define KEYPAD_MemoryClear 0xD2 // - - - -
#define KEYPAD_MemoryAdd 0xD3 // - - - -
#define KEYPAD_MemorySubtract 0xD4 // - - - -
#define KEYPAD_MemoryMultiply 0xD5 // - - - -
#define KEYPAD_MemoryDivide 0xD6 // - - - -
#define KEYPAD_PlusMinux 0xD7 // - - - -
#define KEYPAD_Clear 0xD8 // - - - -
#define KEYPAD_ClearEntry 0xD9 // - - - -
#define KEYPAD_Binary 0xDA // - - - -
#define KEYPAD_Octal 0xDB // - - - -
#define KEYPAD_Decimal 0xDC // - - - -
#define KEYPAD_Hexadecimal 0xDD // - - - -
// (Reserved) 0xDE..0xDF // - - - -
#define KEY_LeftControl 0xE0 // √ √ √ 84/101/104
#define KEY_LeftShift 0xE1 // √ √ √ 84/101/104
#define KEY_LeftAlt 0xE2 // √ √ √ 84/101/104
#define KEY_LeftGUI 0xE3 // √ √ √ 104
#define KEY_RightControl 0xE4 // √ √ √ 101/104
#define KEY_RightShift 0xE5 // √ √ √ 84/101/104
#define KEY_RightAlt 0xE6 // √ √ √ 101/104
#define KEY_RightGUI 0xE7 // √ √ √ 104
// (Reserved) 0xE8..0xFFFF // - - - -

View File

@ -0,0 +1,106 @@
/* ----------------------------------------------------------------------------
* USB LED Codes (usage page 0x08)
*
* Taken from [the HID Usage Tables pdf][1], Section 11,
* which can be found on [the HID Page][2] at <http://www.usb.org>
*
* - applicable Usage Types (from Section 3.4)
* - OOC : On/Off Control
* - Sel : Selector
* - DV : Dynamic Value
* - US : Usage Switch
* - UM : Usage Modifier
*
* [1]: http://www.usb.org/developers/devclass_docs/Hut1_12v2.pdf
* [2]: http://www.usb.org/developers/hidpage
* ----------------------------------------------------------------------------
* 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>
* ------------------------------------------------------------------------- */
// Name ID Usage Type Section of HID Tables
// --------------------------- ---- ---------- ----------------------
// (Undefined) 0x00 // - -
#define LED_NumLock 0x01 // OOC 11.1
#define LED_CapsLock 0x02 // OOC 11.1
#define LED_ScrollLock 0x03 // OOC 11.1
#define LED_Compose 0x04 // OOC 11.1
#define LED_Kana 0x05 // OOC 11.1
#define LED_Power 0x06 // OOC 11.6
#define LED_Shift 0x07 // OOC 11.1
#define LED_DoNotDisturb 0x08 // OOC 11.2
#define LED_Mute 0x09 // OOC 11.3
#define LED_ToneEnable 0x0A // OOC 11.3
#define LED_HighCutFilter 0x0B // OOC 11.3
#define LED_LowCutFilter 0x0C // OOC 11.3
#define LED_EqualizerEnable 0x0D // OOC 11.3
#define LED_SoundFieldOn 0x0E // OOC 11.3
#define LED_SurroundOn 0x0F // OOC 11.3
#define LED_Repeat 0x10 // OOC 11.3
#define LED_Stereo 0x11 // OOC 11.3
#define LED_SamplingRateDetect 0x12 // OOC 11.3
#define LED_Spinning 0x13 // OOC 11.4
#define LED_CAV 0x14 // OOC 11.3
#define LED_CLV 0x15 // OOC 11.3
#define LED_RecordingFormatDetect 0x16 // OOC 11.4
#define LED_OffHook 0x17 // OOC 11.2
#define LED_Ring 0x18 // OOC 11.2
#define LED_MessageWaiting 0x19 // OOC 11.2
#define LED_DataMode 0x1A // OOC 11.2
#define LED_BatteryOperation 0x1B // OOC 11.6
#define LED_BatteryOK 0x1C // OOC 11.6
#define LED_BatteryLow 0x1D // OOC 11.6
#define LED_Speaker 0x1E // OOC 11.2
#define LED_HeadSet 0x1F // OOC 11.2
#define LED_Hold 0x20 // OOC 11.2
#define LED_Microphone 0x21 // OOC 11.2
#define LED_Coverage 0x22 // OOC 11.2
#define LED_NightMode 0x23 // OOC 11.2
#define LED_SendCalls 0x24 // OOC 11.2
#define LED_CallPickup 0x25 // OOC 11.2
#define LED_Conference 0x26 // OOC 11.2
#define LED_Standby 0x27 // OOC 11.6
#define LED_CameraOn 0x28 // OOC 11.3
#define LED_CameraOff 0x29 // OOC 11.3
#define LED_OnLine 0x2A // OOC 11.6
#define LED_OffLine 0x2B // OOC 11.6
#define LED_Busy 0x2C // OOC 11.6
#define LED_Ready 0x2D // OOC 11.6
#define LED_PaperOut 0x2E // OOC 11.5
#define LED_PaperJam 0x2F // OOC 11.5
#define LED_Remote 0x30 // OOC 11.6
#define LED_Forward 0x31 // OOC 11.4
#define LED_Reverse 0x32 // OOC 11.4
#define LED_Stop 0x33 // OOC 11.4
#define LED_Rewind 0x34 // OOC 11.4
#define LED_FastForward 0x35 // OOC 11.4
#define LED_Play 0x36 // OOC 11.4
#define LED_Pause 0x37 // OOC 11.4
#define LED_Record 0x38 // OOC 11.4
#define LED_Error 0x39 // OOC 11.6
#define LED_UsageSelectedIndicator 0x3A // US 11.6
#define LED_UsageInUseIndicator 0x3B // US 11.6
#define LED_UsageMultiModeIndicator 0x3C // UM 11.6
#define LED_IndicatorOn 0x3D // Sel 11.6
#define LED_IndicatorFlash 0x3E // Sel 11.6
#define LED_IndicatorSlowBlink 0x3F // Sel 11.6
#define LED_IndicatorFastBlink 0x40 // Sel 11.6
#define LED_IndicatorOff 0x41 // Sel 11.6
#define LED_FlashOnTime 0x42 // DV 11.6
#define LED_SlowBlinkOnTime 0x43 // DV 11.6
#define LED_SlowBlinkOffTime 0x44 // DV 11.6
#define LED_FastBlinkOnTime 0x45 // DV 11.6
#define LED_FastBlinkOffTime 0x46 // DV 11.6
#define LED_UsageIndicatorColor 0x47 // UM 11.6
#define LED_IndicatorRed 0x48 // Sel 11.6
#define LED_IndicatorGreen 0x49 // Sel 11.6
#define LED_IndicatorAmber 0x4A // Sel 11.6
#define LED_GenericIndicator 0x4B // OOC 11.6
#define LED_SystemSuspend 0x4C // OOC 11.6
#define LED_ExternalPowerConnected 0x4D // OOC 11.6
// (Reserved) 0x4E..0xFFFF // - -

101
src/main.c Normal file
View File

@ -0,0 +1,101 @@
// 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"
// note:
// - see your keyswitch specification for the necessary value. for cherry mx
// switches, bounce time should be <= 5ms. it looks like most switches are
// speced between 5 and 8ms.
// - if timing is important, balance this value with the main() loop run time
// (~5ms, last i checked, nearly all of it in the i2c update() function)
#define DEBOUNCE_TIME 5 // in ms
int main(void) {
kb_init(); // does controller initialization too
KB_LED1_ON;
KB_LED2_ON;
KB_LED3_ON;
usb_init();
while (!usb_configured());
_delay_ms(1000); // make sure the OS has had time to load drivers, etc.
KB_LED1_OFF;
KB_LED2_OFF;
KB_LED3_OFF;
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 if
// necessary
// - everything else is the key function's responsibility; see the
// keyboard layout file ("keyboard/ergodox/layout.c") for which key
// is assigned which function (per layer), and "key-functions.c" for
// their definitions
for (uint8_t row=0; row<KB_ROWS; row++) {
for (uint8_t col=0; col<KB_COLUMNS; col++) {
bool is_pressed = (*kb_is_pressed)[row][col];
bool was_pressed = (*kb_was_pressed)[row][col];
if (is_pressed != was_pressed) {
if (is_pressed) {
kbfun_funptr_t press_function =
kb_layout_press[current_layer][row][col];
if (press_function) {
(*press_function)(
&kb_layout[current_layer][row][col],
&current_layer, &row, &col );
}
} else {
kbfun_funptr_t release_function =
kb_layout_release[current_layer][row][col];
if (release_function) {
(*release_function)(
&kb_layout[current_layer][row][col],
&current_layer, &row, &col );
}
}
usb_keyboard_send();
_delay_ms(DEBOUNCE_TIME);
}
}
}
// 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;
}

38
src/makefile Normal file
View File

@ -0,0 +1,38 @@
# -----------------------------------------------------------------------------
# This is mostly a stub at the moment, but I'm keeping it separate so I can
# mess with it later without changing the original
# -----------------------------------------------------------------------------
# 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>
# -----------------------------------------------------------------------------
TARGET = firmware
SRC = $(shell find -maxdepth 1 -name '*.c') \
$(shell find ./keyboard -name '*.c') \
$(shell find ./lib -name '*.c') \
'./lib-other/pjrc/usb_keyboard/usb_keyboard.c'
EXTRAINCDIRS = .
TEENSY_MAKE = $(MAKE) -f 'lib-other/pjrc/usb_keyboard/Makefile' \
TARGET='$(TARGET)' \
SRC='$(SRC)' \
EXTRAINCDIRS='$(EXTRAINCDIRS)'
.PHONY: all clean debug
all:
$(TEENSY_MAKE) all
clean:
$(TEENSY_MAKE) clean
git clean -X
debug:
$(TEENSY_MAKE) debug

38
src/test/makefile Normal file
View File

@ -0,0 +1,38 @@
# -----------------------------------------------------------------------------
# This is mostly a stub at the moment, but I'm keeping it separate so I can
# mess with it later without changing the original
# -----------------------------------------------------------------------------
# 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>
# -----------------------------------------------------------------------------
TARGET = test
EXTRAINCDIRS = ..
TEENSY_MAKE = $(MAKE) -f '../lib-other/pjrc/blinky/Makefile' \
TARGET='$(TARGET)' \
EXTRAINCDIRS='$(EXTRAINCDIRS)'
.PHONY: test_pwm test_twi test_twi_2
test_pwm:
$(TEENSY_MAKE) all \
SRC='test_pwm.c'
test_twi:
$(TEENSY_MAKE) all \
SRC='test_twi.c'
test_twi_2:
$(TEENSY_MAKE) all \
SRC='test_twi_2.c'
.PHONY: clean
clean:
$(TEENSY_MAKE) clean \
SRC='$(shell find -name '*.c')'

12
src/test/readme.md Normal file
View File

@ -0,0 +1,12 @@
# src/test
Files used for testing (at some point)
* I'm keeping these around for reference; they probably won't be maintained,
and are quite likely to become broken at some point in the future.
-------------------------------------------------------------------------------
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>

85
src/test/test_pwm.c Normal file
View File

@ -0,0 +1,85 @@
/* ----------------------------------------------------------------------------
* Test the Teensy 2.0 PWM code (see `#include`s)
* ----------------------------------------------------------------------------
* 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 <avr/io.h>
#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
for (uint8_t i=0; i<3; i++) {
KB_LED1_SET(0x10);
KB_LED2_SET(0x20);
KB_LED3_SET(0xFF);
_delay_ms(500);
KB_LED1_SET(0x20);
KB_LED2_SET(0xFF);
KB_LED3_SET(0x10);
_delay_ms(500);
KB_LED1_SET(0xFF);
KB_LED2_SET(0x10);
KB_LED3_SET(0x20);
_delay_ms(500);
}
for (uint8_t i=0; i<2; i++) {
KB_LED1_OFF;
KB_LED2_OFF;
KB_LED3_OFF;
_delay_ms(500);
KB_LED1_ON;
KB_LED2_ON;
KB_LED3_ON;
_delay_ms(500);
}
bool counting_up = true;
for (uint8_t i=0;;) {
(counting_up) ? i++ : i--;
if (i == 0xFF)
counting_up = false;
else if (i == 0)
counting_up = true;
KB_LED1_SET(i/2);
KB_LED2_SET(i/2);
KB_LED3_SET(i/2);
_delay_ms(10);
}
}

105
src/test/test_twi.c Normal file
View File

@ -0,0 +1,105 @@
/* ----------------------------------------------------------------------------
* Test for ACK on address 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>
// processor frequency (from <http://www.pjrc.com/teensy/prescaler.html>)
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
#define CPU_8MHz 0x01
#define CPU_4MHz 0x02
#define CPU_2MHz 0x03
#define CPU_1MHz 0x04
#define CPU_500kHz 0x05
#define CPU_250kHz 0x06
#define CPU_125kHz 0x07
#define CPU_62kHz 0x08
// ----------------------------------------------------------------------------
// 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
// ----------------------------------------------------------------------------
void twi_init(void) {
TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
TWBR = ((F_CPU / 100000) - 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
}
// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------
void main(void) {
CPU_PRESCALE(CPU_16MHz);
uint8_t ret;
twi_init();
for (uint8_t i=0;; i+=2) { // try all even (write) addresses
twi_start();
ret = twi_send(i); // i = address
twi_stop();
if (ret == 0x18) // SLA+W sent; ACK received
break;
if (i == 0xFE) // all done
break;
}
// blink the return value
// --- initial blink (get ready)
blink_led(700, 200);
// --- 1st hex number
for (uint8_t i=0; i<(ret/0x10); i++) {
blink_led(200, 100);
}
_delay_ms(400);
// --- 2nd hex number
for (uint8_t i=0; i<(ret%0x10); i++) {
blink_led(200, 100);
}
}

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;
}