1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
|
#include "project.h"
#define KBCLK (1UL << 0)
#define KBCLK_PORT GPIOA
#define KBCLK_IRQ NVIC_EXTI0_IRQ
#define KBDAT (1UL << 1)
#define KBDAT_PORT GPIOA
/*Cope with lost sync */
/*If we've had no bits for this long, it's definately the start of a new word, 72MHz units */
#define RESYNC_GAP (7200000) /* 100ms */
#define ATKBD_TIMEOUT 1000 /*how long to wait for the keyboard to respond to a command in ms */
typedef enum {
STATE_START=0,
STATE_BIT0,
STATE_BIT1,
STATE_BIT2,
STATE_BIT3,
STATE_BIT4,
STATE_BIT5,
STATE_BIT6,
STATE_BIT7,
STATE_PARITY,
STATE_STOP,
} atkbd_state;
#define ATKBD_CMD_SETLEDS 0xed
#define ATKBD_CMD_GSCANSET 0xf0
#define ATKBD_CMD_SSCANSET 0xf0
#define ATKBD_CMD_GETID 0xf2
#define ATKBD_CMD_SETREP 0xf3
#define ATKBD_CMD_ENABLE 0xf4
#define ATKBD_CMD_RESET_DIS 0xf5
#define ATKBD_CMD_RESET_DEF 0xf6
#define ATKBD_CMD_SETALL_MB 0xf8
#define ATKBD_CMD_SETALL_MBR 0xfa
#define ATKBD_CMD_RESET_BAT 0xff
#define ATKBD_CMD_RESEND 0xfe
#define ATKBD_CMD_EX_ENABLE 0xea
#define ATKBD_CMD_EX_SETLEDS 0xeb
#define ATKBD_CMD_OK_GETID 0xe8
#define ATKBD_RET_ECHO 0xee
#define ATKBD_RET_ACK 0xfa
#define ATKBD_RET_NAK 0xfe
#define ATKBD_RET_BAT 0xaa
#define ATKBD_RET_EMUL0 0xe0
#define ATKBD_RET_EMUL1 0xe1
#define ATKBD_RET_RELEASE 0xf0
#define ATKBD_RET_HANJA 0xf1
#define ATKBD_RET_HANGEUL 0xf2
#define ATKBD_RET_ERR 0xff
#define ATKBD_KEY_UNKNOWN 0
#define ATKBD_KEY_NULL 255
static int atkbd_ack;
static int atkbd_nack;
static int atkbd_bat;
static int atkbd_echo;
static uint32_t cycle_diff(uint32_t a,uint32_t b)
{
return b-a;
}
static void atkbd_dispatch(int emul,int key,int updown)
{
printf("KEY> %x %x %x\r\n",emul,key,updown);
}
static void atkbd_data_dispatch(uint8_t byte)
{
static int release;
static int emul;
printf("ATKBD < 0x%02x\r\n",byte);
switch (byte) {
case ATKBD_RET_ACK:
atkbd_ack++;
break;
case ATKBD_RET_NAK:
atkbd_nack++;
break;
case ATKBD_RET_BAT:
atkbd_bat++;
break;
case ATKBD_RET_ECHO:
atkbd_echo++;
break;
case ATKBD_RET_ERR:
case ATKBD_KEY_UNKNOWN:
case ATKBD_RET_HANJA: /*Don't handle japanese or korean for the moment*/
case ATKBD_RET_HANGEUL: /*Don't handle japanese or korean for the moment*/
/*All these need no action */
break;
case ATKBD_RET_EMUL0:
emul=1;
break;
case ATKBD_RET_EMUL1:
emul=2;
break;
case ATKBD_RET_RELEASE:
release=1;
break;
default:
atkbd_dispatch(emul,byte,release);
emul=0;
release=0;
}
}
void exti0_isr(void)
{
static uint32_t last_interrupt=0;
static atkbd_state state=STATE_START;
static uint8_t atkbd_byte;
static int parity;
uint32_t now,diff;
int d;
d=!!GET(KBDAT);
exti_reset_request(KBCLK);
now=dwt_read_cycle_counter();
diff=cycle_diff(last_interrupt,now);
last_interrupt=now;
if (diff>RESYNC_GAP) state=STATE_START;
switch (state) {
case STATE_START:
atkbd_byte=0;
parity=0;
if (!d) state++;
break;
case STATE_BIT0:
case STATE_BIT1:
case STATE_BIT2:
case STATE_BIT3:
case STATE_BIT4:
case STATE_BIT5:
case STATE_BIT6:
case STATE_BIT7:
atkbd_byte|=d<<(state-STATE_BIT0);
/* fall through*/
case STATE_PARITY:
parity ^= d;
state++;
break;
case STATE_STOP:
if (d && parity) atkbd_data_dispatch(atkbd_byte);
state=STATE_START;
break;
}
}
void atkbd_set(int clk,int dat)
{
if (clk) {
MAP_INPUT_PU(KBCLK);
} else {
CLEAR(KBCLK);
MAP_OUTPUT_PP(KBCLK);
}
if (dat) {
MAP_INPUT_PU(KBDAT);
} else {
CLEAR(KBDAT);
MAP_OUTPUT_PP(KBDAT);
}
}
int atkbd_send(uint8_t d)
{
uint32_t then=ticks;
int parity=1;
uint32_t c;
nvic_disable_irq(KBCLK_IRQ);
#define PS2_CLOCK_SEIZE_DELAY 200
#define PS2_BIT_DELAY 10
atkbd_set(0,1);
delay_us(PS2_CLOCK_SEIZE_DELAY);
atkbd_set(0,0);
delay_us(PS2_BIT_DELAY);
atkbd_set(1,0);
delay_us(PS2_BIT_DELAY);
for (c=1;c<0x100;c<<=1) {
while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
atkbd_set(1,c&d);
parity^=!!(c&d);
while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
}
while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
atkbd_set(1,parity);
while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
atkbd_set(1,1);
while (GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
while (GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
while (!GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
exti_reset_request(KBCLK);
nvic_enable_irq(KBCLK_IRQ);
printf("ATKBD > 0x%02x\r\n",d);
return 0;
err:
atkbd_set(1,1);
while (!GET(KBDAT)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
while (!GET(KBCLK)) if (timed_out(then,ATKBD_TIMEOUT)) goto err;
exti_reset_request(KBCLK);
nvic_enable_irq(KBCLK_IRQ);
printf("ATKBD >! 0x%02x\r\n",d);
return -1;
}
static int atkbd_reset(void)
{
uint32_t then=ticks;
atkbd_bat=0;
atkbd_send(ATKBD_CMD_RESET_BAT);
while (!atkbd_bat) if (timed_out(then,ATKBD_TIMEOUT)) return -1;
then=ticks;
atkbd_ack=0;
atkbd_send(ATKBD_CMD_SETALL_MBR);
while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1;
return 0;
}
int atkbd_request_echo(void)
{
uint32_t then=ticks;
atkbd_ack=0;
atkbd_send(ATKBD_CMD_ECHO);
while (!atkbd_echo) if (timed_out(then,ATKBD_TIMEOUT)) return -1;
return 0;
}
int atkbd_set_leds(uint8_t leds)
{
uint32_t then=ticks;
atkbd_ack=0;
atkbd_send(ATKBD_CMD_SETLEDS);
while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1;
then=ticks;
atkbd_ack=0;
atkbd_send(leds);
while (!atkbd_ack) if (timed_out(then,ATKBD_TIMEOUT)) return -1;
return 0;
}
void atkbd_init(void)
{
atkbd_set(1,1);
delay_ms(200);
nvic_enable_irq(NVIC_EXTI0_IRQ);
exti_select_source(KBCLK, KBCLK_PORT);
exti_set_trigger(KBCLK, EXTI_TRIGGER_FALLING);
exti_enable_request(KBCLK);
exti_reset_request(KBCLK);
nvic_enable_irq(KBCLK_IRQ);
atkbd_reset();
atkbd_request_echo();
atkbd_set_leds(0x07);
}
|