Created
September 4, 2024 22:29
-
-
Save jepler/b3b639d222c6b31df01ddf141bdcc8d4 to your computer and use it in GitHub Desktop.
This file contains hidden or 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 | |
# 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.GP26 | |
debug_raw = const(True) | |
program = adafruit_pioasm.Program(""" | |
; from https://raw.githubusercontent.com/PaulW/rp2040-keyboard-converter/main/src/protocols/at-ps2/interface.pio, license: GPLv3 | |
; Pins: 0 = data, 1 = clock | |
init: | |
; Wait until CLK is high before we continue. Keyboards seem to pull this LOW briefly | |
; during power on. This prevents the first bit read being shifted in this scenario. | |
wait 1 pin 1 | |
check: | |
; Wait for incoming data, but jump to bitLoopOut if the Output Shift Register isn't empty | |
jmp !osre, bitLoopOut | |
jmp pin, check ; Loop back to check if pin high | |
; Receiving Data | |
; IBM AT: | |
; ____ 1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7 _ 8 _ 9 _ A _ B _____ | |
; CLK \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ | |
; ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ________ | |
; DAT \___/___X___X___X___X___X___X___X___X___/ | |
; S 0 1 2 3 4 5 6 7 P s | |
; Read Start bit | |
in pins, 1 | |
; Wait for Clock to go High | |
wait 1 pin 1 | |
; Set x to 9 (to read in 8 x Data bits, 1 x Parity and 1 x Stop bit) | |
set x, 9 | |
bitLoopIn: | |
; Wait for clock signal to go low | |
wait 0 pin 1 [1] | |
; Read data pin and store in pins register | |
in pins, 1 | |
; Wait for clock signal to go high | |
wait 1 pin 1 | |
; Decrement x and jump back to bitLoopIn if it's not zero | |
jmp x--, bitLoopIn | |
; Jump back to check now all data read | |
jmp check | |
bitLoopOut: | |
; Sending Data | |
; IBM AT: | |
; __ _ 1 _ 2 _ 3 _ 4 _ 5 _ 6 _ 7 _ 8 _ 9 _ A __ B ____ | |
; CLK \____/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ | |
; ______ ___ ___ ___ ___ ___ ___ ___ ___ ______ ____ | |
; DAT \___/___X___X___X___X___X___X___X___X___/ \___/ | |
; H R 0 1 2 3 4 5 6 7 P s ACK | |
; Set data pin low and configure pins | |
set pins, 0 | |
set pindirs 2 [14] ; Set data pin to output mode | |
set pindirs 1 [1] ; Set clock pin to input mode | |
; Set x to 8 (to write out 8 Data Bits and 1 Parity Bit) | |
set x, 8 | |
bitLoopOutLoop: | |
; Wait for clock signal to go low and start sending bit | |
wait 0 pin 1 [1] | |
out pins, 1 | |
; Wait for clock signal to go high | |
wait 1 pin 1 | |
; Decrement x and jump back to bitLoopOutLoop if it's not zero | |
jmp x--, bitLoopOutLoop | |
; Send stop bit | |
wait 0 pin 1 [1] | |
set pins, 1 | |
wait 1 pin 1 | |
; Wait for ACK to acknowledge | |
set pindirs, 0 ; Set data pin to input mode so we can read ACK | |
wait 0 pin 0 [1] | |
wait 1 pin 0 [5] | |
""", 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=11, | |
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 | |
def get_kbd_byte(): | |
sm.readinto(buf, swap=False) | |
r = (buf[0] >> 6) & 0xff | |
if debug_raw: | |
print(f"RAW {r:02x} {buf[0]:016b}") | |
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) | |
def write_cmd(*args): | |
for b0 in args: | |
p = parity(b0) | |
print(b0, p) | |
buf[0] = b0 | (parity(b0) << 8) | |
print(f"WRITE {b0:08b} {buf[0]:011b}") | |
sm.background_write(buf) | |
buf = array.array('H', [0]) | |
#write_cmd(0xed, 0xe0) | |
#raise SystemExit() | |
write_cmd(0xed, 0xe0) | |
offset = sm.offset | |
print(f"State machine loaded at {sm.offset}") | |
i = 7 | |
while True: | |
pc = sm.pc | |
print(f"{pc - offset:2d} [{pc:2d}]", end="\r") | |
if sm.in_waiting: | |
print(f"{get_kbd_byte():02x}") | |
#else: | |
# write_cmd(0xed, i << 5) | |
# i = (i + 1) & 0x7 | |
# time.sleep(.5) | |
#break | |
while True: | |
code = get_kbd_code() | |
print(f"{'BREAK' if code & 0x200 else 'MAKE':5} {code & 0x1ff:03x}") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment