diff options
Diffstat (limited to 'drivers/sensors/pmw3360.c')
| -rw-r--r-- | drivers/sensors/pmw3360.c | 155 | 
1 files changed, 79 insertions, 76 deletions
| diff --git a/drivers/sensors/pmw3360.c b/drivers/sensors/pmw3360.c index 8c977be1c8..5f4d17a3f0 100644 --- a/drivers/sensors/pmw3360.c +++ b/drivers/sensors/pmw3360.c @@ -1,6 +1,7 @@  /* Copyright 2020 Christopher Courtney, aka Drashna Jael're  (@drashna) <[email protected]>   * Copyright 2019 Sunjun Kim   * Copyright 2020 Ploopy Corporation + * Copyright 2022 Ulrich Spörlein   *   * This program is free software: you can redistribute it and/or modify   * it under the terms of the GNU General Public License as published by @@ -83,7 +84,11 @@  #    define MAX_CPI 0x77  #endif -bool _inBurst = false; +static const pin_t pins[] = PMW3360_CS_PINS; +#define NUMBER_OF_SENSORS (sizeof(pins) / sizeof(pin_t)) + +// per-sensor driver state +static bool _inBurst[NUMBER_OF_SENSORS] = {0};  #ifdef CONSOLE_ENABLE  void print_byte(uint8_t byte) { @@ -92,18 +97,18 @@ void print_byte(uint8_t byte) {  #endif  #define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt))) -bool pmw3360_spi_start(void) { -    bool status = spi_start(PMW3360_CS_PIN, PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR); +bool pmw3360_spi_start(int8_t index) { +    bool status = spi_start(pins[index], PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR);      // tNCS-SCLK, 120ns      wait_us(1);      return status;  } -spi_status_t pmw3360_write(uint8_t reg_addr, uint8_t data) { -    pmw3360_spi_start(); +spi_status_t pmw3360_write(int8_t index, uint8_t reg_addr, uint8_t data) { +    pmw3360_spi_start(index);      if (reg_addr != REG_Motion_Burst) { -        _inBurst = false; +        _inBurst[index] = false;      }      // send address of the register, with MSBit = 1 to indicate it's a write @@ -114,13 +119,13 @@ spi_status_t pmw3360_write(uint8_t reg_addr, uint8_t data) {      wait_us(35);      spi_stop(); -    // tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound +    // tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but it looks like a safe lower bound      wait_us(145);      return status;  } -uint8_t pmw3360_read(uint8_t reg_addr) { -    pmw3360_spi_start(); +uint8_t pmw3360_read(int8_t index, uint8_t reg_addr) { +    pmw3360_spi_start(index);      // send adress of the register, with MSBit = 0 to indicate it's a read      spi_write(reg_addr & 0x7f);      // tSRAD (=160us) @@ -136,36 +141,62 @@ uint8_t pmw3360_read(uint8_t reg_addr) {      return data;  } -bool pmw3360_init(void) { -    setPinOutput(PMW3360_CS_PIN); +bool pmw3360_check_signature(int8_t index) { +    uint8_t pid      = pmw3360_read(index, REG_Product_ID); +    uint8_t iv_pid   = pmw3360_read(index, REG_Inverse_Product_ID); +    uint8_t SROM_ver = pmw3360_read(index, REG_SROM_ID); +    return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04 +} -    spi_init(); -    _inBurst = false; +void pmw3360_upload_firmware(int8_t index) { +    // Datasheet claims we need to disable REST mode first, but during startup +    // it's already disabled and we're not turning it on ... +    // pmw3360_write(index, REG_Config2, 0x00); // disable REST mode +    pmw3360_write(index, REG_SROM_Enable, 0x1d); -    spi_stop(); -    pmw3360_spi_start(); -    spi_stop(); +    wait_ms(10); + +    pmw3360_write(index, REG_SROM_Enable, 0x18); + +    pmw3360_spi_start(index); +    spi_write(REG_SROM_Load_Burst | 0x80); +    wait_us(15); -    pmw3360_write(REG_Shutdown, 0xb6); // Shutdown first -    wait_ms(300); +    for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) { +        spi_write(pgm_read_byte(firmware_data + i)); +#ifndef PMW3360_FIRMWARE_UPLOAD_FAST +        wait_us(15); +#endif +    } +    wait_us(200); -    pmw3360_spi_start(); +    pmw3360_read(index, REG_SROM_ID); +    pmw3360_write(index, REG_Config2, 0x00); +} + +bool pmw3360_init(int8_t index) { +    if (index >= NUMBER_OF_SENSORS) { +        return false; +    } +    spi_init(); + +    // power up, need to first drive NCS high then low. +    // the datasheet does not say for how long, 40us works well in practice. +    pmw3360_spi_start(index);      wait_us(40);      spi_stop();      wait_us(40); - -    // power up, need to first drive NCS high then low, see above. -    pmw3360_write(REG_Power_Up_Reset, 0x5a); +    pmw3360_write(index, REG_Power_Up_Reset, 0x5a);      wait_ms(50);      // read registers and discard -    pmw3360_read(REG_Motion); -    pmw3360_read(REG_Delta_X_L); -    pmw3360_read(REG_Delta_X_H); -    pmw3360_read(REG_Delta_Y_L); -    pmw3360_read(REG_Delta_Y_H); +    pmw3360_read(index, REG_Motion); +    pmw3360_read(index, REG_Delta_X_L); +    pmw3360_read(index, REG_Delta_X_H); +    pmw3360_read(index, REG_Delta_Y_L); +    pmw3360_read(index, REG_Delta_Y_H); -    pmw3360_upload_firmware(); +    pmw3360_upload_firmware(index);      spi_stop(); @@ -174,13 +205,13 @@ bool pmw3360_init(void) {      wait_ms(1); -    pmw3360_write(REG_Config2, 0x00); +    pmw3360_write(index, REG_Config2, 0x00); -    pmw3360_write(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127)); +    pmw3360_write(index, REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127)); -    pmw3360_write(REG_Lift_Config, PMW3360_LIFTOFF_DISTANCE); +    pmw3360_write(index, REG_Lift_Config, PMW3360_LIFTOFF_DISTANCE); -    bool init_success = pmw3360_check_signature(); +    bool init_success = pmw3360_check_signature(index);  #ifdef CONSOLE_ENABLE      if (init_success) {          dprintf("pmw3360 signature verified"); @@ -189,66 +220,38 @@ bool pmw3360_init(void) {      }  #endif -    writePinLow(PMW3360_CS_PIN); -      return init_success;  } -void pmw3360_upload_firmware(void) { -    // Datasheet claims we need to disable REST mode first, but during startup -    // it's already disabled and we're not turning it on ... -    // pmw3360_write(REG_Config2, 0x00);  // disable REST mode -    pmw3360_write(REG_SROM_Enable, 0x1d); - -    wait_ms(10); - -    pmw3360_write(REG_SROM_Enable, 0x18); - -    pmw3360_spi_start(); -    spi_write(REG_SROM_Load_Burst | 0x80); -    wait_us(15); - -    for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) { -        spi_write(pgm_read_byte(firmware_data + i)); -#ifndef PMW3360_FIRMWARE_UPLOAD_FAST -        wait_us(15); -#endif -    } -    wait_us(200); - -    pmw3360_read(REG_SROM_ID); -    pmw3360_write(REG_Config2, 0x00); -} - -bool pmw3360_check_signature(void) { -    uint8_t pid      = pmw3360_read(REG_Product_ID); -    uint8_t iv_pid   = pmw3360_read(REG_Inverse_Product_ID); -    uint8_t SROM_ver = pmw3360_read(REG_SROM_ID); -    return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04 -} - +// Only support reading the value from sensor #0, no one is using this anyway.  uint16_t pmw3360_get_cpi(void) { -    uint8_t cpival = pmw3360_read(REG_Config1); +    uint8_t cpival = pmw3360_read(0, REG_Config1);      return (uint16_t)((cpival + 1) & 0xFF) * CPI_STEP;  } +// Write same CPI to all sensors.  void pmw3360_set_cpi(uint16_t cpi) {      uint8_t cpival = constrain((cpi / CPI_STEP) - 1, 0, MAX_CPI); -    pmw3360_write(REG_Config1, cpival); +    for (size_t i = 0; i < NUMBER_OF_SENSORS; i++) { +        pmw3360_write(i, REG_Config1, cpival); +    }  } -report_pmw3360_t pmw3360_read_burst(void) { +report_pmw3360_t pmw3360_read_burst(int8_t index) {      report_pmw3360_t report = {0}; +    if (index >= NUMBER_OF_SENSORS) { +        return report; +    } -    if (!_inBurst) { +    if (!_inBurst[index]) {  #ifdef CONSOLE_ENABLE -        dprintf("burst on"); +        dprintf("burst on for index %d", index);  #endif -        pmw3360_write(REG_Motion_Burst, 0x00); -        _inBurst = true; +        pmw3360_write(index, REG_Motion_Burst, 0x00); +        _inBurst[index] = true;      } -    pmw3360_spi_start(); +    pmw3360_spi_start(index);      spi_write(REG_Motion_Burst);      wait_us(35); // waits for tSRAD_MOTBR @@ -261,7 +264,7 @@ report_pmw3360_t pmw3360_read_burst(void) {      report.mdy = spi_read();      if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird. -        _inBurst = false; +        _inBurst[index] = false;      }      spi_stop(); | 
