Split mouse sensor implementation
This commit is contained in:
parent
f9f324475b
commit
a4a14fc1de
4 changed files with 143 additions and 93 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -8,4 +8,5 @@
|
|||
"rust-analyzer.cargo.features": [
|
||||
"serial"
|
||||
],
|
||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
||||
}
|
4
src/mouse_sensor/mod.rs
Normal file
4
src/mouse_sensor/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
mod spi_interface;
|
||||
mod wrapper;
|
||||
|
||||
pub use wrapper::MouseSensor;
|
|
@ -6,34 +6,34 @@ use fugit::{HertzU32, MegahertzU32};
|
|||
use rp_pico::{
|
||||
hal::{
|
||||
gpio::{
|
||||
self,
|
||||
bank0::{Gpio2, Gpio25, Gpio3, Gpio4, Gpio5},
|
||||
Function, Output, Pin, PushPull, PushPullOutput, Spi,
|
||||
bank0::{Gpio2, Gpio3, Gpio4, Gpio5},
|
||||
Function, Output, Pin, PushPull, Spi,
|
||||
},
|
||||
spi::{self, Enabled, Spi as SpiDevice},
|
||||
},
|
||||
pac::{RESETS, SPI0},
|
||||
Pins,
|
||||
};
|
||||
|
||||
pub struct MouseSensor<L>
|
||||
pub struct SpiPins {
|
||||
pub sclk: Pin<Gpio2, Function<Spi>>,
|
||||
pub mosi: Pin<Gpio3, Function<Spi>>,
|
||||
pub miso: Pin<Gpio4, Function<Spi>>,
|
||||
pub cs: Pin<Gpio5, Output<PushPull>>,
|
||||
}
|
||||
|
||||
pub struct SpiMouseSensor<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>,
|
||||
pins: SpiPins,
|
||||
|
||||
spi: SpiDevice<Enabled, SPI0, 8>,
|
||||
delay: Delay,
|
||||
|
||||
log: L,
|
||||
pub log: L,
|
||||
}
|
||||
|
||||
impl<L> MouseSensor<L>
|
||||
impl<L> SpiMouseSensor<L>
|
||||
where
|
||||
L: FnMut(&str),
|
||||
{
|
||||
|
@ -61,19 +61,13 @@ where
|
|||
const REG_SPI_MODE: u8 = 0x26;
|
||||
|
||||
pub fn new(
|
||||
pins: Pins,
|
||||
mut pins: SpiPins,
|
||||
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>();
|
||||
let _mosi = pins.gpio3.into_mode::<gpio::FunctionSpi>();
|
||||
let _miso = pins.gpio4.into_mode::<gpio::FunctionSpi>();
|
||||
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);
|
||||
|
||||
|
@ -85,59 +79,31 @@ where
|
|||
&embedded_hal::spi::MODE_2,
|
||||
);
|
||||
|
||||
if let Err(_err) = cs.set_low() {
|
||||
if let Err(_err) = pins.cs.set_low() {
|
||||
log("cs high failed");
|
||||
}
|
||||
|
||||
delay.delay_ms(2);
|
||||
|
||||
if let Err(_err) = cs.set_high() {
|
||||
if let Err(_err) = pins.cs.set_high() {
|
||||
log("cs high failed");
|
||||
}
|
||||
|
||||
let mut me = Self {
|
||||
_sclk,
|
||||
_mosi,
|
||||
_miso,
|
||||
cs,
|
||||
|
||||
led: pins.led.into_push_pull_output(),
|
||||
Self {
|
||||
pins,
|
||||
|
||||
spi,
|
||||
delay,
|
||||
|
||||
log,
|
||||
};
|
||||
|
||||
if me.led.set_high().is_err() {
|
||||
(me.log)("led high failed");
|
||||
}
|
||||
|
||||
// verify initialization
|
||||
loop {
|
||||
if me.verify_product_id_1() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if me.verify_product_id_2() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if me.led.set_low().is_err() {
|
||||
(me.log)("led low failed");
|
||||
}
|
||||
|
||||
me
|
||||
}
|
||||
|
||||
fn access<F, T>(&mut self, f: F) -> T
|
||||
where
|
||||
F: Fn(&mut Self) -> T,
|
||||
{
|
||||
if self.cs.set_low().is_err() {
|
||||
if self.pins.cs.set_low().is_err() {
|
||||
(self.log)("cs low failed");
|
||||
}
|
||||
|
||||
|
@ -145,7 +111,7 @@ where
|
|||
|
||||
let res = f(self);
|
||||
|
||||
if self.cs.set_high().is_err() {
|
||||
if self.pins.cs.set_high().is_err() {
|
||||
(self.log)("cs low failed");
|
||||
}
|
||||
|
||||
|
@ -154,7 +120,7 @@ where
|
|||
res
|
||||
}
|
||||
|
||||
pub fn read(&mut self, address: u8) -> u8 {
|
||||
fn read(&mut self, address: u8) -> u8 {
|
||||
loop {
|
||||
let res = self.access(|me| {
|
||||
if me.spi.send(address & Self::READ).is_err() {
|
||||
|
@ -180,7 +146,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
pub fn write(&mut self, address: u8, value: u8) {
|
||||
fn write(&mut self, address: u8, value: u8) {
|
||||
self.access(|me| {
|
||||
if me.spi.send(address | Self::WRITE).is_err() {
|
||||
(me.log)("send address (write) failed");
|
||||
|
@ -191,24 +157,12 @@ where
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn read_movement(&mut self) -> Option<(i8, i8)> {
|
||||
let (motion, x_overflow, y_overflow) = self.motion_detected();
|
||||
|
||||
if motion {
|
||||
if x_overflow || y_overflow {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x = self.delta_x();
|
||||
let y = self.delta_y();
|
||||
|
||||
Some((x, y))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<L> SpiMouseSensor<L>
|
||||
where
|
||||
L: FnMut(&str),
|
||||
{
|
||||
pub fn delta_x(&mut self) -> i8 {
|
||||
unsafe { mem::transmute(self.read(Self::REG_DELTA_X)) }
|
||||
}
|
||||
|
@ -217,16 +171,6 @@ where
|
|||
unsafe { mem::transmute(self.read(Self::REG_DELTA_Y)) }
|
||||
}
|
||||
|
||||
pub fn motion_detected(&mut self) -> (bool, bool, bool) {
|
||||
let reg = self.read(Self::REG_MOTION_STATUS);
|
||||
|
||||
let motion = (reg & 0b10000000) != 0;
|
||||
let x_overflow = (reg & 0b00010000) != 0;
|
||||
let y_overflow = (reg & 0b00001000) != 0;
|
||||
|
||||
(motion, x_overflow, y_overflow)
|
||||
}
|
||||
|
||||
pub fn product_id_1(&mut self) -> u8 {
|
||||
self.read(Self::REG_PRODUCT_ID1)
|
||||
}
|
||||
|
@ -239,15 +183,7 @@ where
|
|||
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()
|
||||
pub fn motion_status(&mut self) -> u8 {
|
||||
self.read(Self::REG_MOTION_STATUS)
|
||||
}
|
||||
}
|
109
src/mouse_sensor/wrapper.rs
Normal file
109
src/mouse_sensor/wrapper.rs
Normal file
|
@ -0,0 +1,109 @@
|
|||
use super::spi_interface::{SpiMouseSensor, SpiPins};
|
||||
|
||||
use cortex_m::delay::Delay;
|
||||
use embedded_hal::digital::v2::OutputPin;
|
||||
use fugit::HertzU32;
|
||||
use rp_pico::{
|
||||
hal::gpio::{self, bank0::Gpio25, Pin, PushPullOutput},
|
||||
pac::{RESETS, SPI0},
|
||||
Pins,
|
||||
};
|
||||
|
||||
pub struct MouseSensor<L>
|
||||
where
|
||||
L: FnMut(&str),
|
||||
{
|
||||
spi_device: SpiMouseSensor<L>,
|
||||
|
||||
led: Pin<Gpio25, PushPullOutput>,
|
||||
}
|
||||
|
||||
impl<L> MouseSensor<L>
|
||||
where
|
||||
L: FnMut(&str),
|
||||
{
|
||||
pub fn new(
|
||||
pins: Pins,
|
||||
resets: &mut RESETS,
|
||||
spio: SPI0,
|
||||
peripheral_clock: impl Into<HertzU32>,
|
||||
delay: Delay,
|
||||
log: L,
|
||||
) -> Self {
|
||||
// These are implicitly used by the spi driver if they are in the correct mode
|
||||
|
||||
let spi_pins = SpiPins {
|
||||
sclk: pins.gpio2.into_mode::<gpio::FunctionSpi>(),
|
||||
mosi: pins.gpio3.into_mode::<gpio::FunctionSpi>(),
|
||||
miso: pins.gpio4.into_mode::<gpio::FunctionSpi>(),
|
||||
cs: pins.gpio5.into_push_pull_output(),
|
||||
};
|
||||
|
||||
let led = pins.led.into_push_pull_output();
|
||||
let spi_device = SpiMouseSensor::new(spi_pins, resets, spio, peripheral_clock, delay, log);
|
||||
|
||||
let mut me = Self { spi_device, led };
|
||||
|
||||
if me.led.set_high().is_err() {
|
||||
(me.spi_device.log)("led high failed");
|
||||
}
|
||||
|
||||
// verify initialization
|
||||
loop {
|
||||
if me.verify_product_id_1() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
if me.verify_product_id_2() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if me.led.set_low().is_err() {
|
||||
(me.spi_device.log)("led low failed");
|
||||
}
|
||||
|
||||
me
|
||||
}
|
||||
|
||||
fn verify_product_id_1(&mut self) -> bool {
|
||||
const DEFAULT_VALUE: u8 = 0x30;
|
||||
|
||||
DEFAULT_VALUE == self.spi_device.product_id_1()
|
||||
}
|
||||
|
||||
fn verify_product_id_2(&mut self) -> bool {
|
||||
const DEFAULT_VALUE: u8 = 0x02;
|
||||
|
||||
DEFAULT_VALUE == self.spi_device.product_id_2()
|
||||
}
|
||||
|
||||
pub fn motion_detected(&mut self) -> (bool, bool, bool) {
|
||||
let reg = self.spi_device.motion_status();
|
||||
|
||||
let motion = (reg & 0b10000000) != 0;
|
||||
let x_overflow = (reg & 0b00010000) != 0;
|
||||
let y_overflow = (reg & 0b00001000) != 0;
|
||||
|
||||
(motion, x_overflow, y_overflow)
|
||||
}
|
||||
|
||||
pub fn read_movement(&mut self) -> Option<(i8, i8)> {
|
||||
let (motion, x_overflow, y_overflow) = self.motion_detected();
|
||||
|
||||
if motion {
|
||||
if x_overflow || y_overflow {
|
||||
return None;
|
||||
}
|
||||
|
||||
let x = self.spi_device.delta_x();
|
||||
let y = self.spi_device.delta_y();
|
||||
|
||||
Some((x, y))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue