Compare commits
No commits in common. "5f9c5db37d984b4950c07b23499e62004c87b348" and "e555bcb9ff439e90f02da7cac3171605f0fd5608" have entirely different histories.
5f9c5db37d
...
e555bcb9ff
4 changed files with 93 additions and 143 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -8,5 +8,4 @@
|
||||||
"rust-analyzer.cargo.features": [
|
"rust-analyzer.cargo.features": [
|
||||||
"serial"
|
"serial"
|
||||||
],
|
],
|
||||||
"rust-analyzer.showUnlinkedFileNotification": false,
|
|
||||||
}
|
}
|
|
@ -6,34 +6,34 @@ use fugit::{HertzU32, MegahertzU32};
|
||||||
use rp_pico::{
|
use rp_pico::{
|
||||||
hal::{
|
hal::{
|
||||||
gpio::{
|
gpio::{
|
||||||
bank0::{Gpio2, Gpio3, Gpio4, Gpio5},
|
self,
|
||||||
Function, Output, Pin, PushPull, Spi,
|
bank0::{Gpio2, Gpio25, Gpio3, Gpio4, Gpio5},
|
||||||
|
Function, Output, Pin, PushPull, PushPullOutput, Spi,
|
||||||
},
|
},
|
||||||
spi::{self, Enabled, Spi as SpiDevice},
|
spi::{self, Enabled, Spi as SpiDevice},
|
||||||
},
|
},
|
||||||
pac::{RESETS, SPI0},
|
pac::{RESETS, SPI0},
|
||||||
|
Pins,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct SpiPins {
|
pub struct MouseSensor<L>
|
||||||
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
|
where
|
||||||
L: FnMut(&str),
|
L: FnMut(&str),
|
||||||
{
|
{
|
||||||
pins: SpiPins,
|
_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>,
|
spi: SpiDevice<Enabled, SPI0, 8>,
|
||||||
delay: Delay,
|
delay: Delay,
|
||||||
|
|
||||||
pub log: L,
|
log: L,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<L> SpiMouseSensor<L>
|
impl<L> MouseSensor<L>
|
||||||
where
|
where
|
||||||
L: FnMut(&str),
|
L: FnMut(&str),
|
||||||
{
|
{
|
||||||
|
@ -61,13 +61,19 @@ where
|
||||||
const REG_SPI_MODE: u8 = 0x26;
|
const REG_SPI_MODE: u8 = 0x26;
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
mut pins: SpiPins,
|
pins: Pins,
|
||||||
resets: &mut RESETS,
|
resets: &mut RESETS,
|
||||||
spio: SPI0,
|
spio: SPI0,
|
||||||
peripheral_clock: impl Into<HertzU32>,
|
peripheral_clock: impl Into<HertzU32>,
|
||||||
mut delay: Delay,
|
mut delay: Delay,
|
||||||
mut log: L,
|
mut log: L,
|
||||||
) -> Self {
|
) -> 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
|
// Create an SPI driver instance for the SPI0 device
|
||||||
let spi = spi::Spi::<_, _, 8>::new(spio);
|
let spi = spi::Spi::<_, _, 8>::new(spio);
|
||||||
|
|
||||||
|
@ -79,31 +85,59 @@ where
|
||||||
&embedded_hal::spi::MODE_2,
|
&embedded_hal::spi::MODE_2,
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Err(_err) = pins.cs.set_low() {
|
if let Err(_err) = cs.set_low() {
|
||||||
log("cs high failed");
|
log("cs high failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
delay.delay_ms(2);
|
delay.delay_ms(2);
|
||||||
|
|
||||||
if let Err(_err) = pins.cs.set_high() {
|
if let Err(_err) = cs.set_high() {
|
||||||
log("cs high failed");
|
log("cs high failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
let mut me = Self {
|
||||||
pins,
|
_sclk,
|
||||||
|
_mosi,
|
||||||
|
_miso,
|
||||||
|
cs,
|
||||||
|
|
||||||
|
led: pins.led.into_push_pull_output(),
|
||||||
|
|
||||||
spi,
|
spi,
|
||||||
delay,
|
delay,
|
||||||
|
|
||||||
log,
|
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
|
fn access<F, T>(&mut self, f: F) -> T
|
||||||
where
|
where
|
||||||
F: Fn(&mut Self) -> T,
|
F: Fn(&mut Self) -> T,
|
||||||
{
|
{
|
||||||
if self.pins.cs.set_low().is_err() {
|
if self.cs.set_low().is_err() {
|
||||||
(self.log)("cs low failed");
|
(self.log)("cs low failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +145,7 @@ where
|
||||||
|
|
||||||
let res = f(self);
|
let res = f(self);
|
||||||
|
|
||||||
if self.pins.cs.set_high().is_err() {
|
if self.cs.set_high().is_err() {
|
||||||
(self.log)("cs low failed");
|
(self.log)("cs low failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +154,7 @@ where
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read(&mut self, address: u8) -> u8 {
|
pub fn read(&mut self, address: u8) -> u8 {
|
||||||
loop {
|
loop {
|
||||||
let res = self.access(|me| {
|
let res = self.access(|me| {
|
||||||
if me.spi.send(address & Self::READ).is_err() {
|
if me.spi.send(address & Self::READ).is_err() {
|
||||||
|
@ -146,7 +180,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(&mut self, address: u8, value: u8) {
|
pub fn write(&mut self, address: u8, value: u8) {
|
||||||
self.access(|me| {
|
self.access(|me| {
|
||||||
if me.spi.send(address | Self::WRITE).is_err() {
|
if me.spi.send(address | Self::WRITE).is_err() {
|
||||||
(me.log)("send address (write) failed");
|
(me.log)("send address (write) failed");
|
||||||
|
@ -157,12 +191,24 @@ where
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<L> SpiMouseSensor<L>
|
pub fn read_movement(&mut self) -> Option<(i8, i8)> {
|
||||||
where
|
let (motion, x_overflow, y_overflow) = self.motion_detected();
|
||||||
L: FnMut(&str),
|
|
||||||
{
|
if motion {
|
||||||
|
if x_overflow || y_overflow {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let x = self.delta_x();
|
||||||
|
let y = self.delta_y();
|
||||||
|
|
||||||
|
Some((x, y))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn delta_x(&mut self) -> i8 {
|
pub fn delta_x(&mut self) -> i8 {
|
||||||
unsafe { mem::transmute(self.read(Self::REG_DELTA_X)) }
|
unsafe { mem::transmute(self.read(Self::REG_DELTA_X)) }
|
||||||
}
|
}
|
||||||
|
@ -171,6 +217,16 @@ where
|
||||||
unsafe { mem::transmute(self.read(Self::REG_DELTA_Y)) }
|
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 {
|
pub fn product_id_1(&mut self) -> u8 {
|
||||||
self.read(Self::REG_PRODUCT_ID1)
|
self.read(Self::REG_PRODUCT_ID1)
|
||||||
}
|
}
|
||||||
|
@ -183,7 +239,15 @@ where
|
||||||
self.read(Self::REG_OPERATION_MODE)
|
self.read(Self::REG_OPERATION_MODE)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn motion_status(&mut self) -> u8 {
|
fn verify_product_id_1(&mut self) -> bool {
|
||||||
self.read(Self::REG_MOTION_STATUS)
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
mod spi_interface;
|
|
||||||
mod wrapper;
|
|
||||||
|
|
||||||
pub use wrapper::MouseSensor;
|
|
|
@ -1,109 +0,0 @@
|
||||||
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