1#![no_std]
7
8use embedded_hal as hal;
13use hal::digital::v2::OutputPin;
14use embedded_hal::blocking::delay::DelayMs;
15
16#[cfg(feature = "rttdebug")]
17use panic_rtt_core::rprintln;
18
19#[derive(Debug)]
21pub enum Error<CommE, PinE> {
22 Comm(CommE),
24 Pin(PinE),
26
27 NoSignal,
29 UnknownChipId,
31 Unresponsive,
33}
34
35pub struct PMW3901<SPI, CSN> {
36 spi: SPI,
38 csn: CSN,
40}
41
42impl<SPI, CSN, CommE, PinE> PMW3901<SPI, CSN>
43 where
44 SPI: hal::blocking::spi::Write<u8, Error = CommE>
45 + hal::blocking::spi::Transfer<u8, Error = CommE>,
46 CSN: OutputPin<Error = PinE>,
47{
48
49
50 pub fn new(spi: SPI, csn: CSN) -> Self {
51 let mut inst = Self { spi: spi, csn: csn };
52 let _ = inst.csn.set_high();
54 inst
55 }
56
57 pub fn init(&mut self, delay_source: &mut impl DelayMs<u32>) -> Result<(), Error<CommE, PinE>> {
59 self.register_write(Register::PowerUpReset as u8, 0x5A)?;
61 delay_source.delay_ms(3000);
62
63 let cid = self.register_read(Register::ProductId)?;
65 let inv_cid = self.register_read(Register::InverseProductId)?;
66
67 if !(Self::PRODUCT_ID == cid && Self::INV_PRODUCT_ID == inv_cid) {
68 #[cfg(feature = "rttdebug")]
69 rprintln!("unknown cid 0x{:x} inv_cid 0x{:x} ", cid, inv_cid);
70 return Err(Error::UnknownChipId);
71 }
72
73 self.write_config_optimizations()?;
74 let _ = self.get_motion();
76
77 Ok(())
78 }
79
80 const SQUAL_THRESHOLD: u8 = 5;
82 const DIR_READ: u8 = 0x7f;
83 const MOTION_READ_BLOCK: [u8; 12] = [
84 Self::DIR_READ & (Register::Motion as u8), 0,
85 Self::DIR_READ & (Register::DeltaXL as u8), 0,
86 Self::DIR_READ & (Register::DeltaXH as u8), 0,
87 Self::DIR_READ & (Register::DeltaYL as u8), 0,
88 Self::DIR_READ & (Register::DeltaYH as u8), 0,
89 Self::DIR_READ & (Register::Squal as u8), 0
90 ];
91
92 pub fn get_motion(&mut self) -> Result< (i16, i16), Error<CommE, PinE>> {
94 let mut block: [u8; 12] = Self::MOTION_READ_BLOCK;
96 self.transfer_sequence(&mut block)?;
97 #[cfg(feature = "rttdebug")]
98 rprintln!("block: {:?}", block);
99
100 let squal = block[11];
101 if squal < Self::SQUAL_THRESHOLD {
102 return Err(Error::NoSignal);
103 }
104 let dx = ((block[5] as i16) << 8) | (block[3] as i16);
105 let dy = ((block[9] as i16) << 8) | (block[7] as i16);
106
107 Ok((dx, dy))
108 }
109
110 pub fn register_read(&mut self, reg: Register) -> Result<u8, Error<CommE, PinE>> {
112 let mut block: [u8; 2] = [reg as u8, 0];
113 self.transfer_sequence(&mut block)?;
114 Ok(block[1])
116 }
117
118 pub fn register_write(&mut self, reg: u8, val: u8) -> Result<(), Error<CommE, PinE>> {
120 let block: [u8; 2] = [reg, val];
121 self.write_block(&block)?;
122 Ok(())
123 }
124
125 fn transfer_sequence(&mut self, buffer: &mut [u8]) -> Result<(), Error<CommE, PinE>> {
127 self.csn.set_low().map_err(Error::Pin)?;
128 let rc = self.spi.transfer(buffer);
129 self.csn.set_high().map_err(Error::Pin)?;
130 rc.map_err(Error::Comm)?;
131
132 Ok(())
133 }
134
135 fn write_block(&mut self, block: &[u8]) -> Result<(), Error<CommE, PinE>> {
137 #[cfg(feature = "rttdebug")]
138 rprintln!("write {:x?} ", block);
139
140 self.csn.set_low().map_err(Error::Pin)?;
141 let rc = self.spi.write(block);
142 self.csn.set_high().map_err(Error::Pin)?;
143 rc.map_err(Error::Comm)?;
144
145 Ok(())
146 }
147
148 fn write_config_optimizations(&mut self) -> Result<(), Error<CommE, PinE>> {
151 self.register_write(0x7F, 0x00)?;
152 self.register_write(0x61, 0xAD)?;
153 self.register_write(0x7F, 0x03)?;
154 self.register_write(0x40, 0x00)?;
155 self.register_write(0x7F, 0x05)?;
156 self.register_write(0x41, 0xB3)?;
157 self.register_write(0x43, 0xF1)?;
158 self.register_write(0x45, 0x14)?;
159 self.register_write(0x5B, 0x32)?;
160 self.register_write(0x5F, 0x34)?;
161 self.register_write(0x7B, 0x08)?;
162 self.register_write(0x7F, 0x06)?;
163 self.register_write(0x44, 0x1B)?;
164 self.register_write(0x40, 0xBF)?;
165 self.register_write(0x4E, 0x3F)?;
166
167 Ok(())
168 }
169
170 const PRODUCT_ID: u8 = 0x49;
172 const INV_PRODUCT_ID: u8 = 0xB6;
173}
174
175
176
177#[repr(u8)]
178#[derive(Copy, Clone, Debug)]
179pub enum Register {
180 ProductId = 0x00,
181 RevisionId = 0x01,
182 Motion = 0x02,
183 DeltaXL = 0x03,
184 DeltaXH = 0x04,
185 DeltaYL = 0x05,
186 DeltaYH = 0x06,
187 Squal = 0x07,
188 RawDataSum = 0x08,
189 MaximumRawData = 0x09,
190 MinimumRawData = 0x0A,
191 ShutterLower = 0x0B,
192 ShutterUpper = 0x0C,
193 Observation = 0x15,
194 MotionBurst = 0x16,
195
196 PowerUpReset = 0x3A,
197 Shutdown = 0x3B,
198
199 RawDataGrab = 0x58,
200 RawDataGrabStatus = 0x59,
201
202 InverseProductId = 0x5F,
203}
204
205