Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for PAW3204 Optical Sensor #17669

Merged
merged 10 commits into from
Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion builddefs/common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
SRC += $(QUANTUM_DIR)/mousekey.c
endif

VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi pmw3360 pmw3389 pimoroni_trackball custom
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3360 pmw3389 pimoroni_trackball custom
ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
$(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type)
Expand Down
18 changes: 18 additions & 0 deletions docs/feature_pointing_device.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,24 @@ Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when usi

**`POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE`** is not specific to Cirque trackpad; any pointing device with a lift/contact status can integrate this gesture into its driver. e.g. PMW3360 can use Lift_Stat from Motion register. Note that `POINTING_DEVICE_MOTION_PIN` cannot be used with this feature; continuous polling of `pointing_device_get_report()` is needed to generate glide reports.

### PAW 3204 Sensor

To use the paw 3204 sensor, add this to your `rules.mk`

```make
POINTING_DEVICE_DRIVER = paw3204
```

The paw 3204 sensor uses a serial type protocol for communication, and requires an additional light source.

| Setting | Description |
|--------------------|---------------------------------------------------------------------|
|`PAW3204_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. |
|`PAW3204_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. |

The CPI range is 400-1600, with supported values of (400, 500, 600, 800, 1000, 1200 and 1600). Defaults to 1000 CPI.


### Pimoroni Trackball

To use the Pimoroni Trackball module, add this to your `rules.mk`:
Expand Down
172 changes: 172 additions & 0 deletions drivers/sensors/paw3204.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* Copyright 2021 Gompa (@Gompa)
*
* 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
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

// https://github.com/shinoaliceKabocha/choco60_track/tree/master/keymaps/default

#include "paw3204.h"
#include "wait.h"
#include "debug.h"
#include "gpio.h"

#define REG_PID1 0x00
#define REG_PID2 0x01
#define REG_STAT 0x02
#define REG_X 0x03
#define REG_Y 0x04

#define REG_SETUP 0x06
#define REG_IMGQUAL 0x07
#define REG_IMGREC 0x0E
#define REG_IMGTRASH 0x0D

#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))

// CPI values
enum cpi_values {
CPI400, // 0b000
CPI500, // 0b001
CPI600, // 0b010
CPI800, // 0b011
CPI1000, // 0b100
CPI1200, // 0b101
CPI1600, // 0b110
};

uint8_t paw3204_serial_read(void);
void paw3204_serial_write(uint8_t reg_addr);
uint8_t paw3204_read_reg(uint8_t reg_addr);
void paw3204_write_reg(uint8_t reg_addr, uint8_t data);

void paw3204_init(void) {
setPinOutput(PAW3204_SCLK_PIN); // setclockpin to output
setPinInputHigh(PAW3204_SDIO_PIN); // set datapin input high

paw3204_write_reg(REG_SETUP, 0x86); // reset sensor and set 1600cpi
wait_us(5);

paw3204_read_reg(0x00); // read id
paw3204_read_reg(0x01); // read id2
// PAW3204_write_reg(REG_SETUP,0x06); // dont reset sensor and set cpi 1600
paw3204_write_reg(REG_IMGTRASH, 0x32); // write image trashhold
}

uint8_t paw3204_serial_read(void) {
setPinInput(PAW3204_SDIO_PIN);
uint8_t byte = 0;

for (uint8_t i = 0; i < 8; ++i) {
writePinLow(PAW3204_SCLK_PIN);
wait_us(1);

byte = (byte << 1) | readPin(PAW3204_SDIO_PIN);

writePinHigh(PAW3204_SCLK_PIN);
wait_us(1);
}

return byte;
}

void paw3204_serial_write(uint8_t data) {
writePinLow(PAW3204_SDIO_PIN);
setPinOutput(PAW3204_SDIO_PIN);

for (int8_t b = 7; b >= 0; b--) {
writePinLow(PAW3204_SCLK_PIN);
if (data & (1 << b)) {
writePinHigh(PAW3204_SDIO_PIN);
} else {
writePinLow(PAW3204_SDIO_PIN);
}
writePinHigh(PAW3204_SCLK_PIN);
}

wait_us(4);
}

report_paw3204_t paw3204_read(void) {
report_paw3204_t data = {0};

data.isMotion = paw3204_read_reg(REG_STAT) & (1 << 7); // check for motion only (bit 7 in field)
data.x = (int8_t)paw3204_read_reg(REG_X);
data.y = (int8_t)paw3204_read_reg(REG_Y);

return data;
}

void paw3204_write_reg(uint8_t reg_addr, uint8_t data) {
paw3204_serial_write(0b10000000 | reg_addr);
paw3204_serial_write(data);
}

uint8_t paw3204_read_reg(uint8_t reg_addr) {
paw3204_serial_write(reg_addr);
wait_us(5);
return paw3204_serial_read();
}

