diff --git a/Cargo.toml b/Cargo.toml index 6dcf380..41301ce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,3 +14,5 @@ defmt = "0.3.2" usb-device = "0.2.9" usbd-hid = "0.6.1" critical-section = "1.1.1" +embedded-hal = "0.2.7" +fugit = "0.3.6" diff --git a/src/main.rs b/src/main.rs index 9c6d897..a794317 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,8 @@ #![no_std] #![no_main] +mod mouse_sensor; + // Ensure we halt the program on panic (if we don't mention this crate it won't // be linked) use panic_halt as _; @@ -26,6 +28,8 @@ use usbd_hid::{ hid_class::HIDClass, }; +use crate::mouse_sensor::MouseSensor; + /// The USB Device Driver (shared with the interrupt). static mut USB_DEVICE: Option> = None; @@ -57,6 +61,19 @@ fn main() -> ! { .ok() .unwrap(); + // The single-cycle I/O block controls our GPIO pins + let sio = hal::Sio::new(pac.SIO); + + // Set the pins up according to their function on this particular board + let pins = rp_pico::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + + let mouse_sensor = MouseSensor::new(pins, &mut pac.RESETS, pac.SPI0, &clocks); + unsafe { USB_BUS = Some(UsbBusAllocator::new(UsbBus::new( pac.USBCTRL_REGS, diff --git a/src/mouse_sensor.rs b/src/mouse_sensor.rs new file mode 100644 index 0000000..547900d --- /dev/null +++ b/src/mouse_sensor.rs @@ -0,0 +1,88 @@ +use cortex_m::prelude::_embedded_hal_spi_FullDuplex; +use embedded_hal::digital::v2::OutputPin; +use fugit::HertzU32; +use rp_pico::{ + hal::{ + clocks::ClocksManager, + gpio::{ + self, + bank0::{Gpio2, Gpio3, Gpio4, Gpio5}, + Function, Output, Pin, PushPull, Spi, + }, + spi::{self, Enabled, Spi as SpiDevice}, + Clock, + }, + pac::{RESETS, SPI0}, + Pins, +}; + +pub struct MouseSensor { + _sclk: Pin>, + _mosi: Pin>, + _miso: Pin>, + cs: Pin>, + + spi: SpiDevice, +} + +impl MouseSensor { + const READ: u8 = 0x7F; + const WRITE: u8 = 0x80; + + pub fn new(pins: Pins, resets: &mut RESETS, spio: SPI0, clocks: &ClocksManager) -> Self { + // These are implicitly used by the spi driver if they are in the correct mode + let _sclk = pins.gpio2.into_mode::(); + let _mosi = pins.gpio3.into_mode::(); + let _miso = pins.gpio4.into_mode::(); + let mut cs = pins.gpio5.into_push_pull_output(); + + // Create an SPI driver instance for the SPI0 device + let spi = spi::Spi::<_, _, 8>::new(spio); + + // Exchange the uninitialised SPI driver for an initialised one + let spi = spi.init( + resets, + clocks.peripheral_clock.freq(), + HertzU32::from_raw(16_000_000u32), + &embedded_hal::spi::MODE_0, + ); + + cs.set_high().unwrap(); + + Self { + _sclk, + _mosi, + _miso, + cs, + + spi, + } + } + + fn access(&mut self, f: F) -> T + where + F: Fn(&mut Self) -> T, + { + self.cs.set_low().unwrap(); + + let res = f(self); + + self.cs.set_high().unwrap(); + + res + } + + pub fn read(&mut self, address: u8) -> u8 { + self.access(|me| { + me.spi.send(address & Self::READ).unwrap(); + me.spi.read().unwrap() + }) + } + + pub fn write(&mut self, address: u8, value: u8) { + self.access(|me| { + me.spi.send(address | Self::WRITE).unwrap(); + me.spi.send(value).unwrap(); + }); + } +}