|
@@ -21,7 +21,9 @@
|
21
|
21
|
#include "pico/binary_info.h"
|
22
|
22
|
#include "hardware/spi.h"
|
23
|
23
|
|
|
24
|
+#define PMW_PRINT_IDS
|
24
|
25
|
#define PMW_IRQ_COUNTERS
|
|
26
|
+//#define PMW_FEATURE_WIRELESS
|
25
|
27
|
|
26
|
28
|
#include "log.h"
|
27
|
29
|
#include "pmw3360_registers.h"
|
|
@@ -73,48 +75,68 @@ static inline void pmw_cs_deselect() {
|
73
|
75
|
}
|
74
|
76
|
|
75
|
77
|
static void pmw_write_register(uint8_t reg, uint8_t data) {
|
76
|
|
- uint8_t buf[2];
|
77
|
|
- buf[0] = reg | WRITE_BIT;
|
78
|
|
- buf[1] = data;
|
79
|
78
|
pmw_cs_select();
|
80
|
|
- spi_write_blocking(spi_default, buf, 2);
|
|
79
|
+
|
|
80
|
+ reg |= WRITE_BIT;
|
|
81
|
+ spi_write_blocking(spi_default, ®, 1);
|
|
82
|
+
|
|
83
|
+ busy_wait_us(15);
|
|
84
|
+
|
|
85
|
+ spi_write_blocking(spi_default, &data, 1);
|
|
86
|
+
|
|
87
|
+ busy_wait_us(20);
|
81
|
88
|
pmw_cs_deselect();
|
82
|
|
- sleep_ms(10);
|
|
89
|
+ busy_wait_us(100);
|
83
|
90
|
}
|
84
|
91
|
|
85
|
92
|
static uint8_t pmw_read_register(uint8_t reg) {
|
86
|
|
- uint8_t buf = 0;
|
87
|
|
- reg &= ~WRITE_BIT;
|
88
|
93
|
pmw_cs_select();
|
|
94
|
+
|
|
95
|
+ reg &= ~WRITE_BIT;
|
89
|
96
|
spi_write_blocking(spi_default, ®, 1);
|
90
|
|
- sleep_ms(10);
|
|
97
|
+
|
|
98
|
+ busy_wait_us(160);
|
|
99
|
+
|
|
100
|
+ uint8_t buf = 0;
|
91
|
101
|
spi_read_blocking(spi_default, 0, &buf, 1);
|
|
102
|
+
|
|
103
|
+ busy_wait_us(1);
|
92
|
104
|
pmw_cs_deselect();
|
93
|
|
- sleep_ms(10);
|
|
105
|
+ busy_wait_us(20);
|
|
106
|
+
|
94
|
107
|
return buf;
|
95
|
108
|
}
|
96
|
109
|
|
97
|
110
|
static void pmw_write_register_burst(uint8_t reg, const uint8_t *buf, uint16_t len) {
|
98
|
|
- reg |= WRITE_BIT;
|
99
|
111
|
pmw_cs_select();
|
|
112
|
+
|
|
113
|
+ reg |= WRITE_BIT;
|
100
|
114
|
spi_write_blocking(spi_default, ®, 1);
|
101
|
|
- sleep_us(15);
|
|
115
|
+
|
|
116
|
+ busy_wait_us(15);
|
|
117
|
+
|
102
|
118
|
for (uint16_t i = 0; i < len; i++) {
|
103
|
119
|
spi_write_blocking(spi_default, buf + i, 1);
|
104
|
|
- sleep_us(15);
|
|
120
|
+ busy_wait_us(15);
|
105
|
121
|
}
|
|
122
|
+
|
106
|
123
|
pmw_cs_deselect();
|
107
|
|
- sleep_us(1);
|
|
124
|
+
|
|
125
|
+ busy_wait_us(1);
|
108
|
126
|
}
|
109
|
127
|
|
110
|
128
|
static void pmw_read_register_burst(uint8_t reg, uint8_t *buf, uint16_t len) {
|
111
|
|
- reg &= ~WRITE_BIT;
|
112
|
129
|
pmw_cs_select();
|
|
130
|
+
|
|
131
|
+ reg &= ~WRITE_BIT;
|
113
|
132
|
spi_write_blocking(spi_default, ®, 1);
|
114
|
|
- sleep_ms(1);//sleep_us(15); // TODO tSRAD_MOTBR
|
|
133
|
+
|
|
134
|
+ busy_wait_us(35);
|
|
135
|
+
|
115
|
136
|
spi_read_blocking(spi_default, 0, buf, len);
|
|
137
|
+
|
116
|
138
|
pmw_cs_deselect();
|
117
|
|
- sleep_us(1);
|
|
139
|
+ busy_wait_us(1);
|
118
|
140
|
}
|
119
|
141
|
|
120
|
142
|
static uint8_t pmw_srom_download(void) {
|
|
@@ -125,17 +147,17 @@ static uint8_t pmw_srom_download(void) {
|
125
|
147
|
pmw_write_register(REG_SROM_ENABLE, 0x1D);
|
126
|
148
|
|
127
|
149
|
// Wait for 10 ms
|
128
|
|
- sleep_ms(10);
|
|
150
|
+ busy_wait_ms(10);
|
129
|
151
|
|
130
|
152
|
// Write 0x18 to SROM_Enable register again to start SROM Download
|
131
|
153
|
pmw_write_register(REG_SROM_ENABLE, 0x18);
|
132
|
154
|
|
133
|
|
- sleep_us(120);
|
|
155
|
+ busy_wait_us(120);
|
134
|
156
|
|
135
|
157
|
// Write SROM file into SROM_Load_Burst register, 1st data must start with SROM_Load_Burst address.
|
136
|
158
|
pmw_write_register_burst(REG_SROM_LOAD_BURST, pmw_fw_data, pmw_fw_length);
|
137
|
159
|
|
138
|
|
- sleep_us(200);
|
|
160
|
+ busy_wait_us(200);
|
139
|
161
|
|
140
|
162
|
// Read the SROM_ID register to verify the ID before any other register reads or writes
|
141
|
163
|
uint8_t srom_id = pmw_read_register(REG_SROM_ID);
|
|
@@ -143,11 +165,15 @@ static uint8_t pmw_srom_download(void) {
|
143
|
165
|
}
|
144
|
166
|
|
145
|
167
|
static uint8_t pmw_power_up(void) {
|
|
168
|
+ pmw_cs_deselect();
|
|
169
|
+ pmw_cs_select();
|
|
170
|
+ pmw_cs_deselect();
|
|
171
|
+
|
146
|
172
|
// Write 0x5A to Power_Up_Reset register
|
147
|
173
|
pmw_write_register(REG_POWER_UP_RESET, 0x5A);
|
148
|
174
|
|
149
|
175
|
// Wait for at least 50ms
|
150
|
|
- sleep_ms(50);
|
|
176
|
+ busy_wait_ms(50);
|
151
|
177
|
|
152
|
178
|
// Read from registers 0x02, 0x03, 0x04, 0x05 and 0x06 one time
|
153
|
179
|
for (uint8_t reg = REG_MOTION; reg <= REG_DELTA_Y_H; reg++) {
|
|
@@ -174,10 +200,10 @@ static uint16_t pmw_srom_checksum(void) {
|
174
|
200
|
pmw_write_register(REG_SROM_ENABLE, 0x15);
|
175
|
201
|
|
176
|
202
|
// Wait for at least 10 ms
|
177
|
|
- sleep_ms(10);
|
|
203
|
+ busy_wait_ms(10);
|
178
|
204
|
|
179
|
205
|
uint16_t data = pmw_read_register(REG_DATA_OUT_LOWER);
|
180
|
|
- data &= pmw_read_register(REG_DATA_OUT_UPPER) << 8;
|
|
206
|
+ data |= pmw_read_register(REG_DATA_OUT_UPPER) << 8;
|
181
|
207
|
return data;
|
182
|
208
|
}
|
183
|
209
|
|
|
@@ -204,6 +230,16 @@ static void pmw_spi_init(void) {
|
204
|
230
|
bi_decl(bi_1pin_with_name(PICO_DEFAULT_SPI_CSN_PIN, "SPI CS"));
|
205
|
231
|
}
|
206
|
232
|
|
|
233
|
+// TODO
|
|
234
|
+int16_t delta_x = 0, delta_y = 0;
|
|
235
|
+int convTwosComp(int b){
|
|
236
|
+ //Convert from 2's complement
|
|
237
|
+ if(b & 0x8000){
|
|
238
|
+ b = -1 * ((b ^ 0xffff) + 1);
|
|
239
|
+ }
|
|
240
|
+ return b;
|
|
241
|
+}
|
|
242
|
+
|
207
|
243
|
static void pmw_handle_interrupt(void) {
|
208
|
244
|
struct pmw_motion_report motion_report = pmw_motion_read();
|
209
|
245
|
|
|
@@ -234,13 +270,13 @@ static void pmw_handle_interrupt(void) {
|
234
|
270
|
}
|
235
|
271
|
#endif // PMW_IRQ_COUNTERS
|
236
|
272
|
|
237
|
|
- // TODO
|
|
273
|
+ delta_x += convTwosComp(motion_report.delta_x_l | (motion_report.delta_x_h << 8));
|
|
274
|
+ delta_y += convTwosComp(motion_report.delta_y_l | (motion_report.delta_y_h << 8));
|
238
|
275
|
}
|
239
|
276
|
|
240
|
277
|
static void pmw_motion_irq(void) {
|
241
|
278
|
if (gpio_get_irq_event_mask(PMW_MOTION_PIN) & GPIO_IRQ_EDGE_FALL) {
|
242
|
279
|
gpio_acknowledge_irq(PMW_MOTION_PIN, GPIO_IRQ_EDGE_FALL);
|
243
|
|
-
|
244
|
280
|
pmw_handle_interrupt();
|
245
|
281
|
}
|
246
|
282
|
}
|
|
@@ -252,29 +288,44 @@ int pmw_init(void) {
|
252
|
288
|
|
253
|
289
|
uint8_t prod_id = pmw_read_register(REG_PRODUCT_ID);
|
254
|
290
|
uint8_t inv_prod_id = pmw_read_register(REG_INVERSE_PRODUCT_ID);
|
255
|
|
- uint8_t rev_id = pmw_read_register(REG_REVISION_ID);
|
256
|
291
|
uint16_t srom_checksum = pmw_srom_checksum();
|
257
|
292
|
|
|
293
|
+#ifdef PMW_PRINT_IDS
|
|
294
|
+ uint8_t rev_id = pmw_read_register(REG_REVISION_ID);
|
|
295
|
+
|
258
|
296
|
debug("SROM ID: 0x%02X", srom_id);
|
259
|
297
|
debug("Product ID: 0x%02X", prod_id);
|
260
|
298
|
debug("~ Prod. ID: 0x%02X", inv_prod_id);
|
261
|
299
|
debug("Revision ID: 0x%02X", rev_id);
|
262
|
300
|
debug("SROM CRC: 0x%04X", srom_checksum);
|
|
301
|
+#endif // PMW_PRINT_IDS
|
263
|
302
|
|
264
|
303
|
if (prod_id != ((~inv_prod_id) & 0xFF)) {
|
265
|
304
|
debug("SPI communication error (0x%02X != ~0x%02X)", prod_id, inv_prod_id);
|
266
|
305
|
return -1;
|
267
|
306
|
}
|
268
|
307
|
|
|
308
|
+ if (srom_id != pmw_fw_id) {
|
|
309
|
+ debug("PMW3360 error: invalid SROM ID (0x%02X != 0x%02X)", srom_id, pmw_fw_id);
|
|
310
|
+ return -1;
|
|
311
|
+ }
|
|
312
|
+
|
|
313
|
+ if (srom_checksum != pmw_fw_crc) {
|
|
314
|
+ debug("PMW3360 error: invalid SROM CRC (0x%04X != 0x%04X)", srom_checksum, pmw_fw_crc);
|
|
315
|
+ return -1;
|
|
316
|
+ }
|
|
317
|
+
|
269
|
318
|
// Write 0x00 to Config2 register for wired mouse or 0x20 for wireless mouse design
|
270
|
|
-#ifdef FEATURE_WIRELESS
|
|
319
|
+#ifdef PMW_FEATURE_WIRELESS
|
271
|
320
|
pmw_write_register(REG_CONFIG2, 0x20);
|
272
|
|
-#else
|
|
321
|
+#else // ! PMW_FEATURE_WIRELESS
|
273
|
322
|
pmw_write_register(REG_CONFIG2, 0x00);
|
274
|
|
-#endif
|
|
323
|
+#endif // PMW_FEATURE_WIRELESS
|
275
|
324
|
|
276
|
325
|
// setup MOTION pin interrupt to handle reading data
|
277
|
326
|
gpio_add_raw_irq_handler(PMW_MOTION_PIN, pmw_motion_irq);
|
|
327
|
+ gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_EDGE_FALL, true);
|
|
328
|
+ irq_set_enabled(IO_IRQ_BANK0, true);
|
278
|
329
|
|
279
|
330
|
// make MOTION pin available to picotool
|
280
|
331
|
bi_decl(bi_1pin_with_name(PMW_MOTION_PIN, "PMW3360 MOTION"));
|