Mouse sensor testing
This commit is contained in:
parent
2de4c0638e
commit
273dbaa630
5 changed files with 225 additions and 49 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -5,4 +5,7 @@
|
|||
"titleBar.activeForeground": "#FCFCFE"
|
||||
},
|
||||
"rust-analyzer.check.allTargets": false,
|
||||
"rust-analyzer.cargo.features": [
|
||||
"serial"
|
||||
],
|
||||
}
|
|
@ -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)");
|
||||
}
|
||||
|
|
74
src/main.rs
74
src/main.rs
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue