1 | /* Amiga Keyboard reading on Atmel AVR
|
---|
2 | * Copyright 2010, Adrien Destugues <pulkomandy@pulkomandy.ath.cx>
|
---|
3 | * Distributed under the terms of the MIT Licence */
|
---|
4 |
|
---|
5 | #include <avr/io.h>
|
---|
6 | #include <avr/interrupt.h>
|
---|
7 | #include <avr/pgmspace.h>
|
---|
8 | #include <util/delay.h>
|
---|
9 |
|
---|
10 | #include "amiga_keyboard.h"
|
---|
11 | // #include "keymap.h"
|
---|
12 |
|
---|
13 |
|
---|
14 | //PIN configuration
|
---|
15 | #define AK_CLK PD3 /* Also INT1 */
|
---|
16 | #define AK_PORT PIND
|
---|
17 | #define AK_DATA PD4
|
---|
18 |
|
---|
19 | volatile uint8_t kbd_data;
|
---|
20 | volatile uint8_t char_waiting;
|
---|
21 | uint8_t started;
|
---|
22 | uint8_t bit_count;
|
---|
23 | uint8_t shift;
|
---|
24 |
|
---|
25 |
|
---|
26 | // Notify the keyboard we got the last char right
|
---|
27 | inline void acknowledge_char()
|
---|
28 | {
|
---|
29 | // We have to pull down the "DATA" line
|
---|
30 |
|
---|
31 | // Set it as an input
|
---|
32 | DDRD |= (1<<AK_DATA);
|
---|
33 |
|
---|
34 | // Down for 85 us
|
---|
35 | PORTD &= ~(1<<AK_DATA);
|
---|
36 | _delay_us(85);
|
---|
37 |
|
---|
38 | // Up again to let the keybord talk
|
---|
39 | PORTD |= (1<<AK_DATA);
|
---|
40 |
|
---|
41 | // And it's now an input again
|
---|
42 | DDRD &= ~(1<<AK_DATA);
|
---|
43 | }
|
---|
44 |
|
---|
45 |
|
---|
46 | // Interrupt vector - Triggered when there is activity on the clock line
|
---|
47 | ISR(INT1_vect)
|
---|
48 | {
|
---|
49 | //make sure clock line is low, if not ignore this transition
|
---|
50 | if(AK_PORT & (1<<AK_CLK)){
|
---|
51 | return;
|
---|
52 | }
|
---|
53 |
|
---|
54 | // First bit, reset everything then continue below
|
---|
55 | if(!started){
|
---|
56 | started = 1;
|
---|
57 | bit_count = 0;
|
---|
58 | kbd_data = 0;
|
---|
59 | }
|
---|
60 |
|
---|
61 | if(bit_count < 8) { //we started, read in the new bit
|
---|
62 | //put a 1 in the right place of kdb_data if PC2 is high, leave
|
---|
63 | //a 0 otherwise
|
---|
64 | if(!(AK_PORT & (1<<AK_DATA))) kbd_data |= (128>>bit_count);
|
---|
65 | bit_count++;
|
---|
66 | }
|
---|
67 |
|
---|
68 | if(bit_count >= 8)
|
---|
69 | { // enough bits
|
---|
70 | started = 0;
|
---|
71 | bit_count = 0;
|
---|
72 |
|
---|
73 | /*
|
---|
74 | if(kbd_data == 0xF0){ //release code
|
---|
75 | release = 1;
|
---|
76 | kbd_data = 0;
|
---|
77 | return;
|
---|
78 | } else if (kbd_data == 0x12) { //hanlde shift key
|
---|
79 | if(release == 0){
|
---|
80 | shift = 1;
|
---|
81 | } else {
|
---|
82 | shift = 0;
|
---|
83 | release = 0;
|
---|
84 | }
|
---|
85 | return;
|
---|
86 | } else { //not a special character
|
---|
87 | if(release){ //we were in release mode - exit release mode
|
---|
88 | release = 0;
|
---|
89 | //ignore that character
|
---|
90 | } else {
|
---|
91 | char_waiting = 1;
|
---|
92 | }
|
---|
93 | }*/
|
---|
94 | char_waiting=1;
|
---|
95 | }
|
---|
96 | }
|
---|
97 |
|
---|
98 |
|
---|
99 | /*
|
---|
100 | char ak_scancode_to_ascii(uint8_t data){
|
---|
101 | char to_ret = pgm_read_byte(&(keymap[data])); //grab character from array
|
---|
102 | if(shift) to_ret -= 0x20;
|
---|
103 | return to_ret;
|
---|
104 | }
|
---|
105 | */
|
---|
106 |
|
---|
107 | uint8_t ak_wait_scancode(){
|
---|
108 | while(!char_waiting);
|
---|
109 | return ak_read_scancode();
|
---|
110 | }
|
---|
111 |
|
---|
112 |
|
---|
113 | uint8_t ak_read_scancode() {
|
---|
114 | while ((AK_PORT & (1<<AK_CLK)) == 0);
|
---|
115 | _delay_us(30);
|
---|
116 | acknowledge_char();
|
---|
117 |
|
---|
118 | char_waiting = 0;
|
---|
119 | return kbd_data;
|
---|
120 | }
|
---|
121 |
|
---|
122 |
|
---|
123 | void ak_init_keyboard(){
|
---|
124 | started = 0;
|
---|
125 | kbd_data = 0;
|
---|
126 | bit_count = 0;
|
---|
127 |
|
---|
128 | //make AK_CLK input pin
|
---|
129 | DDRD &= ~(1<<AK_CLK);
|
---|
130 | //turn on pullup resistor
|
---|
131 | AK_PORT |= (1<<AK_CLK);
|
---|
132 |
|
---|
133 | // Interrupt configuration
|
---|
134 | // We use INT1 falling edge
|
---|
135 | MCUCR |= (1<<ISC11);
|
---|
136 | MCUCR &= ~(1<<ISC10);
|
---|
137 |
|
---|
138 | // Enable INT1
|
---|
139 | GIMSK |= (1<<INT1);
|
---|
140 |
|
---|
141 | // Enable interrupts
|
---|
142 | sei();
|
---|
143 |
|
---|
144 | acknowledge_char();
|
---|
145 | }
|
---|
146 |
|
---|
147 |
|
---|