Skip to content

Instantly share code, notes, and snippets.

@P1n3appl3
Last active December 29, 2023 07:17
Show Gist options
  • Save P1n3appl3/9211f13325fcb11d80c039c3d631bf5c to your computer and use it in GitHub Desktop.
Save P1n3appl3/9211f13325fcb11d80c039c3d631bf5c to your computer and use it in GitHub Desktop.
pi-pico screen latency tester
[package]
name = "pi-pico-keyboard"
version = "0.1.0"
edition = "2021"
[dependencies]
usb-device = "0.2"
usbd-hid = "0.6"
critical-section = "1"
cortex-m = "0.7"
cortex-m-rt = "0.7"
embedded-hal = "0.2"
panic-halt = "0.2"
rp-pico = "0.8"
rp2040-hal = "0.9"
[build]
target = "thumbv6m-none-eabi"
rustflags = ["-Clink-arg=--nmagic", "-Clink-arg=-Tlink.x"]
[target.thumbv6m-none-eabi]
runner = "elf2uf2-rs -d"
#![no_std]
#![no_main]
use embedded_hal::digital::v2::OutputPin;
use hal::{
clocks::UsbClock,
gpio,
pac::{self, interrupt, Interrupt, RESETS},
prelude::*,
usb::UsbBus,
};
use panic_halt as _;
use rp_pico::hal;
use usb_device::{class_prelude::*, prelude::*};
use usbd_hid::{
descriptor::{generator_prelude::*, KeyboardReport},
hid_class::HIDClass,
};
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
static mut USB_HID: Option<HIDClass<UsbBus>> = None;
// safety: must call with interrupts disabled
unsafe fn init_usb(
ctrl: pac::USBCTRL_REGS,
dpram: pac::USBCTRL_DPRAM,
usb_clock: UsbClock,
resets: &mut RESETS,
) {
let usb_bus = UsbBusAllocator::new(UsbBus::new(ctrl, dpram, usb_clock, true, resets));
// safety: we can mutate global statics since interrupts aren't enabled yet
let bus_ref = unsafe {
USB_BUS = Some(usb_bus);
USB_BUS.as_ref().unwrap()
};
let usb_hid = HIDClass::new(bus_ref, KeyboardReport::desc(), 60);
// safety: interrupts still arent enabled
unsafe {
USB_HID = Some(usb_hid);
}
let usb_dev = UsbDeviceBuilder::new(bus_ref, UsbVidPid(0x03f0, 0x020c))
.manufacturer("Pineapple")
.product("Press F")
.serial_number("TEST")
.device_class(0)
.build();
// safety: interrupts still arent enabled
unsafe {
USB_DEVICE = Some(usb_dev);
}
}
type LedPin = gpio::bank0::Gpio25;
fn init_led(
sio: pac::SIO,
io_bank0: pac::IO_BANK0,
pads_bank0: pac::PADS_BANK0,
resets: &mut RESETS,
) -> gpio::Pin<
LedPin,
gpio::FunctionSio<gpio::SioOutput>,
<LedPin as gpio::DefaultTypeState>::PullType,
> {
let pins =
rp_pico::Pins::new(io_bank0, pads_bank0, hal::Sio::new(sio).gpio_bank0, resets);
pins.led.into_push_pull_output()
}
#[rp_pico::entry]
fn main() -> ! {
let mut periph = pac::Peripherals::take().unwrap();
let mut watchdog = hal::Watchdog::new(periph.WATCHDOG);
let clocks = hal::clocks::init_clocks_and_plls(
rp_pico::XOSC_CRYSTAL_FREQ,
periph.XOSC,
periph.CLOCKS,
periph.PLL_SYS,
periph.PLL_USB,
&mut periph.RESETS,
&mut watchdog,
)
.ok()
.unwrap();
// safety: after initializing the usb stuff nothing will mutate those statics outside of a
// critical section
unsafe {
init_usb(
periph.USBCTRL_REGS,
periph.USBCTRL_DPRAM,
clocks.usb_clock,
&mut periph.RESETS,
);
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
}
let mut led_pin =
init_led(periph.SIO, periph.IO_BANK0, periph.PADS_BANK0, &mut periph.RESETS);
let core = pac::CorePeripherals::take().unwrap();
let mut delay =
cortex_m::delay::Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
loop {
delay.delay_ms(400);
let _ = send_key(Some(b'F'));
led_pin.set_high().unwrap();
delay.delay_ms(100);
let _ = send_key(None);
led_pin.set_low().unwrap();
}
}
const fn single_key(key: u8, modifiers: u8) -> KeyboardReport {
KeyboardReport {
modifier: modifiers,
reserved: 0,
leds: 0,
keycodes: [key, 0, 0, 0, 0, 0],
}
}
const fn keypress(key: u8) -> KeyboardReport {
match key {
b'a'..=b'z' => single_key(key - b'a' + 4, 0),
b'A'..=b'Z' => single_key(key - b'A' + 4, 0x02),
b'0'..=b'9' => single_key(key - b'0' + 30, 0),
_ => panic!("Unhandled key"),
}
}
fn send_key(key: Option<u8>) -> Result<usize, UsbError> {
let report = key.map(keypress).unwrap_or(single_key(0, 0));
critical_section::with(|_| unsafe {
USB_HID.as_mut().map(|hid| hid.push_input(&report))
})
.unwrap()
}
#[allow(non_snake_case)]
#[interrupt]
unsafe fn USBCTRL_IRQ() {
let usb_dev = USB_DEVICE.as_mut().unwrap();
let usb_hid = USB_HID.as_mut().unwrap();
usb_dev.poll(&mut [usb_hid]);
}
MEMORY {
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
RAM : ORIGIN = 0x20000000, LENGTH = 256K
}
EXTERN(BOOT2_FIRMWARE)
SECTIONS {
/* ### Boot loader */
.boot2 ORIGIN(BOOT2) :
{
KEEP(*(.boot2));
} > BOOT2
} INSERT BEFORE .text;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment