Skip to content

Commit bab41af

Browse files
committed
ps2io implementation for esp32s2
1 parent 66fb095 commit bab41af

File tree

4 files changed

+458
-0
lines changed

4 files changed

+458
-0
lines changed

ports/esp32s2/common-hal/ps2io/Ps2.c

Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2020 microDev
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "common-hal/ps2io/Ps2.h"
28+
29+
#include "py/runtime.h"
30+
#include "supervisor/port.h"
31+
#include "shared-bindings/ps2io/Ps2.h"
32+
#include "shared-bindings/microcontroller/__init__.h"
33+
34+
#define STATE_IDLE 0
35+
#define STATE_RECV 1
36+
#define STATE_RECV_PARITY 2
37+
#define STATE_RECV_STOP 3
38+
#define STATE_RECV_ERR 10
39+
40+
#define ERROR_STARTBIT 0x01
41+
#define ERROR_TIMEOUT 0x02
42+
#define ERROR_PARITY 0x04
43+
#define ERROR_STOPBIT 0x08
44+
#define ERROR_BUFFER 0x10
45+
46+
#define ERROR_TX_CLKLO 0x100
47+
#define ERROR_TX_CLKHI 0x200
48+
#define ERROR_TX_ACKDATA 0x400
49+
#define ERROR_TX_ACKCLK 0x800
50+
#define ERROR_TX_RTS 0x1000
51+
#define ERROR_TX_NORESP 0x2000
52+
53+
static void IRAM_ATTR ps2_interrupt_handler(void *self_in);
54+
55+
static void ps2_set_config(ps2io_ps2_obj_t* self) {
56+
// turn on falling edge interrupt
57+
gpio_set_intr_type(self->clk_pin, GPIO_INTR_NEGEDGE);
58+
gpio_isr_register(ps2_interrupt_handler, (void *)self, ESP_INTR_FLAG_IRAM, &self->handle);
59+
gpio_intr_enable(self->clk_pin);
60+
}
61+
62+
static void disable_interrupt(ps2io_ps2_obj_t* self) {
63+
// turn off fallling edge interrupt
64+
gpio_intr_disable(self->clk_pin);
65+
}
66+
67+
static void resume_interrupt(ps2io_ps2_obj_t* self) {
68+
self->state = STATE_IDLE;
69+
gpio_intr_enable(self->clk_pin);
70+
}
71+
72+
static void clk_hi(ps2io_ps2_obj_t* self) {
73+
// external pull-up
74+
gpio_set_direction(self->clk_pin, GPIO_MODE_INPUT);
75+
gpio_pullup_dis(self->clk_pin);
76+
}
77+
78+
static bool wait_clk_lo(ps2io_ps2_obj_t* self, uint32_t us) {
79+
clk_hi(self);
80+
common_hal_mcu_delay_us(1);
81+
while (gpio_get_level(self->clk_pin) && us) {
82+
--us;
83+
common_hal_mcu_delay_us(1);
84+
}
85+
return us;
86+
}
87+
88+
static bool wait_clk_hi(ps2io_ps2_obj_t* self, uint32_t us) {
89+
clk_hi(self);
90+
common_hal_mcu_delay_us(1);
91+
while (!gpio_get_level(self->clk_pin) && us) {
92+
--us;
93+
common_hal_mcu_delay_us(1);
94+
}
95+
return us;
96+
}
97+
98+
static void clk_lo(ps2io_ps2_obj_t* self) {
99+
gpio_pullup_dis(self->clk_pin);
100+
gpio_set_direction(self->clk_pin, GPIO_MODE_OUTPUT);
101+
gpio_set_level(self->clk_pin, 0);
102+
}
103+
104+
static void data_hi(ps2io_ps2_obj_t* self) {
105+
// external pull-up
106+
gpio_set_direction(self->data_pin, GPIO_MODE_INPUT);
107+
gpio_pullup_dis(self->data_pin);
108+
}
109+
110+
static bool wait_data_lo(ps2io_ps2_obj_t* self, uint32_t us) {
111+
data_hi(self);
112+
common_hal_mcu_delay_us(1);
113+
while (gpio_get_level(self->data_pin) && us) {
114+
--us;
115+
common_hal_mcu_delay_us(1);
116+
}
117+
return us;
118+
}
119+
120+
static bool wait_data_hi(ps2io_ps2_obj_t* self, uint32_t us) {
121+
data_hi(self);
122+
common_hal_mcu_delay_us(1);
123+
while (!gpio_get_level(self->data_pin) && us) {
124+
--us;
125+
common_hal_mcu_delay_us(1);
126+
}
127+
return us;
128+
}
129+
130+
static void data_lo(ps2io_ps2_obj_t* self) {
131+
gpio_pullup_dis(self->data_pin);
132+
gpio_set_direction(self->data_pin, GPIO_MODE_OUTPUT);
133+
gpio_set_level(self->data_pin, 0);
134+
}
135+
136+
static void idle(ps2io_ps2_obj_t* self) {
137+
clk_hi(self);
138+
data_hi(self);
139+
}
140+
141+
static void inhibit(ps2io_ps2_obj_t* self) {
142+
clk_lo(self);
143+
data_hi(self);
144+
}
145+
146+
static void delay_us(uint32_t t) {
147+
common_hal_mcu_delay_us(t);
148+
}
149+
150+
static void IRAM_ATTR ps2_interrupt_handler(void *self_in) {
151+
// Grab the current time first.
152+
uint64_t current_tick = port_get_raw_ticks(NULL);
153+
154+
ps2io_ps2_obj_t * self = self_in;
155+
int data_bit = gpio_get_level(self->data_pin) ? 1 : 0;
156+
157+
// test for timeout
158+
if (self->state != STATE_IDLE) {
159+
int64_t diff_ms = current_tick - self->last_raw_ticks;
160+
if (diff_ms > 1) { // a.k.a. > 1.001ms
161+
self->last_errors |= ERROR_TIMEOUT;
162+
self->state = STATE_IDLE;
163+
}
164+
}
165+
166+
self->last_raw_ticks = current_tick;
167+
168+
if (self->state == STATE_IDLE) {
169+
self->bits = 0;
170+
self->parity = false;
171+
self->bitcount = 0;
172+
self->state = STATE_RECV;
173+
if (data_bit) {
174+
// start bit should be 0
175+
self->last_errors |= ERROR_STARTBIT;
176+
self->state = STATE_RECV_ERR;
177+
} else {
178+
self->state = STATE_RECV;
179+
}
180+
181+
} else if (self->state == STATE_RECV) {
182+
if (data_bit) {
183+
self->bits |= data_bit << self->bitcount;
184+
self->parity = !self->parity;
185+
}
186+
++self->bitcount;
187+
if (self->bitcount >= 8) {
188+
self->state = STATE_RECV_PARITY;
189+
}
190+
191+
} else if (self->state == STATE_RECV_PARITY) {
192+
++self->bitcount;
193+
if (data_bit) {
194+
self->parity = !self->parity;
195+
}
196+
if (!self->parity) {
197+
self->last_errors |= ERROR_PARITY;
198+
self->state = STATE_RECV_ERR;
199+
} else {
200+
self->state = STATE_RECV_STOP;
201+
}
202+
203+
} else if (self->state == STATE_RECV_STOP) {
204+
++self->bitcount;
205+
if (! data_bit) {
206+
self->last_errors |= ERROR_STOPBIT;
207+
} else if (self->waiting_cmd_response) {
208+
self->cmd_response = self->bits;
209+
self->waiting_cmd_response = false;
210+
} else if (self->bufcount >= sizeof(self->buffer)) {
211+
self->last_errors |= ERROR_BUFFER;
212+
} else {
213+
self->buffer[self->bufposw] = self->bits;
214+
self->bufposw = (self->bufposw + 1) % sizeof(self->buffer);
215+
self->bufcount++;
216+
}
217+
self->state = STATE_IDLE;
218+
219+
} else if (self->state == STATE_RECV_ERR) {
220+
// just count the bits until idle
221+
if (++self->bitcount >= 10) {
222+
self->state = STATE_IDLE;
223+
}
224+
}
225+
}
226+
227+
void common_hal_ps2io_ps2_construct(ps2io_ps2_obj_t* self,
228+
const mcu_pin_obj_t* data_pin, const mcu_pin_obj_t* clk_pin) {
229+
clk_hi(self);
230+
data_hi(self);
231+
232+
self->clk_pin = (gpio_num_t)clk_pin->number;
233+
self->data_pin = (gpio_num_t)data_pin->number;
234+
self->state = STATE_IDLE;
235+
self->bufcount = 0;
236+
self->bufposr = 0;
237+
self->bufposw = 0;
238+
self->waiting_cmd_response = false;
239+
240+
claim_pin(clk_pin);
241+
claim_pin(data_pin);
242+
243+
// set config will enable the interrupt.
244+
ps2_set_config(self);
245+
}
246+
247+
bool common_hal_ps2io_ps2_deinited(ps2io_ps2_obj_t* self) {
248+
return self->clk_pin == GPIO_NUM_MAX;
249+
}
250+
251+
void common_hal_ps2io_ps2_deinit(ps2io_ps2_obj_t* self) {
252+
if (common_hal_ps2io_ps2_deinited(self)) {
253+
return;
254+
}
255+
if (self->handle) {
256+
esp_intr_free(self->handle);
257+
self->handle = NULL;
258+
}
259+
reset_pin_number(self->clk_pin);
260+
reset_pin_number(self->data_pin);
261+
self->clk_pin = GPIO_NUM_MAX;
262+
self->data_pin = GPIO_NUM_MAX;
263+
}
264+
265+
uint16_t common_hal_ps2io_ps2_get_len(ps2io_ps2_obj_t* self) {
266+
return self->bufcount;
267+
}
268+
269+
int16_t common_hal_ps2io_ps2_popleft(ps2io_ps2_obj_t* self) {
270+
common_hal_mcu_disable_interrupts();
271+
if (self->bufcount <= 0) {
272+
common_hal_mcu_enable_interrupts();
273+
return -1;
274+
}
275+
uint8_t b = self->buffer[self->bufposr];
276+
self->bufposr = (self->bufposr + 1) % sizeof(self->buffer);
277+
self->bufcount -= 1;
278+
common_hal_mcu_enable_interrupts();
279+
return b;
280+
}
281+
282+
uint16_t common_hal_ps2io_ps2_clear_errors(ps2io_ps2_obj_t* self) {
283+
common_hal_mcu_disable_interrupts();
284+
uint16_t errors = self->last_errors;
285+
self->last_errors = 0;
286+
common_hal_mcu_enable_interrupts();
287+
return errors;
288+
}
289+
290+
// Based upon TMK implementation of PS/2 protocol
291+
// https://github.com/tmk/tmk_keyboard/blob/master/tmk_core/protocol/ps2_interrupt.c
292+
293+
int16_t common_hal_ps2io_ps2_sendcmd(ps2io_ps2_obj_t* self, uint8_t b) {
294+
disable_interrupt(self);
295+
inhibit(self);
296+
delay_us(100);
297+
298+
/* RTS and start bit */
299+
data_lo(self);
300+
clk_hi(self);
301+
if (!wait_clk_lo(self, 10000)) {
302+
self->last_errors |= ERROR_TX_RTS;
303+
goto ERROR;
304+
}
305+
306+
bool parity = true;
307+
for (uint8_t i = 0; i < 8; i++) {
308+
delay_us(15);
309+
if (b & (1 << i)) {
310+
parity = !parity;
311+
data_hi(self);
312+
} else {
313+
data_lo(self);
314+
}
315+
if (!wait_clk_hi(self, 50)) {
316+
self->last_errors |= ERROR_TX_CLKHI;
317+
goto ERROR;
318+
}
319+
if (!wait_clk_lo(self, 50)) {
320+
self->last_errors |= ERROR_TX_CLKLO;
321+
goto ERROR;
322+
}
323+
}
324+
325+
delay_us(15);
326+
if (parity) {
327+
data_hi(self);
328+
} else {
329+
data_lo(self);
330+
}
331+
if (!wait_clk_hi(self, 50)) {
332+
self->last_errors |= ERROR_TX_CLKHI;
333+
goto ERROR;
334+
}
335+
if (!wait_clk_lo(self, 50)) {
336+
self->last_errors |= ERROR_TX_CLKLO;
337+
goto ERROR;
338+
}
339+
340+
/* Stop bit */
341+
delay_us(15);
342+
data_hi(self);
343+
344+
/* Ack */
345+
if (!wait_data_lo(self, 50)) {
346+
self->last_errors |= ERROR_TX_ACKDATA;
347+
goto ERROR;
348+
}
349+
if (!wait_clk_lo(self, 50)) {
350+
self->last_errors |= ERROR_TX_ACKCLK;
351+
goto ERROR;
352+
}
353+
354+
/* wait for idle state */
355+
if (!wait_clk_hi(self, 50)) {
356+
self->last_errors |= ERROR_TX_ACKCLK;
357+
goto ERROR;
358+
}
359+
if (!wait_data_hi(self, 50)) {
360+
self->last_errors |= ERROR_TX_ACKDATA;
361+
goto ERROR;
362+
}
363+
364+
/* Wait for response byte */
365+
self->waiting_cmd_response = true;
366+
idle(self);
367+
resume_interrupt(self);
368+
369+
for (int i = 0; i < 25; ++i) {
370+
delay_us(1000);
371+
common_hal_mcu_disable_interrupts();
372+
bool has_response = !self->waiting_cmd_response;
373+
uint8_t response = self->cmd_response;
374+
common_hal_mcu_enable_interrupts();
375+
376+
if (has_response) {
377+
return response;
378+
}
379+
}
380+
381+
/* No response */
382+
common_hal_mcu_disable_interrupts();
383+
self->waiting_cmd_response = false;
384+
self->last_errors |= ERROR_TX_NORESP;
385+
common_hal_mcu_enable_interrupts();
386+
return -1;
387+
388+
/* Other errors */
389+
ERROR:
390+
idle(self);
391+
resume_interrupt(self);
392+
return -1;
393+
}

0 commit comments

Comments
 (0)