#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "usb_keyboard.h"
#define bool uint8_t
#define true 1
#define false 0
#define _PINB (uint8_t *const)&PINB
#define _PORTC (uint8_t *const)&PORTC
#define _PORTD (uint8_t *const)&PORTD
#define _PORTF (uint8_t *const)&PORTF
#define NULL 0
#define NA 0
#define KEY_MACRO 0
#define KEY_FN 0
#define FN_KEY1_ID 11*6+0
#define FN_KEY2_ID 2*6+0
#define MACRO_KEY_ID 0*6+0
const uint8_t is_modifier[84] = {
1, 1, 1, 0, 0, 0, // COL 0
NA, NA, 0, 0, 0, 0, // COL 1
1, 0, 0, 0, 0, 0, // COL 2
1, 0, 0, 0, 0, 0, // COL 3
0, 0, 0, 0, 0, 0, // COL 4
0, 0, 0, 0, 0, 0, // COL 5
0, 0, 0, 0, 0, 0, // COL 6
0, 0, 0, 0, 0, 0, // COL 7
0, 0, 0, 0, 0, 0, // COL 8
0, 0, 0, 0, 0, 0, // COL 9
1, 0, 0, 0, 0, 0, // COL 10
1, 0, 0, 0, 0, 0, // COL 11
NA, NA, 0, 0, 0, 0, // COL 12
1, 1, 0, 0, 0, 0 // COL 13
};
const uint8_t layer1[84] = {
//ROW 0 ROW 1 ROW 2 ROW 3 ROW 4 ROW5
KEY_MACRO, KEY_LEFT_SHIFT, KEY_LEFT_CTRL, KEY_TAB, KEY_ESC, NULL, // COL 0
NA, NA, KEY_A, KEY_Q, KEY_TILDE, KEY_F1, // COL 1
KEY_FN, KEY_Z, KEY_S, KEY_W, KEY_1, KEY_F2, // COL 2
KEY_LEFT_ALT, KEY_X, KEY_D, KEY_E, KEY_2, KEY_F3, // COL 3
NA, KEY_C, KEY_F, KEY_R, KEY_3, KEY_F4, // COL 4
NA, KEY_V, KEY_G, KEY_T, KEY_4, KEY_F5, // COL 5
KEY_SLASH, KEY_BACKSLASH, KEY_LEFT_BRACE, KEY_RIGHT_BRACE, KEY_5, KEY_F6, // COL 6
KEY_SPACE, KEY_B, KEY_QUOTE, KEY_MINUS, KEY_EQUAL, KEY_F7, // COL 7
NA, KEY_N, KEY_H, KEY_Y, KEY_6, KEY_F8, // COL 8
NA, KEY_M, KEY_J, KEY_U, KEY_7, KEY_F9, // COL 9
KEY_RIGHT_ALT, KEY_COMMA, KEY_K, KEY_I, KEY_8, KEY_F10, // COL 10
KEY_FN, KEY_PERIOD, KEY_L, KEY_O, KEY_9, KEY_F11, // COL 11
NA, NA, KEY_SEMICOLON, KEY_P, KEY_0, KEY_F12, // COL 12
KEY_RIGHT_CTRL, KEY_RIGHT_SHIFT, KEY_ENTER, KEY_BACKSPACE, KEY_DELETE, NULL // COL 13
};
const uint8_t layer2[84] = {
//ROW 0 ROW 1 ROW 2 ROW 3 ROW 4 ROW5
NULL, KEY_LEFT_SHIFT, KEY_LEFT_CTRL, KEY_TAB, KEY_ESC, NULL, // COL 0
NA, NA, KEY_DELETE, KEY_INSERT, NULL, NULL, // COL 1
KEY_FN, NULL, KEY_LEFT, KEY_HOME, KEY_PRINTSCREEN, NULL, // COL 2
KEY_LEFT_ALT, NULL, KEY_DOWN, KEY_UP, KEY_SCROLL_LOCK, NULL, // COL 3
NULL, NULL, KEY_RIGHT, KEY_END, KEY_PAUSE, NULL, // COL 4
NULL, NULL, KEY_PAGE_DOWN, KEY_PAGE_UP, NULL, NULL, // COL 5
NULL, NULL, NULL, NULL, NULL, NULL, // COL 6
KEY_SPACE, NULL, NULL, NULL, NULL, NULL, // COL 7
NULL, KEYPAD_0, KEYPAD_PERIOD, KEY_NUM_LOCK, NULL, NULL, // COL 8
NULL, KEYPAD_1, KEYPAD_4, KEYPAD_7, KEYPAD_PLUS, NULL, // COL 9
KEY_RIGHT_ALT, KEYPAD_2, KEYPAD_5, KEYPAD_8, KEYPAD_MINUS, NULL, // COL 10
KEY_FN, KEYPAD_3, KEYPAD_6, KEYPAD_9, KEYPAD_ASTERIX, NULL, // COL 11
NA, NA, NULL, NULL, KEYPAD_SLASH, NULL, // COL 12
KEY_RIGHT_CTRL, KEY_RIGHT_SHIFT, KEY_ENTER, KEY_BACKSPACE, KEY_DELETE, NULL // COL 13
};
const uint8_t *layout = layer1;
uint8_t *const row_port[6] = { _PINB, _PINB, _PINB, _PINB, _PINB, _PINB};
const uint8_t row_bit[6] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20};
uint8_t *const col_port[14] = {_PORTD, _PORTD, _PORTD, _PORTD, _PORTD, _PORTC, _PORTD, _PORTD, _PORTF, _PORTF, _PORTF, _PORTF, _PORTF, _PORTF};
const uint8_t col_bit[14] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x40, 0x40, 0x80, 0x01, 0x02, 0x10, 0x20, 0x40, 0x80};
bool pressed[84];
uint8_t queue[7] = {0,0,0,0,0,0,0};
uint8_t mod_keys = 0;
void init(void);
void send(void);
void poll(void);
void key_press(uint8_t key_id);
void key_release(uint8_t key_id);
int main(void) {
init();
for(;;) poll();
}
void send(void) {
uint8_t i;
if(pressed[FN_KEY1_ID] || pressed[FN_KEY2_ID])
layout = layer2;
else
layout = layer1;
for(i=0; i<6; i++)
keyboard_keys[i] = layout[queue[i]];
keyboard_modifier_keys = mod_keys;
usb_keyboard_send();
}
void poll() {
uint8_t row, col, key_id;
_delay_ms(5);
for(col=0; col<14; col++) {
*col_port[col] &= ~col_bit[col];
_delay_us(1);
for(row=0; row<6; row++) {
key_id = col*6+row;
if(!(*row_port[row] & row_bit[row])) {
if(!pressed[key_id])
key_press(key_id);
}
else if(pressed[key_id])
key_release(key_id);
}
*col_port[col] |= col_bit[col];
}
}
void key_press(uint8_t key_id) {
uint8_t i;
pressed[key_id] = true;
if(is_modifier[key_id])
mod_keys |= layer1[key_id];
else {
for(i=5; i>0; i--) queue[i] = queue[i-1];
queue[0] = key_id;
}
send();
}
void key_release(uint8_t key_id) {
uint8_t i;
pressed[key_id] = false;
if(is_modifier[key_id])
mod_keys &= ~layout[key_id];
else {
for(i=0; i<6; i++) if(queue[i]==key_id) break;
for(; i<6; i++) queue[i] = queue[i+1];
}
send();
}
void init(void) {
uint8_t i;
CLKPR = 0x80; CLKPR = 0;
usb_init();
while(!usb_configured());
_delay_ms(1000);
// PORTB is set as input with pull-up resistors
// PORTC,D,F are set to high output
DDRB = 0x00; DDRC = 0xFF; DDRD = 0xFF; DDRF = 0xFF;
PORTB = 0xFF; PORTC = 0xFF; PORTD = 0xFF; PORTF = 0xFF;
for(i=0; i<84; i++) pressed[i] = false;
}
Show Image(http://i52.tinypic.com/2zs1k4o.jpg)
Looking at both that and your PCB, are you not using the MX keys with fixing pins or did you do something else sneaky I am missing?
No, I thought they would be more work than help. Omewhere around 50% extra holes to drill... There are plenty already. Also for them to do any good in switch alignment I guess they would have to be pretty tight and absolutely straight. As it is made now it is possible to give the switch a slight twist after soldering it. If it is a little more skewed it can be resoldered at a slightly different angle.
Actually I put the diodes in myself.
I can understand your justification and in hind sight it was probably a good decision (having already purchased my keys with mounting pins I am stuck with them).
Put the diodes in as in opened up each individual key and inserted it in the pre-cut holes? :o
You know, you could just cut the mounting pins. They're plastic after all ;)I don't like the idea of damaging my beautiful switches though :p
Yes =) and yes, it gets old pretty quick.. It is not impossibly tedious though. I bought mine from mouser and they don't seem to stock the ones with diodes.I also got mine from mouser so had the same issue, I was going to mount all the diodes above the keys but noticed the drilled holes in the bottom and how they seemed to line up with the drilling patterns, but I hadn't found any documentation of anyone adding their own diodes.
It was a bit harder to get a printout of the larger pcb on a suitable paper. I think there were some paper left in the toner which somehow let the etching agent seep through and affect the copper underneath (or I just left the laminate in for too long). Better paper probably helps, I read somewhere about using those waxed papers used to wrap sandwiches and stuff.
Any tips for taking apart the MX switches? Just took one of mine apart now using a pair of scissors to shimmy one set of the clips at a time, worked fine but seemed a bit delicate
When I was making custom boards for headphone amps I used the laser-printable plastic transparency sheets. Worked nicely, could get quite fine lines. Of course, photo-etching removes the element of risk of the ironing process.
Double shots are in =D I was pretty sure I would be getting the inverse of that color scheme though... That doesn't really concern me a lot but some of the number labels seem to be of a larger font. That I will probably whine to SP about.Show Image(http://i53.tinypic.com/21153zr.jpg)
Hundred and one blank keysShow Image(http://i55.tinypic.com/zvww3r.jpg)
Forty nine and two relegendable keysShow Image(http://i51.tinypic.com/2550uaq.jpg)
Another day I will take pictures in better lighting...Show Image(http://i52.tinypic.com/34y5z52.jpg)
The bizarre amount of wider keys are due to the fact they are not cheaper bought in smaller quantities. So I thought I might be able to pass some of them along to fellow geekhackers for a no profit price. Single width keys are usually bought in larger quantities and therefor possible to order more or less at will. Apparently SP are unable to do double shots keys wider than 2 units in the DSA family. All keys are of that profile for easy swapping.
Wait a second!
How comes you've got already what we are all supposed to wait for 6 weeks!!!
Do you've got a time machine?
Of course, doesn't everyone?? =D
Nah, I just beat you to it =P Paid a lot more per key probably though...
Hey Prinz, mind posting or PM'ing your ExpressSCH/ExpressPCB files? I'm curious as to how you laid out the circuit. Growing up, my dad was an electrical engineer, so I've always had a fascination for circuits.
Oh. Not THAT thick then. Filcos are .9. Signature Plastic DCS a bit under .8. Cherry Doubleshots 1.5mm. Lol.
Awesome work PV! I can't wait to finish my own custom keyboard project.
Damn, that is really awesome and inspiring. Any plans yet for the housing?
Thanks =) I will be using a "recycled" keyboard casing.
I found a bug in my firmware too, If the key with keyid 0 does not contain a 0 in the layout vectors the keyboard won't work. I did a quick fix for that, I will leave the old code in the article for now though. Future code will be added in my new keyboard designing article (http://geekhack.org/showwiki.php?title=Design+your+own+Teensy+keyboard+in+KiCAD+how-to+guide).
uint8_t queue[7] = {255,255,255,255,255,255,255};
void send(void) {
uint8_t i;
for(i=0; i<6; i++)
keyboard_keys[i] = queue[i]<255? layout[queue[i]]: 0;
keyboard_modifier_keys = mod_keys;
usb_keyboard_send();
}