added support for a new keyboard model

This commit is contained in:
Ronald Schaten 2008-11-12 21:45:43 +00:00
parent dbc411f969
commit 5d7ab00387
9 changed files with 10770 additions and 0 deletions

View File

@ -23,6 +23,7 @@ CC = avr-gcc
# Options: # Options:
DEFINES = -DMODELIBMMODELM DEFINES = -DMODELIBMMODELM
#DEFINES = -DMODELMAYHEM
#DEFINES = -DMODELSUNTYPE5 #DEFINES = -DMODELSUNTYPE5
CFLAGS = -Wall -Os -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) $(DEFINES) CFLAGS = -Wall -Os -I. -mmcu=$(DEVICE) -DF_CPU=$(F_CPU) $(DEFINES)

View File

@ -147,6 +147,21 @@ static inline void bootLoaderInit(void) {
PORTC = 0xff; PORTC = 0xff;
} }
#endif #endif
#ifdef MODELMAYHEM
static inline void bootLoaderInit(void) {
// switch on leds
DDRD |= (1 << PIND1) | (1 << PIND3) | (1 << PIND6) | (1 << PIND7);
PORTD &= ~((1 << PIND1) | (1 << PIND3) | (1 << PIND6) | (1 << PIND7));
// choose matrix position for hotkey. we use KEY_D, so we set row 4
// and later look for column 5
DDRA = (1 << DDA4);
PORTA = ~(1 << PINA4);
DDRB &= ~(1 << PB5);
PORTB |= (1 << PB5);
DDRC = 0x00;
PORTC = 0xff;
}
#endif
#ifdef MODELSUNTYPE5 #ifdef MODELSUNTYPE5
static inline void bootLoaderInit(void) { static inline void bootLoaderInit(void) {
// configure ports // configure ports
@ -189,6 +204,12 @@ static inline void bootLoaderExit(void) {
PORTD |= (1 << PIND4) | (1 << PIND5) | (1 << PIND6); PORTD |= (1 << PIND4) | (1 << PIND5) | (1 << PIND6);
} }
#endif #endif
#ifdef MODELMAYHEM
static inline void bootLoaderExit(void) {
// switch off leds
PORTD |= (1 << PIND1) | (1 << PIND3) | (1 << PIND6) | (1 << PIND7);
}
#endif
#ifdef MODELSUNTYPE5 #ifdef MODELSUNTYPE5
static inline void bootLoaderExit(void) { static inline void bootLoaderExit(void) {
// switch off leds // switch off leds
@ -230,6 +251,34 @@ static inline uint8_t bootLoaderCondition() {
} }
} }
#endif #endif
#ifdef MODELMAYHEM
static inline uint8_t bootLoaderCondition() {
// look for pin 5
if (!(PINB & (1 << PINB5))) {
// boot loader active, fade leds
ledcounter++;
if (ledcounter < ledbrightness) {
// switch on leds
PORTD &= ~((1 << PIND1) | (1 << PIND3) | (1 << PIND6) | (1 << PIND7));
} else {
// switch off leds
PORTD |= (1 << PIND1) | (1 << PIND3) | (1 << PIND6) | (1 << PIND7);
}
if (ledcounter == 255) {
ledcounter = 0;
ledbrightness += leddirection;
if (ledbrightness == 255) {
leddirection = -leddirection;
ledbrightness += leddirection;
}
}
return 1;
} else {
// no boot loader
return 0;
}
}
#endif
#ifdef MODELSUNTYPE5 #ifdef MODELSUNTYPE5
static inline uint8_t bootLoaderCondition() { static inline uint8_t bootLoaderCondition() {
// look for pin 12, KEY_D // look for pin 12, KEY_D

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
EESchema-DOCLIB Version 2.0 12/11/2008-07:33:03
#
$CMP C
D Condensateur non polarise
$ENDCMP
#
$CMP CONN_2
D Symbole general de connecteur
K CONN
$ENDCMP
#
$CMP CP
D Condensateur polarise
$ENDCMP
#
$CMP R
D Resistance
K R DEV
$ENDCMP
#
$CMP USB_CONN
D USB CONNECTOR
K USB
$ENDCMP
#
$CMP ZENER
D Diode zener
K DEV DIODE
$ENDCMP
#
#End Doc Library

View File

@ -0,0 +1,354 @@
EESchema-LIBRARY Version 12/11/2008-07:33:03
#
#
# C
#
DEF C C 0 10 N Y 1 F N
F0 "C" 50 100 50 H V L C
F1 "C" 50 -100 50 H V L C
$FPLIST
SM*
C?
C1-1
$ENDFPLIST
DRAW
P 2 0 1 8 -100 30 100 30 N
P 2 0 1 8 -100 -30 100 -30 N
X ~ 1 0 200 170 D 40 40 1 1 P
X ~ 2 0 -200 170 U 40 40 1 1 P
ENDDRAW
ENDDEF
#
# CONN_2
#
DEF CONN_2 P 0 40 Y N 1 F N
F0 "P" -50 0 40 V V C C
F1 "CONN_2" 50 0 40 V V C C
DRAW
S -100 150 100 -150 0 1 0 N
X PM 2 -350 -100 250 R 60 60 1 1 P I
X P1 1 -350 100 250 R 60 60 1 1 P I
ENDDRAW
ENDDEF
#
# CP
#
DEF CP C 0 10 N N 1 F N
F0 "C" 50 100 50 H V L C
F1 "CP" 50 -100 50 H V L C
ALIAS CAPAPOL
$FPLIST
CP*
SM*
$ENDFPLIST
DRAW
P 4 0 1 0 -50 50 -50 -20 50 -20 50 50 F
P 4 0 1 8 -100 50 -100 -50 100 -50 100 50 N
X ~ 1 0 200 150 D 40 40 1 1 P
X ~ 2 0 -200 150 U 40 40 1 1 P
ENDDRAW
ENDDEF
#
# CRYSTAL
#
DEF CRYSTAL X 0 40 N N 0 F N
F0 "X" 0 150 60 H V C C
F1 "CRYSTAL" 0 -150 60 H V C C
DRAW
P 5 0 1 12 -50 50 50 50 50 -50 -50 -50 -50 50 f
P 2 0 1 16 -100 100 -100 -100 N
P 2 0 1 16 100 100 100 -100 N
X 2 2 300 0 200 L 40 40 1 1 P
X 1 1 -300 0 200 R 40 40 1 1 P
ENDDRAW
ENDDEF
#
# GND
#
DEF ~GND #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 0 30 H I C C
F1 "GND" 0 -70 30 H I C C
DRAW
P 4 0 1 4 -50 0 0 -50 50 0 -50 0 N
X GND 1 0 0 0 U 30 30 1 1 W N
ENDDRAW
ENDDEF
#
# MEGA32-P
#
DEF MEGA32-P IC 0 40 Y Y 1 L N
F0 "IC" -800 1830 50 H V L B
F1 "MEGA32-P" 200 -2000 50 H V L B
F2 "atmel-DIL40" 0 150 50 H I C C
DRAW
P 2 1 0 0 -800 1800 800 1800 N
P 2 1 0 0 800 1800 800 -1800 N
P 2 1 0 0 800 -1800 -800 -1800 N
P 2 1 0 0 -800 -1800 -800 1800 N
X VCC 10 -100 2000 200 D 40 40 1 1 W
X AVCC 30 0 2000 200 D 40 40 1 1 W
X (RXD)PD0 14 1000 -1700 200 L 40 40 1 1 B
X (TXD)PD1 15 1000 -1600 200 L 40 40 1 1 B
X (INT0)PD2 16 1000 -1500 200 L 40 40 1 1 B
X (INT1)PD3 17 1000 -1400 200 L 40 40 1 1 B
X (OC1B)PD4 18 1000 -1300 200 L 40 40 1 1 B
X (OC1A)PD5 19 1000 -1200 200 L 40 40 1 1 B
X (ICP)PD6 20 1000 -1100 200 L 40 40 1 1 B
X (OC2)PD7 21 1000 -1000 200 L 40 40 1 1 B
X (SCL)PC0 22 1000 -800 200 L 40 40 1 1 B
X (SDA)PC1 23 1000 -700 200 L 40 40 1 1 B
X (TCK)PC2 24 1000 -600 200 L 40 40 1 1 B
X (TMS)PC3 25 1000 -500 200 L 40 40 1 1 B
X (TDO)PC4 26 1000 -400 200 L 40 40 1 1 B
X (TDI)PC5 27 1000 -300 200 L 40 40 1 1 B
X (TOSC1)PC6 28 1000 -200 200 L 40 40 1 1 B
X (TOSC2)PC7 29 1000 -100 200 L 40 40 1 1 B
X (T0/XCK)PB0 1 1000 100 200 L 40 40 1 1 B
X (T1)PB1 2 1000 200 200 L 40 40 1 1 B
X (AIN0/INT2)PB2 3 1000 300 200 L 40 40 1 1 B
X (AIN1/OC0)PB3 4 1000 400 200 L 40 40 1 1 B
X (SS)PB4 5 1000 500 200 L 40 40 1 1 B
X (MOSI)PB5 6 1000 600 200 L 40 40 1 1 B
X (MISO)PB6 7 1000 700 200 L 40 40 1 1 B
X (SCK)PB7 8 1000 800 200 L 40 40 1 1 B
X (ADC0)PA0 40 1000 1000 200 L 40 40 1 1 B
X (ADC1)PA1 39 1000 1100 200 L 40 40 1 1 B
X (ADC2)PA2 38 1000 1200 200 L 40 40 1 1 B
X (ADC3)PA3 37 1000 1300 200 L 40 40 1 1 B
X (ADC4)PA4 36 1000 1400 200 L 40 40 1 1 B
X (ADC5)PA5 35 1000 1500 200 L 40 40 1 1 B
X (ADC6)PA6 34 1000 1600 200 L 40 40 1 1 B
X (ADC7)PA7 33 1000 1700 200 L 40 40 1 1 B
X AREF 32 -1000 500 200 R 40 40 1 1 W
X XTAL1 13 -1000 900 200 R 40 40 1 1 B
X XTAL2 12 -1000 1300 200 R 40 40 1 1 B
X RESET 9 -1000 1700 200 R 40 40 1 1 I I
X GND 11 -100 -2000 200 U 40 40 1 1 W
X AGND 31 0 -2000 200 U 40 40 1 1 W
ENDDRAW
ENDDEF
#
# PINHD-1X16M
#
DEF PINHD-1X16M JP 0 40 Y Y 1 L N
F0 "JP" -250 825 50 H V L B
F1 "PINHD-1X16M" -250 -1000 50 H V L B
F2 "pinhead-1X16M" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 800 -250 -900 N
P 2 1 0 0 50 800 -250 800 N
P 2 1 0 0 50 -900 50 800 N
P 2 1 0 0 -250 -900 50 -900 N
X 16 16 -100 -800 100 R 40 40 1 1 P I
X 15 15 -100 -700 100 R 40 40 1 1 P I
X 14 14 -100 -600 100 R 40 40 1 1 P I
X 13 13 -100 -500 100 R 40 40 1 1 P I
X 12 12 -100 -400 100 R 40 40 1 1 P I
X 11 11 -100 -300 100 R 40 40 1 1 P I
X 10 10 -100 -200 100 R 40 40 1 1 P I
X 9 9 -100 -100 100 R 40 40 1 1 P I
X 8 8 -100 0 100 R 40 40 1 1 P I
X 7 7 -100 100 100 R 40 40 1 1 P I
X 6 6 -100 200 100 R 40 40 1 1 P I
X 5 5 -100 300 100 R 40 40 1 1 P I
X 4 4 -100 400 100 R 40 40 1 1 P I
X 3 3 -100 500 100 R 40 40 1 1 P I
X 2 2 -100 600 100 R 40 40 1 1 P I
X 1 1 -100 700 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# PINHD-1X3
#
DEF PINHD-1X3 JP 0 40 Y Y 1 L N
F0 "JP" -250 225 50 H V L B
F1 "PINHD-1X3" -250 -300 50 H V L B
F2 "pinhead-1X03" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 200 -250 -200 N
P 2 1 0 0 50 200 -250 200 N
P 2 1 0 0 50 -200 50 200 N
P 2 1 0 0 -250 -200 50 -200 N
X 3 3 -100 -100 100 R 40 40 1 1 P I
X 2 2 -100 0 100 R 40 40 1 1 P I
X 1 1 -100 100 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# PINHD-1X3M
#
DEF PINHD-1X3M JP 0 40 Y Y 1 L N
F0 "JP" -250 225 50 H V L B
F1 "PINHD-1X3M" -250 -300 50 H V L B
F2 "pinhead-1X03M" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 200 -250 -200 N
P 2 1 0 0 50 200 -250 200 N
P 2 1 0 0 50 -200 50 200 N
P 2 1 0 0 -250 -200 50 -200 N
X 3 3 -100 -100 100 R 40 40 1 1 P I
X 2 2 -100 0 100 R 40 40 1 1 P I
X 1 1 -100 100 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# PINHD-1X4
#
DEF PINHD-1X4 JP 0 40 Y Y 1 L N
F0 "JP" -250 325 50 H V L B
F1 "PINHD-1X4" -250 -300 50 H V L B
F2 "pinhead-1X04" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 300 -250 -200 N
P 2 1 0 0 50 300 -250 300 N
P 2 1 0 0 50 -200 50 300 N
P 2 1 0 0 -250 -200 50 -200 N
X 4 4 -100 -100 100 R 40 40 1 1 P I
X 3 3 -100 0 100 R 40 40 1 1 P I
X 2 2 -100 100 100 R 40 40 1 1 P I
X 1 1 -100 200 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# PINHD-1X5M
#
DEF PINHD-1X5M JP 0 40 Y Y 1 L N
F0 "JP" -250 325 50 H V L B
F1 "PINHD-1X5M" -250 -400 50 H V L B
F2 "pinhead-1X05M" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 300 -250 -300 N
P 2 1 0 0 50 300 -250 300 N
P 2 1 0 0 50 -300 50 300 N
P 2 1 0 0 -250 -300 50 -300 N
X 5 5 -100 -200 100 R 40 40 1 1 P I
X 4 4 -100 -100 100 R 40 40 1 1 P I
X 3 3 -100 0 100 R 40 40 1 1 P I
X 2 2 -100 100 100 R 40 40 1 1 P I
X 1 1 -100 200 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# PINHD-1X8M
#
DEF PINHD-1X8M JP 0 40 Y Y 1 L N
F0 "JP" -250 525 50 H V L B
F1 "PINHD-1X8M" -250 -500 50 H V L B
F2 "pinhead-1X08M" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 500 -250 -400 N
P 2 1 0 0 50 500 -250 500 N
P 2 1 0 0 50 -400 50 500 N
P 2 1 0 0 -250 -400 50 -400 N
X 8 8 -100 -300 100 R 40 40 1 1 P I
X 7 7 -100 -200 100 R 40 40 1 1 P I
X 6 6 -100 -100 100 R 40 40 1 1 P I
X 5 5 -100 0 100 R 40 40 1 1 P I
X 4 4 -100 100 100 R 40 40 1 1 P I
X 3 3 -100 200 100 R 40 40 1 1 P I
X 2 2 -100 300 100 R 40 40 1 1 P I
X 1 1 -100 400 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# PINHD-2X5M
#
DEF PINHD-2X5M JP 0 40 Y Y 1 L N
F0 "JP" -250 325 50 H V L B
F1 "PINHD-2X5M" -250 -400 50 H V L B
F2 "pinhead-2X05M" 0 150 50 H I C C
DRAW
P 2 1 0 0 -250 300 -250 -300 N
P 2 1 0 0 350 300 -250 300 N
P 2 1 0 0 350 -300 350 300 N
P 2 1 0 0 -250 -300 350 -300 N
X 10 10 200 -200 100 L 40 40 1 1 P I
X 8 8 200 -100 100 L 40 40 1 1 P I
X 6 6 200 0 100 L 40 40 1 1 P I
X 4 4 200 100 100 L 40 40 1 1 P I
X 2 2 200 200 100 L 40 40 1 1 P I
X 9 9 -100 -200 100 R 40 40 1 1 P I
X 7 7 -100 -100 100 R 40 40 1 1 P I
X 5 5 -100 0 100 R 40 40 1 1 P I
X 3 3 -100 100 100 R 40 40 1 1 P I
X 1 1 -100 200 100 R 40 40 1 1 P I
ENDDRAW
ENDDEF
#
# R
#
DEF R R 0 0 N Y 1 F N
F0 "R" 80 0 50 V V C C
F1 "R" 0 0 50 V V C C
$FPLIST
R?
SM0603
SM0805
$ENDFPLIST
DRAW
S -40 150 40 -150 0 1 8 N
X ~ 1 0 250 100 D 60 60 1 1 P
X ~ 2 0 -250 100 U 60 60 1 1 P
ENDDRAW
ENDDEF
#
# USB_CONN
#
DEF USB_CONN J 0 0 Y Y 1 F N
F0 "J" -50 400 60 H V C C
F1 "USB_CONN" -250 150 60 V V C C
ALIAS USB
DRAW
P 3 0 1 0 100 -50 200 -200 200 -200 N
S 50 100 50 200 0 1 0 N
P 4 0 1 0 -100 -450 -50 -400 -50 -50 -50 -50 N
P 4 0 1 0 0 -50 0 -400 50 -450 50 -450 N
P 9 0 1 0 -150 0 100 0 100 250 50 300 -100 300 -150 250 -150 0 -150 0 -150 0 N
S -100 200 -100 100 0 1 0 N
P 4 0 1 0 50 -50 50 -250 200 -350 200 -350 N
S -100 200 -100 200 0 1 0 N
P 3 0 1 0 -150 -50 -250 -200 -250 -200 N
S 50 100 -100 100 0 1 0 N
P 6 0 1 0 -200 -50 150 -50 150 350 -200 350 -200 -50 -200 -50 N
S -100 200 50 200 0 1 0 N
P 4 0 1 0 -100 -50 -100 -250 -250 -350 -250 -350 N
X Shield_1 5 350 -450 300 L 40 30 1 1 P
X D- 2 350 -350 150 L 40 30 1 1 B
X D+ 3 350 -200 150 L 40 30 1 1 B
X Shield_2 6 -400 -450 300 R 40 30 1 1 P
X GND 4 -400 -350 150 R 40 30 1 1 w
X Vbus 1 -400 -200 150 R 40 30 1 1 w
ENDDRAW
ENDDEF
#
# VCC
#
DEF VCC #PWR 0 0 Y Y 1 F P
F0 "#PWR" 0 100 30 H I C C
F1 "VCC" 0 100 30 H V C C
DRAW
C 0 50 20 0 1 4 N
P 3 0 1 4 0 0 0 30 0 30 N
X VCC 1 0 0 0 U 20 20 0 0 W N
ENDDRAW
ENDDEF
#
# ZENER
#
DEF ZENER D 0 40 N N 1 F N
F0 "D" 0 100 50 H V C C
F1 "ZENER" 0 -100 40 H V C C
$FPLIST
D?
SO*
SM*
$ENDFPLIST
DRAW
P 5 0 1 0 50 0 -50 50 -50 -50 50 0 50 0 F
P 5 0 1 8 70 50 50 30 50 -30 30 -50 30 -50 N
X K 2 200 0 150 L 40 40 1 1 P
X A 1 -200 0 150 R 40 40 1 1 P
ENDDRAW
ENDDEF
#
#EndLibrary

View File

@ -0,0 +1,146 @@
update=16/4/2008-14:31:58
last_client=pcbnew
[general]
version=1
RootSch=dulcimer.sch
[common]
NetDir=
[eeschema]
version=1
LibDir=
NetFmt=1
HPGLSpd=20
HPGLDm=15
HPGLNum=1
offX_A4=0
offY_A4=0
offX_A3=0
offY_A3=0
offX_A2=0
offY_A2=0
offX_A1=0
offY_A1=0
offX_A0=0
offY_A0=0
offX_A=0
offY_A=0
offX_B=0
offY_B=0
offX_C=0
offY_C=0
offX_D=0
offY_D=0
offX_E=0
offY_E=0
RptD_X=0
RptD_Y=100
RptLab=1
SimCmd=
UseNetN=0
LabSize=60
[eeschema/libraries]
LibName1=power
LibName2=pinhead
LibName3=device
LibName4=conn
LibName5=linear
LibName6=regul
LibName7=74xx
LibName8=cmos4000
LibName9=adc-dac
LibName10=memory
LibName11=xilinx
LibName12=special
LibName13=microcontrollers
LibName14=dsp
LibName15=microchip
LibName16=analog_switches
LibName17=motorola
LibName18=texas
LibName19=intel
LibName20=audio
LibName21=interface
LibName22=digital-audio
LibName23=philips
LibName24=display
LibName25=cypress
LibName26=siliconi
LibName27=contrib
LibName28=valves
[cvpcb]
version=1
NetITyp=0
NetIExt=.net
PkgIExt=.pkg
NetType=0
[cvpcb/libraries]
EquName1=devcms
[pcbnew]
version=1
PadDrlX=320
PadDimH=600
PadDimV=600
PadForm=1
PadMask=14745599
ViaDiam=450
ViaDril=250
MViaDia=200
MViaDrl=80
Isol=60
Countlayer=2
Lpiste=170
RouteTo=15
RouteBo=0
TypeVia=3
Segm45=1
Racc45=1
Unite=0
SegFill=1
SegAffG=0
NewAffG=1
PadFill=1
PadAffG=1
PadSNum=1
ModAffC=0
ModAffT=0
PcbAffT=0
SgPcb45=1
TxtPcbV=800
TxtPcbH=600
TxtModV=600
TxtModH=600
TxtModW=120
HPGLnum=1
HPGdiam=15
HPGLSpd=20
HPGLrec=2
HPGLorg=0
GERBmin=15
VEgarde=100
DrawLar=150
EdgeLar=150
TxtLar=120
MSegLar=150
ForPlot=1
WpenSer=10
UserGrX=1
UserGrY=1
UserGrU=1
DivGrPc=1
TimeOut=600
MaxLnkS=3
ShowRat=0
ShowMRa=1
[pcbnew/libraries]
LibDir=
LibName1=supports
LibName2=pl_empreinte
LibName3=pinhead
LibName4=atmel
LibName5=connect
LibName6=discret
LibName7=pin_array
LibName8=divers
LibName9=libcms
LibName10=display
LibName11=valves

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ AVRDUDE = avrdude -p atmega32 -c usbasp
# Options: # Options:
HWOBJECTS = modelibmmodelm.o HWOBJECTS = modelibmmodelm.o
#HWOBJECTS = modelmayhem.o
#HWOBJECTS = modelsuntype5.o #HWOBJECTS = modelsuntype5.o
COMPILE = avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega32 -DF_CPU=12000000L $(DEFINES) COMPILE = avr-gcc -Wall -Os -Iusbdrv -I. -mmcu=atmega32 -DF_CPU=12000000L $(DEFINES)

311
firmware/modelmayhem.c Normal file
View File

@ -0,0 +1,311 @@
/**
* \file firmware/modelmayhem.c
* \brief Hardware specific part for IBM Model M keyboard, modified to be the
* ultimate geek keyboard. :-)
* \author Ronald Schaten <ronald@schatenseite.de>
* \version $Id$
*
* License: GNU GPL v2 (see License.txt)
*/
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <string.h>
#include <stdio.h>
#include "keycodes.h"
#include "tools.h"
#include "modelinterface.h"
/* ----------------------- hardware I/O abstraction ------------------------ */
#define PORTCOLUMNS PORTB ///< port on which we read the state of the columns
#define PINCOLUMNS PINB ///< port on which we read the state of the columns
#define DDRCOLUMNS DDRB ///< port on which we read the state of the columns
#define PORTROWS1 PORTA ///< first port connected to the matrix rows
#define PINROWS1 PINA ///< first port connected to the matrix rows
#define DDRROWS1 DDRA ///< first port connected to the matrix rows
#define PORTROWS2 PORTC ///< second port connected to the matrix rows
#define PINROWS2 PINC ///< second port connected to the matrix rows
#define DDRROWS2 DDRC ///< second port connected to the matrix rows
#define PORTLEDS PORTD ///< port on which the LEDs are connected
#define PINLEDS PIND ///< port on which the LEDs are connected
#define DDRLEDS DDRD ///< port on which the LEDs are connected
#define LEDCOMP PIND1 ///< address of the compose LED
#define LEDNUM PIND3 ///< address of the num-lock LED
#define LEDCAPS PIND6 ///< address of the caps-lock LED
#define LEDSCROLL PIND7 ///< address of the scroll-lock LED
#define LEDBACK1 PIND4 ///< address of the first backlight LED
#define LEDBACK2 PIND5 ///< address of the second backlight LED
uint8_t curmatrix[16]; ///< contains current state of the keyboard
uint8_t oldmatrix[16]; ///< contains old state of the keyboard
uint8_t ghostmatrix[16]; ///< contains pressed keys that belong to a ghost-key situation
void hardwareInit(void) {
// column-port is input
PORTCOLUMNS = 0xff;
DDRCOLUMNS = 0x00;
// row-ports are output
PORTROWS1 = 0xff;
DDRROWS1 = 0x00;
PORTROWS2 = 0xff;
DDRROWS2 = 0x00;
// port D contains USB (D0, D2),
// LEDs (D4, D5, D6)
// and Jumpers (D1, D3, D7),
// so we call it PORTD instead of PORTJUMPERS or PORTLEDS
PORTD = 0xfa; // 1111 1010: no pull-ups on USB- and LED-lines
DDRD = 0xff; // 1111 1111: USB reset condition, LED-lines off
// USB Reset by device only required on Watchdog Reset
_delay_us(11); // delay >10ms for USB reset
DDRD = 0xfa; // 1111 1010: remove USB reset condition
// configure timer 0 for a rate of 12M/(1024 * 256) = 45.78Hz (~22ms)
TCCR0 = 5; // timer 0 prescaler: 1024
// blink, to indicate power-on
PORTLEDS &= ~((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL) | (1 << LEDCOMP));
_delay_ms(50);
PORTLEDS |= ((1 << LEDNUM) | (1 << LEDCAPS) | (1 << LEDSCROLL) | (1 << LEDCOMP));
}
/**
* Print the current state of the keyboard in a readable form. This function
* is used for debug-purposes only.
*/
void printMatrix(void) {
for (uint8_t i = 0; i <= 15; i++) {
char buffer[10];
/*
sprintf(buffer, "%d%d%d%d%d%d%d%d.",
(curmatrix[i] & (1 << 0) ? 1 : 0),
(curmatrix[i] & (1 << 1) ? 1 : 0),
(curmatrix[i] & (1 << 2) ? 1 : 0),
(curmatrix[i] & (1 << 3) ? 1 : 0),
(curmatrix[i] & (1 << 4) ? 1 : 0),
(curmatrix[i] & (1 << 5) ? 1 : 0),
(curmatrix[i] & (1 << 6) ? 1 : 0),
(curmatrix[i] & (1 << 7) ? 1 : 0));
*/
sprintf(buffer, "%2x", curmatrix[i]);
sendString(buffer);
if (i == 7) {
sendString(":");
} else {
sendString(".");
}
}
sendString("---");
}
void setLeds(uint8_t LEDstate) {
if (LEDstate & LED_NUM) { // light up num lock
PORTLEDS &= ~(1 << LEDNUM);
} else {
PORTLEDS |= (1 << LEDNUM);
}
if (LEDstate & LED_CAPS) { // light up caps lock
PORTLEDS &= ~(1 << LEDCAPS);
} else {
PORTLEDS |= (1 << LEDCAPS);
}
if (LEDstate & LED_SCROLL) { // light up scroll lock
PORTLEDS &= ~(1 << LEDSCROLL);
} else {
PORTLEDS |= (1 << LEDSCROLL);
}
if (LEDstate & LED_COMPOSE) { // light up compose
PORTLEDS &= ~(1 << LEDCOMP);
} else {
PORTLEDS |= (1 << LEDCOMP);
}
}
/**
* The keymatrix-array contains positions of keys in the matrix. Here you can
* see which row is connected to which column when a key is pressed. This array
* probably has to be modified if this firmware is ported to a different
* keyboard.
* \sa modmatrix
*/
const uint8_t PROGMEM keymatrix[16][8] = {
// 0 1 2 3 4 5 6 7
{KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved }, // 0
{KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_Reserved }, // 1
{KEY_ESCAPE, KEY_Tab, KEY_grave, KEY_1, KEY_Q, KEY_A, KEY_Z, KEY_Reserved }, // 2
{KEY_Euro, KEY_capslock, KEY_F1, KEY_2, KEY_W, KEY_S, KEY_X, KEY_Reserved }, // 3
{KEY_F4, KEY_F3, KEY_F2, KEY_3, KEY_E, KEY_D, KEY_C, KEY_Reserved }, // 4
{KEY_G, KEY_T, KEY_5, KEY_4, KEY_R, KEY_F, KEY_V, KEY_B }, // 5
{KEY_F5, KEY_DELETE, KEY_F9, KEY_F10, KEY_Reserved, KEY_Reserved, KEY_Return, KEY_Spacebar }, // 6
{KEY_H, KEY_Y, KEY_6, KEY_7, KEY_U, KEY_J, KEY_M, KEY_N }, // 7
{KEY_F6, KEY_rbracket, KEY_equals, KEY_8, KEY_I, KEY_K, KEY_comma, KEY_Reserved }, // 8
{KEY_Reserved, KEY_F7, KEY_F8, KEY_9, KEY_O, KEY_L, KEY_dot, KEY_Reserved }, // 9
{KEY_apostroph, KEY_lbracket, KEY_minus, KEY_0, KEY_P, KEY_semicolon, KEY_hash, KEY_slash }, // 10
{KEY_Reserved, KEY_KP4, KEY_DeleteForward, KEY_F11, KEY_KP7, KEY_KP1, KEY_NumLock, KEY_DownArrow }, // 11
{KEY_KP0, KEY_KP5, KEY_Insert, KEY_F12, KEY_KP8, KEY_KP2, KEY_KPslash, KEY_RightArrow }, // 12
{KEY_KPcomma, KEY_KP6, KEY_PageUp, KEY_PageDown, KEY_KP9, KEY_KP3, KEY_KPasterisk, KEY_KPminus }, // 13
{KEY_UpArrow, KEY_Reserved, KEY_Home, KEY_End, KEY_KPplus, KEY_KPenter, KEY_Pause, KEY_LeftArrow }, // 14
{KEY_Reserved, KEY_Reserved, KEY_Reserved, KEY_PrintScreen, KEY_ScrollLock, KEY_Reserved, KEY_Reserved, KEY_Reserved }, // 15
};
/**
* The modmatrix-array contains positions of the modifier-keys in the matrix.
* It is built in the same way as the keymatrix-array.
* \sa keymatrix
*/
const uint8_t PROGMEM modmatrix[16][8] = { // contains positions of modifiers in the matrix
// 0 1 2 3 4 5 6 7
{MOD_NONE, MOD_NONE, MOD_CONTROL_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_CONTROL_RIGHT, MOD_NONE }, // 0
{MOD_NONE, MOD_SHIFT_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_SHIFT_RIGHT, MOD_NONE }, // 1
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 2
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 3
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 4
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 5
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 6
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 7
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 8
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 9
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 10
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 11
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 12
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 13
{MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE }, // 14
{MOD_ALT_LEFT, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_NONE, MOD_ALT_RIGHT}, // 15
};
/**
* Checks if more than one bit in data is set.
* \param data value to check
* \return true if more than one bit is set
*/
static uint8_t bitcount2(uint16_t data) {
data &= (data - 1);
return data != 0;
}
/**
* check if reportBuffer contains the key
* \param buffer buffer to check
* \param key key to search
* \return 1 if buffer contains key, 0 otherwise
*/
static uint8_t bufferContains(uint8_t* buffer, uint8_t key) {
for (uint8_t i = 2; i < sizeof(buffer); i++) {
if (buffer[i] == key) {
return 1;
}
}
return 0;
}
/**
* Scan and debounce keypresses. This is the main worker function for normal
* keyboard operation, the code contains lot of comments. Basically, it first
* scans the keyboard state. If a change is detected, it initializes a counter
* that is decreased each time this function is called. If the counter reaches
* 1, that means that the same scan result has been scanned ten times in a row,
* so we can be pretty sure that the keys are in a certain state (as in: not
* bouncing). Then, the codes for keys and modifiers are searched from the two
* arrays, the USB-message to send the state is prepared. The return value of
* this function indicates if the message has to be sent.
* \return flag to indicate whether something has changed
*/
uint8_t scankeys(uint8_t* reportBuffer, uint8_t* oldReportBuffer, uint8_t sizeOfReportBuffer) {
static uint8_t debounce = 5;
uint8_t retval = 0;
for (uint8_t row = 0; row <= 15; row++) {
if (row <= 7) {
DDRROWS1 = (1 << row);
PORTROWS1 = ~(1 << row);
DDRROWS2 = 0x00;
PORTROWS2 = 0xff;
} else {
DDRROWS1 = 0x00;
PORTROWS1 = 0xff;
// (15 - row) looks a bit weird, you would expect (row - 8) here.
// This is because pins on PORTC are ordered in the other direction
// than on PORTA. With (15 - row), we have the bytes in the
// resulting matrix matching the pins of the keyboard connector.
DDRROWS2 = (1 << (15 - row));
PORTROWS2 = ~(1 << (15 - row));
}
_delay_us(30);
uint8_t data = ~PINCOLUMNS;
// check if we have to prevent ghost-keys
uint16_t rows= (PINROWS1 << 8) | PINROWS2;
if (bitcount2(~rows) && bitcount2(data)) {
// ghost-key situation detected
ghostmatrix[row] = data;
} else {
ghostmatrix[row] = 0x00;
}
if (data != curmatrix[row]) {
// if a change was detected
debounce = 10; // activate debounce counter
curmatrix[row] = data; // and store the result
}
}
if (debounce) {
// Count down, but avoid underflow
debounce--;
}
if (debounce == 1) {
/*
if (memcmp(oldmatrix, curmatrix, sizeof(curmatrix)) != 0) {
printMatrix();
memcpy(oldmatrix, curmatrix, sizeof(curmatrix));
}
*/
// debounce counter expired, create report
uint8_t reportIndex = 2; // reportBuffer[0] contains modifiers
memset(reportBuffer, 0, sizeOfReportBuffer); // clear report buffer
for (uint8_t row = 0; row <= 15; row++) { // process all rows for key-codes
uint8_t data = curmatrix[row]; // restore buffer
if (data != 0xff) { // anything on this row? - optimization
for (uint8_t col = 0; col <= 7; col++) { // check every bit on this row
uint8_t key, modifier, isghostkey;
if (data & (1 << col)) {
key = pgm_read_byte(&keymatrix[row][col]);
modifier = pgm_read_byte(&modmatrix[row][col]);
isghostkey = ghostmatrix[row] & (1 << col);
} else {
key = KEY_Reserved;
modifier = MOD_NONE;
isghostkey = 0x00;
}
if (key != KEY_Reserved) { // keycode should be added to report
if (reportIndex >= sizeOfReportBuffer) { // too many keycodes
if (!retval & 0x02) { // Only fill buffer once
memset(reportBuffer+2, KEY_ErrorRollOver, sizeOfReportBuffer-2);
retval |= 0x02; // continue decoding to get modifiers
}
} else {
if (isghostkey) {
// we're in a ghost-key situation
if (bufferContains(oldReportBuffer, key)) {
// this key has been pressed before, so we still send it
reportBuffer[reportIndex] = key; // set next available entry
reportIndex++;
}
} else {
reportBuffer[reportIndex] = key; // set next available entry
reportIndex++;
}
}
}
if (modifier != MOD_NONE) { // modifier should be added to report
reportBuffer[0] |= modifier;
}
}
}
}
retval |= 0x01; // must have been a change at some point, since debounce is done
}
return retval;
}