void paw3204_set_cpi(uint16_t cpi) {
uint8_t cpival = CPI1000;
if (cpi <= 450) {
cpival = CPI400;
} else if (cpi <= 550) {
cpival = CPI500;
} else if (cpi <= 700) {
cpival = CPI600;
} else if (cpi <= 900) {
cpival = CPI800;
} else if (cpi <= 1100) {
cpival = CPI1000;
} else if (cpi <= 1400) {
cpival = CPI1200;
} else if (cpi > 1400) {
cpival = CPI1600;
}
paw3204_write_reg(REG_SETUP, cpival);
}

uint16_t paw3204_get_cpi(void) {
uint16_t cpival = 1000;

switch (paw3204_read_reg(REG_SETUP) & 0b111) {
case CPI400:
cpival = 400;
break;
case CPI500:
cpival = 500;
break;
case CPI600:
cpival = 600;
break;
case CPI800:
cpival = 800;
break;
case CPI1000:
cpival = 1000;
break;
case CPI1200:
cpival = 1200;
break;
case CPI1600:
cpival = 1600;
break;
}
return cpival;
}

uint8_t read_pid_paw3204(void) {
return paw3204_read_reg(REG_PID1);
}
68 changes: 68 additions & 0 deletions drivers/sensors/paw3204.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* Copyright 2021 Gompa (@Gompa)
*
* 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
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include <stdint.h>
#include <stdbool.h>

#ifndef PAW3204_SCLK_PIN
# error "No clock pin defined -- missing PAW3204_SCLK_PIN"
#endif
#ifndef PAW3204_SDIO_PIN
# error "No data pin defined -- missing PAW3204_SDIO_PIN"
#endif

typedef struct {
int16_t x;
int16_t y;
bool isMotion;
} report_paw3204_t;

/**
* @brief Initializes the sensor so it is in a working state and ready to
* be polled for data.
*
* @return true Initialization was a success
* @return false Initialization failed, do not proceed operation
*/
void paw3204_init(void);

/**
* @brief Reads and clears the current delta, and motion register values on the
* given sensor.
*
* @return pmw33xx_report_t Current values of the sensor, if errors occurred all
* fields are set to zero
*/

report_paw3204_t paw3204_read(void);
/**
* @brief Sets the given CPI value the sensor. CPI is often refereed to
* as the sensors sensitivity. Values outside of the allowed range are
* constrained into legal values.
*
* @param cpi CPI value to set
*/
void paw3204_set_cpi(uint16_t cpi);

/**
* @brief Gets the currently set CPI value from the sensor. CPI is often
* refereed to as the sensors sensitivity.
*
* @return uint16_t Current CPI value of the sensor
*/
uint16_t paw3204_get_cpi(void);
2 changes: 2 additions & 0 deletions quantum/pointing_device.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
# include "drivers/sensors/cirque_pinnacle.h"
# include "drivers/sensors/cirque_pinnacle_gestures.h"
# include "pointing_device_gestures.h"
#elif defined(POINTING_DEVICE_DRIVER_paw3204)
# include "drivers/sensors/paw3204.h"
#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball)
# include "i2c_master.h"
# include "drivers/sensors/pimoroni_trackball.h"
Expand Down
21 changes: 21 additions & 0 deletions quantum/pointing_device_drivers.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#define CONSTRAIN_HID_XY(amt) ((amt) < XY_REPORT_MIN ? XY_REPORT_MIN : ((amt) > XY_REPORT_MAX ? XY_REPORT_MAX : (amt)))

// get_report functions should probably be moved to their respective drivers.

#if defined(POINTING_DEVICE_DRIVER_adns5050)
report_mouse_t adns5050_get_report(report_mouse_t mouse_report) {
report_adns5050_t data = adns5050_read_burst();
Expand Down Expand Up @@ -198,7 +199,27 @@ const pointing_device_driver_t pointing_device_driver = {
.get_cpi = cirque_pinnacle_get_cpi
};
// clang-format on
#elif defined(POINTING_DEVICE_DRIVER_paw3204)

report_mouse_t paw3204_get_report(report_mouse_t mouse_report) {
report_paw3204_t data = paw3204_read();
if (data.isMotion) {
# ifdef CONSOLE_ENABLE
dprintf("Raw ] X: %d, Y: %d\n", data.x, data.y);
# endif

mouse_report.x = data.x;
mouse_report.y = data.y;
}

return mouse_report;
}
const pointing_device_driver_t pointing_device_driver = {
.init = paw3204_init,
.get_report = paw3204_get_report,
.set_cpi = paw3204_set_cpi,
.get_cpi = paw3204_get_cpi,
};
#elif defined(POINTING_DEVICE_DRIVER_pimoroni_trackball)

mouse_xy_report_t pimoroni_trackball_adapt_values(clamp_range_t* offset) {
Expand Down