6.8 KiB
USB4VC Technical Notes / Make Your Own Protocol Card
Get USB4VC | Official Discord | Getting Started | Table of Contents
This document contains technical information about how USB4VC works. Please read the whole article if you're planning to make your own Protocol Cards.
Linux Input Event Codes
First of all, how does USB4VC read from KB/Mouse/Gamepads in the first place?
The answer is Linux Input Event Codes. Here's a very simplified description:
- Connected input devices show up in
/dev/inputas files:
$ ls /dev/input/
event0 event1 event2 mice mouse0 mouse1
-
Reading from one of those files returns input events. Try
cat /dev/input/mice! -
On RPi, 16 Bytes are returned each time there is an event. They are arranged as follows:
| Byte | Name |
|---|---|
| 0-7 | Timestamp |
| 8-9 | Event Type |
| 10-11 | Event Code |
| 12-15 | Event Value |
-
A list of all Event Type, Code and Values can be found here, set a bookmark if you're making your own P-Card!
-
Keyboard keys and mouse/gamepad buttons are EV_KEY type, mouse moments are EV_REL (relative) type, and joystick movements are EV_ABS (absolute) type.
-
Once you know the Event Type, you can look up Event Code to see which key/button/axes is being updated.
-
Event Value will be 1 (pressed) or 0 (released) for buttons, and a signed value for relative or absolute axes.
-
Here's a good article that goes into a bit more details.
-
You can install
evtestand see what your device is returning in real time. -
USB4VC reads those events from all input devices, processes them, and send them out to the Protocol Card.
Hardware Pinout
The Protocol Card connector directly maps to the Raspberry Pi Header, although the pins are flipped around.
Most pins are already in use:
-
Protocol Card and OLED screen shares the same SPI bus, with different CS of course.
-
Pin 22 is used to reset the P-Card, pin 32 for putting the microcontroller in bootloader mode for firmware updates.
-
Pin 3 and 5 are connected to microcontroller I2C lines for firmware updates.
-
A CH340 TTL-Serial-to-USB chip converts RPi serial (Pin 8 and 10) to USB-C on the Baseboard, currently unused.
-
Pin 36 is P-Card-to-Baseboard interrupt pin, details in next section.
-
5V current should not exceed 2A.
-
3.3V current should not exceed 600mA.
SPI Communication Protocol
Raspberri Pi communicates with Protocol Card through SPI. Here's a quick introduction if you're unfamiliar.
RPi is master, P-card is slave. SCLK is 2MHz.
Mode 0 is used. CPOL=0 (CLK idle low), CPHA=0 (data valid on CLK rising edge).
RPi and P-Card communicates via fixed-length 32-byte packets.
Detailed description of messaging protocol can be found in this document, note that there are multiple pages.
Here is a sample capture of pressing U on the keyboard:
-
32 Bytes are sent in a single CS activation.
-
SCLK is 2MHz, the entire transmission take around 290uS.
Here is a close-up of the first few bytes:
Compare to the keyboard tab in the document:
P-Card Interrupt Handling
When Protocol Card has data for RPi, it should prepare the SPI buffer, and switch its interrupt pin to HIGH (Pin 36).
Upon detecting this change, RPi will send out an ACK message. Upon receiving, the P-Card switches the interrupt pin to LOW.
RPi will then send out another ACK (or NOP) message to shift the data from P-Card to itself.
Here is a sample capture:
Currently this feature is only used for changing keyboard LEDs.
Sample SPI Message Captures
More sample captures can be found here.
Click one and press Download.
Open with Saleae Logic app.
Latency Information
Input latency can be introduced during all stages of input chain. Using keyboard as example, we have:
-
Step 1: Switch physically depressed
-
Step 2: Keyboard sends out event on USB/Bluetooth
-
Step 3: Raspberry Pi processes the event and informs Protocol Card
-
Step 4: Protocol Card sends out the keystroke to retro computer
-
Step 5: Retro computer responds to the keystroke.
The part we're interested in is Step 3 and 4, as any time spent here is the additional delay from USB4VC.
To accurately measure the delay, I used a logic analyzer connecting to keyboard USB lines and PS/2 output on the IBM PC Protocol Card. Here is the delay in action:
From the keystroke appearing on USB, to keystroke appearing on PS/2, it took 487 microseconds.
Zoomed out capture with multiple keypresses:
I tested out different generations of Raspberry Pis, and here is the result:
| RPi Generation | Avg. Latency |
|---|---|
| 2 | 1ms |
| 3 | 0.63ms |
| 4 | 0.5ms |
You can find the capture files here, open with saleae app, search PID ACK for USB input events, more info in this video
Developing your own Protocol Card
USB4VC will send out keyboard and mouse event on SPI regardless of whether a protocol card is inserted or not. Although it will display appropriate options for switching protocols if the protocol card ID is recognized.
SPI Format, AVR based arduino probably wont work, suggested to use STM32, include link.
RPi Header pinout, explain what each pin does.
Current limits etc.
Questions or Comments?
Feel free to ask in official Discord Chatroom, raise a Github issue, DM on Twitter, or email dekunukem gmail.com!






