Mouse sensor testing

This commit is contained in:
hodasemi 2023-03-25 14:29:35 +01:00
parent 2de4c0638e
commit 273dbaa630
5 changed files with 225 additions and 49 deletions

View file

@ -5,4 +5,7 @@
"titleBar.activeForeground": "#FCFCFE"
},
"rust-analyzer.check.allTargets": false,
"rust-analyzer.cargo.features": [
"serial"
],
}

View file

@ -1,4 +1,7 @@
use crate::{serial::Serial, MouseInfoSender};
use crate::{
serial::{Commands, Serial},
MouseInfoSender,
};
use rp_pico as bsp;
@ -7,6 +10,7 @@ use bsp::{
clocks::ClocksManager,
pac,
pac::{interrupt, Interrupt},
rom_data::reset_to_usb_boot,
usb::UsbBus,
},
pac::{RESETS, USBCTRL_DPRAM, USBCTRL_REGS},
@ -19,12 +23,15 @@ static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
static mut USB_SERIAL: Option<Serial> = None;
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
pub struct CustomHID<'a> {
out_ep: EndpointOut<'a, UsbBus>,
in_ep: EndpointIn<'a, UsbBus>,
pub fn serial() -> &'static mut Serial<'static> {
unsafe { USB_SERIAL.as_mut().unwrap() }
}
impl<'a> CustomHID<'a> {
pub struct CustomHID {
c: u32,
}
impl CustomHID {
pub fn new(
usbctrl_reg: USBCTRL_REGS,
usbctrl_dpram: USBCTRL_DPRAM,
@ -58,20 +65,25 @@ impl<'a> CustomHID<'a> {
);
}
let (in_ep, out_ep) = unsafe {
unsafe {
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
(
USB_BUS.as_ref().unwrap().interrupt(64, poll_ms),
USB_BUS.as_ref().unwrap().interrupt(64, poll_ms),
)
pac::NVIC::unmask(Interrupt::SW0_IRQ);
};
Self { in_ep, out_ep }
Self { c: 0 }
}
pub fn serial<F>(&mut self, mut f: F)
where
F: FnMut(&mut Serial),
{
critical_section::with(|_| {
f(serial());
})
}
}
impl<'a> MouseInfoSender for CustomHID<'a> {
impl MouseInfoSender for CustomHID {
fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8) {
push_mouse_movement(MouseReport {
x,
@ -81,12 +93,24 @@ impl<'a> MouseInfoSender for CustomHID<'a> {
pan,
})
}
fn heart_beat(&mut self) {
self.c += 1;
if self.c == 1_000_000 {
self.c = 0;
if !(pac::NVIC::is_pending(Interrupt::SW0_IRQ)) {
pac::NVIC::pend(Interrupt::SW0_IRQ);
}
}
}
}
/// with interrupts disabled, to avoid a race hazard with the USB IRQ.
fn push_mouse_movement(report: MouseReport) {
critical_section::with(|_| unsafe {
let serial = USB_SERIAL.as_mut().unwrap();
critical_section::with(|_| {
let serial = serial();
serial.send_text("x");
serial.send_number(report.x, 10);
@ -101,6 +125,19 @@ fn push_mouse_movement(report: MouseReport) {
unsafe fn USBCTRL_IRQ() {
// Handle USB request
let usb_dev = USB_DEVICE.as_mut().unwrap();
let usb_hid = USB_SERIAL.as_mut().unwrap();
usb_dev.poll(&mut [usb_hid]);
let usb_hid = serial();
if usb_dev.poll(&mut [usb_hid]) {
if let Some(command) = usb_hid.read() {
match command {
Commands::Reset => reset_to_usb_boot(0, 0),
}
}
}
}
#[allow(non_snake_case)]
#[interrupt]
unsafe fn SW0_IRQ() {
serial().send_text("heartbeat (IRQ)");
}

View file

@ -1,24 +1,28 @@
#![no_std]
#![no_main]
#[cfg(features = "serial")]
#[cfg(feature = "serial")]
mod custom_hid;
#[cfg(not(features = "serial"))]
#[cfg(not(feature = "serial"))]
mod mouse_hid;
mod mouse_sensor;
mod serial;
#[cfg(features = "serial")]
use core::panic::PanicInfo;
use cortex_m::delay::Delay;
#[cfg(feature = "serial")]
use custom_hid::CustomHID;
#[cfg(not(features = "serial"))]
#[cfg(not(feature = "serial"))]
use mouse_hid::MouseHID;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _;
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
loop {}
}
use rp_pico as bsp;
@ -32,6 +36,7 @@ use crate::mouse_sensor::MouseSensor;
pub trait MouseInfoSender {
fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8);
fn heart_beat(&mut self);
}
#[entry]
@ -57,8 +62,9 @@ fn main() -> ! {
.unwrap();
let peripheral_clock = clocks.peripheral_clock.freq();
let delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
#[cfg(features = "serial")]
#[cfg(feature = "serial")]
let mut hid = CustomHID::new(
pac.USBCTRL_REGS,
pac.USBCTRL_DPRAM,
@ -67,7 +73,7 @@ fn main() -> ! {
10,
);
#[cfg(not(features = "serial"))]
#[cfg(not(feature = "serial"))]
let mut hid = MouseHID::new(
pac.USBCTRL_REGS,
pac.USBCTRL_DPRAM,
@ -87,11 +93,53 @@ fn main() -> ! {
&mut pac.RESETS,
);
let mut mouse_sensor = MouseSensor::new(pins, &mut pac.RESETS, pac.SPI0, peripheral_clock);
let mut mouse_sensor = MouseSensor::new(
pins,
&mut pac.RESETS,
pac.SPI0,
peripheral_clock,
delay,
|msg| {
#[cfg(feature = "serial")]
critical_section::with(|_| {
custom_hid::serial().send_text(msg);
});
},
);
// #[cfg(feature = "serial")]
// {
// hid.serial(|serial| {
// serial.send_number(mouse_sensor.product_id_1(), 10);
// serial.send_number(mouse_sensor.product_id_2(), 10);
// });
// }
let mut c = 0;
loop {
if let Some((x, y)) = mouse_sensor.read_movement() {
hid.send(x, y, 0, 0, 0);
// if let Some((x, y)) = mouse_sensor.read_movement() {
// hid.send(x, y, 0, 0, 0);
// }
c += 1;
if c == 10_000_000 {
c = 0;
#[cfg(feature = "serial")]
critical_section::with(|_| {
let serial = custom_hid::serial();
serial.send_text("---");
serial.send_number(mouse_sensor.operation_mode(), 10);
serial.send_text(" - ");
serial.send_number(0xB8, 10);
// custom_hid::serial().send_number(mouse_sensor.product_id_2(), 10);
});
}
// hid.heart_beat();
}
}

View file

@ -78,8 +78,6 @@ impl MouseHID {
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
}
let delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
Self { delay }
}
}
@ -95,6 +93,10 @@ impl MouseInfoSender for MouseHID {
})
.unwrap_or(0);
}
fn heart_beat(&mut self) {
// mouse hid does everything by itself
}
}
/// with interrupts disabled, to avoid a race hazard with the USB IRQ.

View file

@ -1,14 +1,14 @@
use core::mem;
use cortex_m::prelude::_embedded_hal_spi_FullDuplex;
use cortex_m::{delay::Delay, prelude::_embedded_hal_spi_FullDuplex};
use embedded_hal::digital::v2::OutputPin;
use fugit::HertzU32;
use fugit::{HertzU32, MegahertzU32};
use rp_pico::{
hal::{
gpio::{
self,
bank0::{Gpio2, Gpio3, Gpio4, Gpio5},
Function, Output, Pin, PushPull, Spi,
bank0::{Gpio2, Gpio25, Gpio3, Gpio4, Gpio5},
Function, Output, Pin, PushPull, PushPullOutput, Spi,
},
spi::{self, Enabled, Spi as SpiDevice},
},
@ -16,18 +16,29 @@ use rp_pico::{
Pins,
};
pub struct MouseSensor {
pub struct MouseSensor<L>
where
L: FnMut(&str),
{
_sclk: Pin<Gpio2, Function<Spi>>,
_mosi: Pin<Gpio3, Function<Spi>>,
_miso: Pin<Gpio4, Function<Spi>>,
cs: Pin<Gpio5, Output<PushPull>>,
led: Pin<Gpio25, PushPullOutput>,
spi: SpiDevice<Enabled, SPI0, 8>,
delay: Delay,
log: L,
}
impl MouseSensor {
const READ: u8 = 0x7F;
const WRITE: u8 = 0x80;
impl<L> MouseSensor<L>
where
L: FnMut(&str),
{
const READ: u8 = 0b0111_1111;
const WRITE: u8 = 0b1000_0000;
const REG_PRODUCT_ID1: u8 = 0x00;
const REG_PRODUCT_ID2: u8 = 0x01;
@ -54,6 +65,8 @@ impl MouseSensor {
resets: &mut RESETS,
spio: SPI0,
peripheral_clock: impl Into<HertzU32>,
mut delay: Delay,
mut log: L,
) -> Self {
// These are implicitly used by the spi driver if they are in the correct mode
let _sclk = pins.gpio2.into_mode::<gpio::FunctionSpi>();
@ -68,46 +81,95 @@ impl MouseSensor {
let spi = spi.init(
resets,
peripheral_clock,
HertzU32::from_raw(16_000_000u32),
&embedded_hal::spi::MODE_0,
MegahertzU32::from_raw(1).convert(),
&embedded_hal::spi::MODE_2,
);
cs.set_high().unwrap();
if let Err(_err) = cs.set_low() {
log("cs high failed");
}
Self {
delay.delay_ms(2);
if let Err(_err) = cs.set_high() {
log("cs high failed");
}
let mut me = Self {
_sclk,
_mosi,
_miso,
cs,
led: pins.led.into_push_pull_output(),
spi,
delay,
log,
};
if me.led.set_low().is_err() {
(me.log)("led low failed");
}
if !me.verify_product_id_1() || !me.verify_product_id_2() {
if me.led.set_high().is_err() {
(me.log)("led high failed");
}
}
me
}
fn access<F, T>(&mut self, f: F) -> T
where
F: Fn(&mut Self) -> T,
{
self.cs.set_low().unwrap();
if self.cs.set_low().is_err() {
(self.log)("cs low failed");
}
self.delay.delay_us(1);
let res = f(self);
self.cs.set_high().unwrap();
if self.cs.set_high().is_err() {
(self.log)("cs low failed");
}
self.delay.delay_us(2);
res
}
pub fn read(&mut self, address: u8) -> u8 {
self.access(|me| {
me.spi.send(address & Self::READ).unwrap();
me.spi.read().unwrap()
if me.spi.send(address & Self::READ).is_err() {
(me.log)("send address (read) failed");
}
me.delay.delay_us(50);
match me.spi.read() {
Ok(res) => res,
Err(_) => {
(me.log)("read failed");
0
}
}
})
}
pub fn write(&mut self, address: u8, value: u8) {
self.access(|me| {
me.spi.send(address | Self::WRITE).unwrap();
me.spi.send(value).unwrap();
if me.spi.send(address | Self::WRITE).is_err() {
(me.log)("send address (write) failed");
}
if me.spi.send(value).is_err() {
(me.log)("send value (write) failed");
}
});
}
@ -145,4 +207,28 @@ impl MouseSensor {
(motion, x_overflow, y_overflow)
}
pub fn product_id_1(&mut self) -> u8 {
self.read(Self::REG_PRODUCT_ID1)
}
pub fn product_id_2(&mut self) -> u8 {
self.read(Self::REG_PRODUCT_ID2)
}
pub fn operation_mode(&mut self) -> u8 {
self.read(Self::REG_OPERATION_MODE)
}
fn verify_product_id_1(&mut self) -> bool {
const DEFAULT_VALUE: u8 = 0x30;
DEFAULT_VALUE == self.product_id_1()
}
fn verify_product_id_2(&mut self) -> bool {
const DEFAULT_VALUE: u8 = 0x02;
DEFAULT_VALUE == self.product_id_2()
}
}