rktk_drivers_common/mouse/pmw3360/
mod.rs1#![allow(dead_code)]
4
5mod error;
6mod registers;
7mod srom_liftoff;
8mod srom_tracking;
9
10use embassy_time::Timer;
11use embedded_hal_async::spi::Operation;
12
13use error::Pmw3360Error;
14use registers as reg;
15use rktk::drivers::interface::mouse::MouseDriver;
16
17use crate::spi::{ExtendedSpi, IterOperation};
18
19mod timing {
20 pub const NCS_SCLK: u32 = 120;
22}
23
24#[derive(Default, Debug)]
25#[cfg_attr(feature = "defmt", derive(defmt::Format))]
26pub struct BurstData {
27 pub motion: bool,
28 pub on_surface: bool,
29 pub op_mode: u8,
30 pub frame_data_first: bool,
31 pub dx: i16,
32 pub dy: i16,
33 pub surface_quality: u8,
34 pub raw_data_sum: u8,
35 pub max_raw_data: u8,
36 pub min_raw_data: u8,
37 pub shutter: u16,
38}
39
40#[derive(Debug, Default)]
41#[cfg_attr(feature = "defmt", derive(defmt::Format))]
42pub enum Pmw3360Srom {
43 #[default]
44 None,
45 Liftoff,
46 Tracking,
47}
48
49impl Pmw3360Srom {
50 fn id(&self) -> u8 {
51 match self {
52 Pmw3360Srom::None => 0x00,
53 Pmw3360Srom::Liftoff => 0x81,
54 Pmw3360Srom::Tracking => 0x04,
55 }
56 }
57}
58
59#[derive(Debug)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61pub struct Pmw3360Config {
62 pub srom: Pmw3360Srom,
63 pub cpi: u16,
64 pub auto_reset: bool,
65}
66
67impl Default for Pmw3360Config {
68 fn default() -> Self {
69 Self { srom: Pmw3360Srom::default(), cpi: 1000, auto_reset: true }
70 }
71}
72
73pub struct Pmw3360<S: ExtendedSpi> {
83 spi_device: S,
84 in_burst_mode: bool,
85 config: Pmw3360Config,
86}
87
88impl<S: ExtendedSpi> Pmw3360<S> {
89 pub fn new(spi_device: S, config: Pmw3360Config) -> Self {
90 Self { spi_device, in_burst_mode: false, config }
91 }
92}
93
94impl<S: ExtendedSpi> MouseDriver for Pmw3360<S> {
95 type Error = Pmw3360Error<S::Error>;
96
97 async fn init(&mut self) -> Result<(), Self::Error> {
98 self.power_up().await
99 }
100
101 async fn read(&mut self) -> Result<(i8, i8), Self::Error> {
102 self.burst_read().await.map(|data| (data.dx as i8, data.dy as i8))
103 }
104
105 async fn set_cpi(&mut self, cpi: u16) -> Result<(), Self::Error> {
106 self.set_cpi(cpi).await?;
107 Ok(())
108 }
109
110 async fn get_cpi(&mut self) -> Result<u16, Self::Error> {
111 Err(Self::Error::NotSupported)
112 }
113}
114
115impl<S: ExtendedSpi> Pmw3360<S> {
116 async fn write(&mut self, address: u8, data: u8) -> Result<(), <Self as MouseDriver>::Error> {
117 self.in_burst_mode = false;
118 self.spi_device
119 .transaction(&mut [
120 Operation::DelayNs(timing::NCS_SCLK),
121 Operation::TransferInPlace(&mut [address | 0x80, data]),
123 Operation::DelayNs(35 * 1000),
125 ])
126 .await
127 .map_err(Pmw3360Error::Spi)?;
128
129 Timer::after_micros(145).await;
131
132 Ok(())
133 }
134
135 async fn read(&mut self, address: u8) -> Result<u8, <Self as MouseDriver>::Error> {
136 self.in_burst_mode = false;
137 let mut buf = [0x00];
138 self.spi_device
139 .transaction(&mut [
140 Operation::DelayNs(timing::NCS_SCLK),
141 Operation::Write(&[address & 0x7f]),
143 Operation::DelayNs(160 * 1000),
145 Operation::Read(&mut buf),
147 Operation::DelayNs(120),
149 ])
150 .await
151 .map_err(Pmw3360Error::Spi)?;
152
153 Timer::after_micros(20).await;
155
156 Ok(buf[0])
157 }
158
159 pub async fn burst_read(&mut self) -> Result<BurstData, <Self as MouseDriver>::Error> {
160 if !self.in_burst_mode {
161 self.write(reg::MOTION_BURST, 0x00).await?;
162 self.in_burst_mode = true;
163 }
164
165 let mut data = [0u8; 12];
166
167 self.spi_device
168 .transaction(&mut [
169 Operation::DelayNs(timing::NCS_SCLK),
170 Operation::Write(&[reg::MOTION_BURST]),
171 Operation::DelayNs(35 * 1000),
173 Operation::Read(&mut data),
174 ])
175 .await
176 .map_err(Pmw3360Error::Spi)?;
177
178 Timer::after_micros(1).await;
180
181 let data = BurstData {
183 motion: (data[0] & 0x80) != 0,
184 on_surface: (data[0] & 0x08) == 0,
185 op_mode: (data[0] >> 1) & 0x03,
186 frame_data_first: data[0] & 0x01 != 0,
187 dx: ((data[3] as i16) << 8) | (data[2] as i16),
188 dy: ((data[5] as i16) << 8) | (data[4] as i16),
189 surface_quality: data[6],
190 raw_data_sum: data[7],
191 max_raw_data: data[8],
192 min_raw_data: data[9],
193 shutter: ((data[11] as u16) << 8) | (data[10] as u16),
194 };
195
196 if data.motion
200 && data.op_mode == 0x01
201 && data.on_surface
202 && data.dx == 0
203 && data.dy == 0
204 && self.config.auto_reset
205 {
206 rktk_log::warn!("Invalid motion detected. Performing reset:\n{:?}", data);
207 self.power_up().await?;
208 }
209
210 Ok(data)
211 }
212
213 pub async fn set_cpi(&mut self, cpi: u16) -> Result<(), <Self as MouseDriver>::Error> {
214 self.config.cpi = cpi;
215 let val: u16;
216 if cpi < 100 {
217 val = 0
218 } else if cpi > 12000 {
219 val = 0x77
220 } else {
221 val = (cpi - 100) / 100;
222 }
223 self.write(reg::CONFIG_1, val as u8).await?;
224 Ok(())
225 }
226
227 pub async fn get_cpi(&mut self) -> Result<u16, <Self as MouseDriver>::Error> {
228 let val = self.read(reg::CONFIG_1).await.unwrap_or_default() as u16;
229 Ok((val + 1) * 100)
230 }
231
232 pub async fn check_signature(&mut self) -> Result<bool, <Self as MouseDriver>::Error> {
233 let srom = self.read(reg::SROM_ID).await.unwrap_or(0);
234 let pid = self.read(reg::PRODUCT_ID).await.unwrap_or(0);
235 let ipid = self.read(reg::INVERSE_PRODUCT_ID).await.unwrap_or(0);
236
237 Ok(srom == self.config.srom.id() && pid == 0x42 && ipid == 0xBD)
238 }
239
240 #[allow(dead_code)]
241 pub async fn self_test(&mut self) -> Result<bool, <Self as MouseDriver>::Error> {
242 self.write(reg::SROM_ENABLE, 0x15).await?;
243 Timer::after_micros(10000).await;
244
245 let u = self.read(reg::DATA_OUT_UPPER).await.unwrap_or(0); let l = self.read(reg::DATA_OUT_LOWER).await.unwrap_or(0); Ok(u == 0xBE && l == 0xEF)
249 }
250
251 async fn power_up(&mut self) -> Result<(), <Self as MouseDriver>::Error> {
252 let is_valid_signature = self.power_up_inner().await?;
253 if is_valid_signature {
254 self.set_cpi(self.config.cpi).await?;
255 Ok(())
256 } else {
257 Err(Pmw3360Error::InvalidSignature)
258 }
259 }
260
261 async fn power_up_inner(&mut self) -> Result<bool, <Self as MouseDriver>::Error> {
262 self.spi_device.transaction(&mut []).await.map_err(Pmw3360Error::Spi)?;
264
265 self.write(reg::POWER_UP_RESET, 0x5A).await?;
267
268 Timer::after_millis(100).await;
270
271 self.read(reg::MOTION).await?;
273 self.read(reg::DELTA_X_L).await?;
274 self.read(reg::DELTA_X_H).await?;
275 self.read(reg::DELTA_Y_L).await?;
276 self.read(reg::DELTA_Y_H).await?;
277
278 self.srom_download().await?;
280
281 let is_valid_signature = self.check_signature().await.unwrap_or(false);
282
283 self.write(reg::CONFIG_2, 0x00).await?;
286
287 Timer::after_micros(100).await;
288
289 Ok(is_valid_signature)
290 }
291
292 async fn srom_download(&mut self) -> Result<(), <Self as MouseDriver>::Error> {
293 let fw = match self.config.srom {
294 Pmw3360Srom::None => {
295 rktk_log::info!("SROM download skipped: no SROM selected");
296 return Ok(());
297 }
298 Pmw3360Srom::Liftoff => &srom_liftoff::FW,
299 Pmw3360Srom::Tracking => &srom_tracking::FW,
300 };
301 if !self.spi_device.transaction_iter_supported() {
302 rktk_log::warn!("SROM download skipped: transaction_iter not supported");
303 return Ok(());
304 }
305
306 self.write(reg::CONFIG_2, 0x00).await?;
308
309 self.write(reg::SROM_ENABLE, 0x1d).await?;
311
312 Timer::after_micros(10000).await;
314
315 self.write(reg::SROM_ENABLE, 0x18).await?;
317
318 let operations = [IterOperation::Write(reg::SROM_LOAD_BURST | 0x80)].into_iter().chain(
319 fw.iter()
320 .flat_map(|byte| [IterOperation::Write(*byte), IterOperation::DelayNs(15 * 1000)]),
321 );
322
323 self.spi_device.transaction_iter(operations).await.map_err(Pmw3360Error::Spi)?;
324
325 Timer::after_micros(185).await;
326
327 let srom_id = self.read(reg::SROM_ID).await?;
328 if srom_id != self.config.srom.id() {
329 rktk_log::error!("SROM Download failed. ID: 0x{:02x}", srom_id);
330 return Err(Pmw3360Error::InvalidSignature);
331 }
332 rktk_log::debug!("SROM Download succeeded. ID: 0x{:02x}", srom_id);
333
334 Ok(())
335 }
336}