RKTK API Docs RKTK Home Repo

rktk_drivers_common/mouse/pmw3360/
mod.rs

1//! PMW3360 optical sensor driver.
2
3#![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, SpiDevice};
12use error::Pmw3360Error;
13use registers as reg;
14use rktk::drivers::interface::mouse::MouseDriver;
15
16mod timing {
17    /// NCS To SCLK Active
18    pub const NCS_SCLK: u32 = 120;
19}
20
21#[derive(Default, Debug)]
22#[cfg_attr(feature = "defmt", derive(defmt::Format))]
23pub struct BurstData {
24    pub motion: bool,
25    pub on_surface: bool,
26    pub op_mode: u8,
27    pub frame_data_first: bool,
28    pub dx: i16,
29    pub dy: i16,
30    pub surface_quality: u8,
31    pub raw_data_sum: u8,
32    pub max_raw_data: u8,
33    pub min_raw_data: u8,
34    pub shutter: u16,
35}
36
37pub struct Pmw3360<S: SpiDevice> {
38    spi: S,
39    in_burst_mode: bool,
40    cpi: u16,
41}
42
43impl<S: SpiDevice> Pmw3360<S> {
44    pub fn new(spi: S) -> Self {
45        Self {
46            spi,
47            in_burst_mode: false,
48            cpi: 1000, // Default CPI
49        }
50    }
51}
52
53impl<S: SpiDevice> MouseDriver for Pmw3360<S> {
54    type Error = Pmw3360Error<S::Error>;
55
56    async fn init(&mut self) -> Result<(), Self::Error> {
57        self.power_up().await
58    }
59
60    async fn read(&mut self) -> Result<(i8, i8), Self::Error> {
61        self.burst_read()
62            .await
63            .map(|data| (data.dx as i8, data.dy as i8))
64    }
65
66    async fn set_cpi(&mut self, cpi: u16) -> Result<(), Self::Error> {
67        self.set_cpi(cpi).await?;
68        Ok(())
69    }
70
71    async fn get_cpi(&mut self) -> Result<u16, Self::Error> {
72        Err(Self::Error::NotSupported)
73    }
74}
75
76impl<S: SpiDevice> Pmw3360<S> {
77    async fn write(&mut self, address: u8, data: u8) -> Result<(), Pmw3360Error<S::Error>> {
78        self.in_burst_mode = false;
79        self.spi
80            .transaction(&mut [
81                Operation::DelayNs(timing::NCS_SCLK),
82                // send adress of the register, with MSBit = 1 to indicate it's a write and send data
83                Operation::TransferInPlace(&mut [address | 0x80, data]),
84                // tSCLK-NCS (write)
85                Operation::DelayNs(35 * 1000),
86            ])
87            .await
88            .map_err(Pmw3360Error::Spi)?;
89
90        // tSWW/tSWR minus tSCLK-NCS (write)
91        Timer::after_micros(145).await;
92
93        Ok(())
94    }
95
96    async fn read(&mut self, address: u8) -> Result<u8, Pmw3360Error<S::Error>> {
97        self.in_burst_mode = false;
98        let mut buf = [0x00];
99        self.spi
100            .transaction(&mut [
101                Operation::DelayNs(timing::NCS_SCLK),
102                // send adress of the register, with MSBit = 0 to indicate it's a read
103                Operation::Write(&[address & 0x7f]),
104                // tSRAD
105                Operation::DelayNs(160 * 1000),
106                // read the data
107                Operation::Read(&mut buf),
108                // tSCLK-NCS (read)
109                Operation::DelayNs(120),
110            ])
111            .await
112            .map_err(Pmw3360Error::Spi)?;
113
114        //  tSRW/tSRR
115        Timer::after_micros(20).await;
116
117        Ok(buf[0])
118    }
119
120    pub async fn burst_read(&mut self) -> Result<BurstData, Pmw3360Error<S::Error>> {
121        if !self.in_burst_mode {
122            self.write(reg::MOTION_BURST, 0x00).await?;
123            self.in_burst_mode = true;
124        }
125
126        let mut data = [0u8; 12];
127
128        self.spi
129            .transaction(&mut [
130                Operation::DelayNs(timing::NCS_SCLK),
131                Operation::Write(&[reg::MOTION_BURST]),
132                // tSRAD-MOTBR
133                Operation::DelayNs(35 * 1000),
134                Operation::Read(&mut data),
135            ])
136            .await
137            .map_err(Pmw3360Error::Spi)?;
138
139        // tBEXIT
140        Timer::after_micros(1).await;
141
142        //combine the register values
143        let data = BurstData {
144            motion: (data[0] & 0x80) != 0,
145            on_surface: (data[0] & 0x08) == 0,
146            op_mode: (data[0] >> 1) & 0x03,
147            frame_data_first: data[0] & 0x01 != 0,
148            dx: ((data[3] as i16) << 8) | (data[2] as i16),
149            dy: ((data[5] as i16) << 8) | (data[4] as i16),
150            surface_quality: data[6],
151            raw_data_sum: data[7],
152            max_raw_data: data[8],
153            min_raw_data: data[9],
154            shutter: ((data[11] as u16) << 8) | (data[10] as u16),
155        };
156
157        // FIXME: This is a workaround for a phenomenon in which the PMW3360 sensor stacks with
158        // OP_MODE remaining at Rest1 and then stops moving.
159        // It is necessary to investigate whether this is hardware-specific or whether other programs are incorrect.
160        if data.motion && data.op_mode == 0x01 && data.on_surface && data.dx == 0 && data.dy == 0 {
161            rktk_log::warn!("Invalid motion detected. Performing reset:\n{:?}", data);
162            self.power_up().await?;
163        }
164
165        Ok(data)
166    }
167
168    pub async fn set_cpi(&mut self, cpi: u16) -> Result<(), Pmw3360Error<S::Error>> {
169        self.cpi = cpi;
170        let val: u16;
171        if cpi < 100 {
172            val = 0
173        } else if cpi > 12000 {
174            val = 0x77
175        } else {
176            val = (cpi - 100) / 100;
177        }
178        self.write(reg::CONFIG_1, val as u8).await?;
179        Ok(())
180    }
181
182    pub async fn get_cpi(&mut self) -> Result<u16, S::Error> {
183        let val = self.read(reg::CONFIG_1).await.unwrap_or_default() as u16;
184        Ok((val + 1) * 100)
185    }
186
187    pub async fn check_signature(&mut self) -> Result<bool, Pmw3360Error<S::Error>> {
188        let srom = self.read(reg::SROM_ID).await.unwrap_or(0);
189        let pid = self.read(reg::PRODUCT_ID).await.unwrap_or(0);
190        let ipid = self.read(reg::INVERSE_PRODUCT_ID).await.unwrap_or(0);
191
192        // signature for SROM 0x04
193        Ok(srom == 0x00 && pid == 0x42 && ipid == 0xBD)
194    }
195
196    #[allow(dead_code)]
197    pub async fn self_test(&mut self) -> Result<bool, Pmw3360Error<S::Error>> {
198        self.write(reg::SROM_ENABLE, 0x15).await?;
199        Timer::after_micros(10000).await;
200
201        let u = self.read(reg::DATA_OUT_UPPER).await.unwrap_or(0); // should be 0xBE
202        let l = self.read(reg::DATA_OUT_LOWER).await.unwrap_or(0); // should be 0xEF
203
204        Ok(u == 0xBE && l == 0xEF)
205    }
206
207    async fn power_up(&mut self) -> Result<(), Pmw3360Error<S::Error>> {
208        let is_valid_signature = self.power_up_inner().await?;
209        if is_valid_signature {
210            self.set_cpi(self.cpi).await?;
211            Ok(())
212        } else {
213            Err(Pmw3360Error::InvalidSignature)
214        }
215    }
216
217    async fn power_up_inner(&mut self) -> Result<bool, Pmw3360Error<S::Error>> {
218        // reset spi port
219        self.spi
220            .transaction(&mut [])
221            .await
222            .map_err(Pmw3360Error::Spi)?;
223
224        // Write to reset register
225        self.write(reg::POWER_UP_RESET, 0x5A).await?;
226
227        // Wait at least 50ms
228        Timer::after_millis(100).await;
229
230        // read registers 0x02 to 0x06
231        self.read(reg::MOTION).await?;
232        self.read(reg::DELTA_X_L).await?;
233        self.read(reg::DELTA_X_H).await?;
234        self.read(reg::DELTA_Y_L).await?;
235        self.read(reg::DELTA_Y_H).await?;
236
237        // perform SROM download
238        // self.srom_download().await?;
239
240        let is_valid_signature = self.check_signature().await.unwrap_or(false);
241
242        // Write 0x00 (rest disable) to Config2 register for wired mouse or 0x20 for
243        // wireless mouse design.
244        self.write(reg::CONFIG_2, 0x00).await?;
245
246        Timer::after_micros(100).await;
247
248        Ok(is_valid_signature)
249    }
250
251    // TODO: To implement srom download, access to cs pin is needed.
252    //
253    // async fn srom_download(&mut self) -> Result<(), Pmw3360Error<S::Error>> {
254    //     // Write 0 to Rest_En bit of Config2 register to disable Rest mode.
255    //     self.write(reg::CONFIG_2, 0x00).await?;
256    //
257    //     // write 0x1d in SROM_enable reg for initializing
258    //     self.write(reg::SROM_ENABLE, 0x1d).await?;
259    //
260    //     // wait for 10 ms
261    //     Timer::after_micros(10000).await;
262    //
263    //     // Write 0x18 to SROM_Enable register again to start SROM Download
264    //     self.write(reg::SROM_ENABLE, 0x18).await?;
265    //
266    //     self.spi
267    //         .transaction(&mut srom_tracking::FW_OPS)
268    //         .await
269    //         .map_err(Pmw3360Error::Spi)?;
270    //
271    //     Timer::after_micros(185).await;
272    //
273    //     Ok(())
274    // }
275}