Last active
September 28, 2024 02:31
-
-
Save jepler/7d2e3d53c1716d8307e98746c6cb0b76 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import array | |
import rp2pio | |
import board | |
import adafruit_pioasm | |
import time | |
import supervisor | |
# MIT licensed https://github.com/No0ne/ps2pico/blob/main/LICENSE | |
# https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-AT-Keyboard-Protocol | |
KBD_DATA = board.GP27 | |
KBD_CLK = board.GP28 | |
debug_raw = const(True) | |
if debug_raw: | |
log_last_direction = None | |
def log(direction, *args): | |
global log_last_direction | |
if log_last_direction != direction: | |
print() | |
print(direction, end="") | |
log_last_direction = direction | |
for a in args: | |
print(f" {a:02x}", end="") | |
else: | |
def log(*args): | |
return | |
program = adafruit_pioasm.Program.from_file("newps2.pio", build_debuginfo=True) | |
program.print_c_program("program") | |
cycles_per_bit = 11 | |
poll_rate_khz = 20_000 | |
sm = rp2pio.StateMachine(program.assembled, | |
first_in_pin = KBD_DATA, | |
first_out_pin = KBD_DATA, | |
first_set_pin = KBD_DATA, | |
jmp_pin = KBD_CLK, | |
in_pin_count = 2, | |
out_pin_count = 2, | |
set_pin_count = 2, | |
in_shift_right=True, | |
frequency=8_000_000, | |
exclusive_pin_use=False, | |
auto_pull=True, | |
pull_threshold=9, | |
auto_push=True, | |
push_threshold=10, | |
initial_out_pin_direction=0, | |
initial_set_pin_direction=0, | |
**program.pio_kwargs) | |
def parity(x): | |
x = x ^ (x >> 4) | |
x = x ^ (x >> 2) | |
x = x ^ (x >> 1) | |
return (x & 1) ^ 1 | |
assert parity(0) == 1 | |
def get_kbd_byte(): | |
log(f"pio pointer {sm.pc - sm.offset}") | |
sm.readinto(buf, swap=False) | |
r = (buf[0] >> 6) & 0xff | |
log("<", r) | |
return r | |
def get_kbd_code(): | |
val = get_kbd_byte() | |
is_extended = (val == 0xe0) | |
if is_extended: | |
val = get_kbd_byte() | |
is_break = (val == 0xf0) | |
if is_break: | |
val = get_kbd_byte() | |
return val | (is_extended << 8) | (is_break << 9) | |
pending_led_value = None | |
def set_kbd_leds(value): | |
global pending_led_value, pending_led_flag | |
if value != pending_led_value: | |
write_cmd(0xed) | |
pending_led_value = value | |
pending_led_flag = True | |
def write_cmd(*args): | |
for b0 in args: | |
p = parity(b0) | |
log(">", b0) | |
buf[0] = b0 | (parity(b0) << 8) | |
#wop = "".join(reversed(f"{buf[0]:09b}")) | |
#print(f"WRITE {b0:08b} wire order with parity: {wop}") | |
sm.background_write(buf) | |
buf = array.array('H', [0]) | |
offset = sm.offset | |
log(f"State machine loaded at {sm.offset}") | |
write_cmd(0xff) | |
b = get_kbd_byte() | |
if b != 0xfa: | |
raise SystemExit("keyboard didn't ack??") | |
b = get_kbd_byte() | |
if b != 0xaa: | |
raise SystemExit("selftest didn't go OK") | |
log("selftest done") | |
write_cmd(0xf0) | |
b = get_kbd_byte() | |
if b != 0xfa: | |
raise SystemExit("keyboard didn't ack??") | |
write_cmd(0x03) | |
b = get_kbd_byte() | |
if b != 0xfa: | |
raise SystemExit("keyboard didn't ack??") | |
log("set3 enabled") | |
write_cmd(0xfa) | |
b = get_kbd_byte() | |
if b != 0xfa: | |
raise SystemExit("keyboard didn't ack??") | |
log("set all typematic/make/break") | |
while True: | |
if sm.in_waiting: | |
b = get_kbd_byte() | |
if b == 0xFA: | |
if pending_led_flag: | |
write_cmd(pending_led_value) | |
pending_led_flag = False | |
else: | |
pass | |
#set_kbd_leds((supervisor.ticks_ms() >> 8) & 0x7) | |
while True: | |
code = get_kbd_code() | |
print(f"{'BREAK' if code & 0x200 else 'MAKE':5} {code & 0x1ff:03x}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; todo: use 'wait gpio' (or 'wait jmp' [rp2350]) so any pair of pins | |
;; can be used | |
;wait 1 pin 1 ; wait for keyboard to signal ready (not necessary?) | |
.wrap_target | |
start: | |
jmp !osre send_byte ; if a byte is pending to send, do that | |
jmp pin start ; otherwise wait for keyboard to send something | |
; keyboard has signaled start condition | |
set x 9 ; will receive 10 bits (data + parity + stop) | |
wait 1 pin 1 ; wait for clock pin to go high (discard start bit) | |
receive_bit: | |
wait 0 pin 1 | |
in pins 1 | |
wait 1 pin 1 | |
jmp x-- receive_bit | |
jmp start | |
send_byte: | |
set pins 0 ; will be pulling lines low selectively | |
set pindirs 2 [14] ; pull clock low to request to send | |
set pindirs 1 [1] ; set data pin to output & send "R" bit | |
set x 8 ; will send 9 bits (data + parity) | |
send_bit: | |
wait 0 pin 1 | |
out pins 1 | |
wait 1 pin 1 | |
jmp x-- send_bit | |
set pindirs 0 ; pins back to input mode | |
wait 0 pin 0 | |
wait 1 pin 0 ; wait for keyboard ACK | |
.wrap |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment