|
@@ -20,6 +20,7 @@
|
20
|
20
|
#include "pico/stdlib.h"
|
21
|
21
|
#include "pico/binary_info.h"
|
22
|
22
|
#include "hardware/spi.h"
|
|
23
|
+#include "hardware/watchdog.h"
|
23
|
24
|
|
24
|
25
|
#include "config.h"
|
25
|
26
|
#include "log.h"
|
|
@@ -28,12 +29,15 @@
|
28
|
29
|
#include "pmw3360_srom.h"
|
29
|
30
|
#include "pmw3360.h"
|
30
|
31
|
|
|
32
|
+#define HEALTH_CHECK_INTERVAL_MS 1000
|
|
33
|
+
|
31
|
34
|
#if !defined(spi_default) || !defined(PICO_DEFAULT_SPI_SCK_PIN) || !defined(PICO_DEFAULT_SPI_TX_PIN) || !defined(PICO_DEFAULT_SPI_RX_PIN) || !defined(PICO_DEFAULT_SPI_CSN_PIN)
|
32
|
35
|
#error PMW3360 API requires a board with SPI pins
|
33
|
36
|
#endif
|
34
|
37
|
|
35
|
38
|
static volatile int32_t delta_x = 0, delta_y = 0;
|
36
|
39
|
static volatile bool mouse_motion = false;
|
|
40
|
+static uint32_t last_health_check = 0;
|
37
|
41
|
|
38
|
42
|
#ifdef PMW_IRQ_COUNTERS
|
39
|
43
|
static uint64_t pmw_irq_count_all = 0;
|
|
@@ -48,16 +52,24 @@ static uint64_t pmw_irq_count_rest3 = 0;
|
48
|
52
|
#endif // PMW_IRQ_COUNTERS
|
49
|
53
|
|
50
|
54
|
void pmw_print_status(void) {
|
|
55
|
+ bool com = pmw_is_alive();
|
|
56
|
+ if (com) {
|
|
57
|
+ println("Communication to PMW3360 is working");
|
|
58
|
+ } else {
|
|
59
|
+ println("ERROR: can not communicate to PMW3360");
|
|
60
|
+ }
|
|
61
|
+
|
51
|
62
|
#ifdef PMW_IRQ_COUNTERS
|
52
|
|
- print(" pmw_irq_cnt_all = %llu", pmw_irq_count_all);
|
53
|
|
- print(" pmw_irq_cnt_motion = %llu", pmw_irq_count_motion);
|
54
|
|
- print("pmw_irq_cnt_no_move = %llu", pmw_irq_count_no_motion);
|
55
|
|
- print("pmw_irq_cnt_surface = %llu", pmw_irq_count_on_surface);
|
56
|
|
- print(" pmw_irq_cnt_lifted = %llu", pmw_irq_count_lifted);
|
57
|
|
- print(" pmw_irq_cnt_run = %llu", pmw_irq_count_run);
|
58
|
|
- print(" pmw_irq_cnt_rest1 = %llu", pmw_irq_count_rest1);
|
59
|
|
- print(" pmw_irq_cnt_rest2 = %llu", pmw_irq_count_rest2);
|
60
|
|
- print(" pmw_irq_cnt_rest3 = %llu", pmw_irq_count_rest3);
|
|
63
|
+ println("Interrupt statistics:");
|
|
64
|
+ println(" pmw_irq_cnt_all = %llu", pmw_irq_count_all);
|
|
65
|
+ println(" pmw_irq_cnt_motion = %llu", pmw_irq_count_motion);
|
|
66
|
+ println("pmw_irq_cnt_no_move = %llu", pmw_irq_count_no_motion);
|
|
67
|
+ println("pmw_irq_cnt_surface = %llu", pmw_irq_count_on_surface);
|
|
68
|
+ println(" pmw_irq_cnt_lifted = %llu", pmw_irq_count_lifted);
|
|
69
|
+ println(" pmw_irq_cnt_run = %llu", pmw_irq_count_run);
|
|
70
|
+ println(" pmw_irq_cnt_rest1 = %llu", pmw_irq_count_rest1);
|
|
71
|
+ println(" pmw_irq_cnt_rest2 = %llu", pmw_irq_count_rest2);
|
|
72
|
+ println(" pmw_irq_cnt_rest3 = %llu", pmw_irq_count_rest3);
|
61
|
73
|
#endif // PMW_IRQ_COUNTERS
|
62
|
74
|
}
|
63
|
75
|
|
|
@@ -314,21 +326,24 @@ uint8_t pmw_get_sensitivity(void) {
|
314
|
326
|
return sense_y;
|
315
|
327
|
}
|
316
|
328
|
|
|
329
|
+static void pmw_irq_start(void) {
|
|
330
|
+ gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, true);
|
|
331
|
+}
|
|
332
|
+
|
|
333
|
+static void pmw_irq_stop(void) {
|
|
334
|
+ gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, false);
|
|
335
|
+}
|
|
336
|
+
|
317
|
337
|
static void pmw_irq_init(void) {
|
318
|
338
|
// setup MOTION pin interrupt to handle reading data
|
319
|
339
|
gpio_add_raw_irq_handler(PMW_MOTION_PIN, pmw_motion_irq);
|
320
|
|
- gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, true);
|
|
340
|
+ pmw_irq_start();
|
321
|
341
|
irq_set_enabled(IO_IRQ_BANK0, true);
|
322
|
342
|
|
323
|
343
|
// make MOTION pin available to picotool
|
324
|
344
|
bi_decl(bi_1pin_with_name(PMW_MOTION_PIN, "PMW3360 MOTION"));
|
325
|
345
|
}
|
326
|
346
|
|
327
|
|
-static void pmw_irq_stop(void) {
|
328
|
|
- gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, false);
|
329
|
|
- irq_set_enabled(IO_IRQ_BANK0, false);
|
330
|
|
-}
|
331
|
|
-
|
332
|
347
|
bool pmw_is_alive(void) {
|
333
|
348
|
bool r = true;
|
334
|
349
|
gpio_set_irq_enabled(PMW_MOTION_PIN, GPIO_IRQ_LEVEL_LOW, false);
|
|
@@ -343,12 +358,84 @@ bool pmw_is_alive(void) {
|
343
|
358
|
return r;
|
344
|
359
|
}
|
345
|
360
|
|
|
361
|
+ssize_t pmw_frame_capture(uint8_t *buff, size_t buffsize) {
|
|
362
|
+ if ((buffsize < PMW_FRAME_CAPTURE_LEN) || (buff == NULL)) {
|
|
363
|
+ debug("invalid or too small buffer (%u < %u)", buffsize, PMW_FRAME_CAPTURE_LEN);
|
|
364
|
+ return -1;
|
|
365
|
+ }
|
|
366
|
+
|
|
367
|
+ pmw_irq_stop();
|
|
368
|
+
|
|
369
|
+ // write 0 to Rest_En bit of Config2 register to disable Rest mode
|
|
370
|
+ pmw_write_register(REG_CONFIG2, 0x00);
|
|
371
|
+
|
|
372
|
+ // write 0x83 to Frame_Capture register
|
|
373
|
+ pmw_write_register(REG_FRAME_CAPTURE, 0x83);
|
|
374
|
+
|
|
375
|
+ // write 0xC5 to Frame_Capture register
|
|
376
|
+ pmw_write_register(REG_FRAME_CAPTURE, 0xC5);
|
|
377
|
+
|
|
378
|
+ // wait for 20ms
|
|
379
|
+ busy_wait_ms(20);
|
|
380
|
+
|
|
381
|
+ // continue burst read from Raw_data_Burst register until all 1296 raw data are transferred
|
|
382
|
+ pmw_read_register_burst(REG_RAW_DATA_BURST, buff, PMW_FRAME_CAPTURE_LEN);
|
|
383
|
+
|
|
384
|
+ return PMW_FRAME_CAPTURE_LEN;
|
|
385
|
+}
|
|
386
|
+
|
|
387
|
+#define PMW_DATA_DUMP_SAMPLES 5000
|
|
388
|
+
|
|
389
|
+void pmw_dump_data(void) {
|
|
390
|
+ struct pmw_motion_report buff[PMW_DATA_DUMP_SAMPLES];
|
|
391
|
+
|
|
392
|
+ println("Will now capture %u data samples from PMW3360", PMW_DATA_DUMP_SAMPLES);
|
|
393
|
+ println("Move trackball to generate some data!");
|
|
394
|
+
|
|
395
|
+ pmw_irq_stop();
|
|
396
|
+
|
|
397
|
+ for (size_t i = 0; i < PMW_DATA_DUMP_SAMPLES; i++) {
|
|
398
|
+ // wait until MOTION pin is set
|
|
399
|
+ while (gpio_get(PMW_MOTION_PIN)) {
|
|
400
|
+ watchdog_update();
|
|
401
|
+ }
|
|
402
|
+
|
|
403
|
+ buff[i] = pmw_motion_read();
|
|
404
|
+ }
|
|
405
|
+
|
|
406
|
+ println();
|
|
407
|
+ println("time,motion,observation,delta_x,delta_y,squal,raw_sum,raw_max,raw_min,shutter");
|
|
408
|
+ for (size_t i = 0; i < PMW_DATA_DUMP_SAMPLES; i++) {
|
|
409
|
+ watchdog_update();
|
|
410
|
+
|
|
411
|
+ uint16_t delta_x_raw = buff[i].delta_x_l | (buff[i].delta_x_h << 8);
|
|
412
|
+ uint16_t delta_y_raw = buff[i].delta_y_l | (buff[i].delta_y_h << 8);
|
|
413
|
+ uint16_t shutter_raw = buff[i].shutter_lower | (buff[i].shutter_upper << 8);
|
|
414
|
+
|
|
415
|
+ print("%llu,", to_us_since_boot(get_absolute_time()));
|
|
416
|
+ print("%u,", buff[i].motion);
|
|
417
|
+ print("%u,", buff[i].observation);
|
|
418
|
+ print("%ld,", convert_two_complement(delta_x_raw));
|
|
419
|
+ print("%ld,", convert_two_complement(delta_y_raw));
|
|
420
|
+ print("%u,", buff[i].squal);
|
|
421
|
+ print("%u,", buff[i].raw_data_sum);
|
|
422
|
+ print("%u,", buff[i].maximum_raw_data);
|
|
423
|
+ print("%u,", buff[i].minimum_raw_data);
|
|
424
|
+ println("%u", shutter_raw);
|
|
425
|
+ }
|
|
426
|
+ println();
|
|
427
|
+
|
|
428
|
+ pmw_irq_start();
|
|
429
|
+}
|
|
430
|
+
|
346
|
431
|
int pmw_init(void) {
|
|
432
|
+ // initializing takes a while (~160ms)
|
|
433
|
+ watchdog_update();
|
|
434
|
+
|
347
|
435
|
pmw_irq_stop();
|
348
|
436
|
pmw_spi_init();
|
349
|
437
|
|
350
|
438
|
uint8_t srom_id = pmw_power_up();
|
351
|
|
-
|
352
|
439
|
uint8_t prod_id = pmw_read_register(REG_PRODUCT_ID);
|
353
|
440
|
uint8_t inv_prod_id = pmw_read_register(REG_INVERSE_PRODUCT_ID);
|
354
|
441
|
uint16_t srom_checksum = pmw_srom_checksum();
|
|
@@ -368,13 +455,16 @@ int pmw_init(void) {
|
368
|
455
|
return -1;
|
369
|
456
|
}
|
370
|
457
|
|
371
|
|
- if (srom_id != pmw_fw_id) {
|
372
|
|
- debug("PMW3360 error: invalid SROM ID (0x%02X != 0x%02X)", srom_id, pmw_fw_id);
|
373
|
|
- return -1;
|
374
|
|
- }
|
|
458
|
+ if ((srom_id != pmw_fw_id) || (srom_checksum != pmw_fw_crc)) {
|
|
459
|
+ if (srom_id != pmw_fw_id) {
|
|
460
|
+ debug("PMW3360 error: invalid SROM ID (0x%02X != 0x%02X)", srom_id, pmw_fw_id);
|
|
461
|
+ }
|
|
462
|
+
|
|
463
|
+ if (srom_checksum != pmw_fw_crc) {
|
|
464
|
+ debug("PMW3360 error: invalid SROM CRC (0x%04X != 0x%04X)", srom_checksum, pmw_fw_crc);
|
|
465
|
+ }
|
375
|
466
|
|
376
|
|
- if (srom_checksum != pmw_fw_crc) {
|
377
|
|
- debug("PMW3360 error: invalid SROM CRC (0x%04X != 0x%04X)", srom_checksum, pmw_fw_crc);
|
|
467
|
+ debug("this may require a power-cycle to fix!");
|
378
|
468
|
return -1;
|
379
|
469
|
}
|
380
|
470
|
|
|
@@ -396,3 +486,14 @@ int pmw_init(void) {
|
396
|
486
|
|
397
|
487
|
return 0;
|
398
|
488
|
}
|
|
489
|
+
|
|
490
|
+void pmw_run(void) {
|
|
491
|
+ uint32_t now = to_ms_since_boot(get_absolute_time());
|
|
492
|
+ if (now >= (last_health_check + HEALTH_CHECK_INTERVAL_MS)) {
|
|
493
|
+ last_health_check = now;
|
|
494
|
+ if (!pmw_is_alive()) {
|
|
495
|
+ debug("PMW3360 is dead. resetting!");
|
|
496
|
+ reset_to_main();
|
|
497
|
+ }
|
|
498
|
+ }
|
|
499
|
+}
|