Răsfoiți Sursa

Merge remote-tracking branch 'origin/develop' into xap

QMK Bot 5 luni în urmă
părinte
comite
f381d1d255

+ 3 - 1
builddefs/common_features.mk

@@ -129,7 +129,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
     MOUSE_ENABLE := yes
     MOUSE_ENABLE := yes
 endif
 endif
 
 
-VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick azoteq_iqs5xx cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 paw3222 pmw3320 pmw3360 pmw3389 pimoroni_trackball custom
+VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick azoteq_iqs5xx cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 paw3222 pmw3320 pmw3325 pmw3360 pmw3389 pimoroni_trackball custom
 ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
 ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
     ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
     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)
         $(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type)
@@ -163,6 +163,8 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
             SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c
             SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c
         else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), paw3222)
         else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), paw3222)
             SPI_DRIVER_REQUIRED = yes
             SPI_DRIVER_REQUIRED = yes
+        else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pmw3325)
+            SPI_DRIVER_REQUIRED = yes
         else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball)
         else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball)
             I2C_DRIVER_REQUIRED = yes
             I2C_DRIVER_REQUIRED = yes
         else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),)
         else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),)

+ 17 - 0
docs/features/pointing_device.md

@@ -320,6 +320,23 @@ The PMW3320 sensor uses a serial type protocol for communication, and requires a
 
 
 The CPI range is 500-3500, in increments of 250. Defaults to 1000 CPI.
 The CPI range is 500-3500, in increments of 250. Defaults to 1000 CPI.
 
 
+### PMW-3325 Sensor
+
+To use the PMW-3325 sensor, add this to your `rules.mk`:
+
+```make
+POINTING_DEVICE_DRIVER = pmw3325
+```
+
+The following pins must be defined in `config.h`:
+
+| Setting (`config.h`)  | Description                                                        | Default                      |
+| --------------------- | ------------------------------------------------------------------ | ---------------------------- |
+| `PMW3325_CS_PIN`      | (Required) The pin connected to the chip select pin of the sensor. | `POINTING_DEVICE_CS_PIN`     |
+| `PMW3325_SPI_DIVISOR` | (Required) The SPI clock divisor. This is dependent on your MCU.   | _not defined_                |
+
+The CPI range is 100-5000, in increments of 100. Defaults to 2000 CPI.
+
 ### PMW 3360 and PMW 3389 Sensor
 ### PMW 3360 and PMW 3389 Sensor
 
 
 This drivers supports both the PMW 3360 and PMW 3389 sensor as well as multiple sensors of the same type _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards).
 This drivers supports both the PMW 3360 and PMW 3389 sensor as well as multiple sensors of the same type _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards).

+ 179 - 0
drivers/sensors/pmw3325.c

@@ -0,0 +1,179 @@
+// Copyright 2024 Colin Lam (Ploopy Corporation)
+// Copyright 2026 HorrorTroll <https://github.com/HorrorTroll>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "pmw3325.h"
+#include "wait.h"
+#include "gpio.h"
+#include "spi_master.h"
+#include "pointing_device_internal.h"
+
+#define MSB1 0x80
+#define MSB0 0x7F
+
+const pointing_device_driver_t pmw3325_pointing_device_driver = {
+    .init       = pmw3325_init,
+    .get_report = pmw3325_get_report,
+    .set_cpi    = pmw3325_set_cpi,
+    .get_cpi    = pmw3325_get_cpi,
+};
+
+// Convert a 16-bit twos complement binary-represented number into a
+// signed 16-bit integer.
+static int16_t convert_twoscomp_16(uint8_t high, uint8_t low) {
+    uint16_t data = (high << 8) | low;
+
+    if ((data & 0x8000) == 0x8000) {
+        return -32768 + (data & 0x7FFF);
+    } else {
+        return data;
+    }
+}
+
+void pmw3325_write(uint8_t reg_addr, uint8_t data) {
+    spi_start(PMW3325_CS_PIN, false, 3, PMW3325_SPI_DIVISOR);
+    wait_us(1); // tNCS_SCLK
+    spi_write(reg_addr | MSB1);
+    wait_us(180); // tSRAD
+    spi_write(data);
+    wait_us(1); // tSCLK_NCS
+    spi_stop();
+    wait_us(20); // tSRR
+}
+
+uint8_t pmw3325_read(uint8_t reg_addr) {
+    spi_start(PMW3325_CS_PIN, false, 3, PMW3325_SPI_DIVISOR);
+    wait_us(1); // tNCS_SCLK
+    spi_write(reg_addr & MSB0);
+    wait_us(180); // tSRAD
+    uint8_t data = spi_read();
+    wait_us(1); // tSCLK_NCS
+    spi_stop();
+    wait_us(20); // tSRR
+
+    return data;
+}
+
+bool pmw3325_init(void) {
+    wait_ms(50);
+    gpio_set_pin_output(PMW3325_CS_PIN);
+
+    // CS must be kept high at power-up stage for at least 1ms
+    gpio_write_pin_low(PMW3325_CS_PIN);
+    wait_ms(10);
+    gpio_write_pin_high(PMW3325_CS_PIN);
+
+    spi_init();
+
+    // reboot
+    pmw3325_write(0x3A, 0x5A);
+    wait_ms(10);
+
+    pmw3325_write(0x18, 0x39);
+
+    if (!pmw3325_check_signature()) {
+        return false;
+    }
+
+    // read a burst, then discard
+    pmw3325_read(0x02);
+    pmw3325_read(0x03);
+    pmw3325_read(0x04);
+    pmw3325_read(0x05);
+    pmw3325_read(0x06);
+
+    // initialize
+    pmw3325_write(0x78, 0x80);
+    pmw3325_write(0x79, 0x80);
+    pmw3325_write(0x14, 0x80);
+    pmw3325_write(0x20, 0x40);
+    pmw3325_write(0x1A, 0x40);
+    pmw3325_write(0x47, 0x00);
+    pmw3325_write(0x48, 0x01);
+    pmw3325_write(0x60, 0x01);
+    pmw3325_write(0x69, 0x03);
+    pmw3325_write(0x1D, 0x90);
+    pmw3325_write(0x1B, 0x2E);
+    pmw3325_write(0x24, 0x05);
+    pmw3325_write(0x56, 0x00);
+    pmw3325_write(0x2C, 0x8A);
+    pmw3325_write(0x2D, 0x58);
+    pmw3325_write(0x40, 0x80);
+    pmw3325_write(0x7F, 0x01);
+    pmw3325_write(0x7A, 0x32);
+    pmw3325_write(0x6A, 0x93);
+    pmw3325_write(0x6B, 0x68);
+    pmw3325_write(0x6C, 0x71);
+    pmw3325_write(0x6D, 0x50);
+    pmw3325_write(0x7F, 0x00);
+    pmw3325_write(0x7F, 0x02);
+    pmw3325_write(0x29, 0x1C);
+    pmw3325_write(0x2A, 0x1A);
+    pmw3325_write(0x2B, 0x90);
+    pmw3325_write(0x40, 0x80);
+    pmw3325_write(0x7F, 0x00);
+    return true;
+}
+
+report_pmw3325_t pmw3325_read_burst(void) {
+    report_pmw3325_t report = {0};
+
+    uint8_t motion = pmw3325_read(0x02);
+    if ((motion & MSB1) == MSB1) {
+        // Motion detected
+        uint8_t dx_l = pmw3325_read(0x03);
+        uint8_t dx_h = pmw3325_read(0x04);
+        uint8_t dy_l = pmw3325_read(0x05);
+        uint8_t dy_h = pmw3325_read(0x06);
+
+        report.dx = convert_twoscomp_16(dx_h, dx_l);
+        report.dy = convert_twoscomp_16(dy_h, dy_l);
+    }
+
+    return report;
+}
+
+static const uint8_t pmw3325_cpi_lut[50] = {
+    0x02, 0x04, 0x06, 0x08, 0x0B, 0x0D, 0x0F, 0x12, 0x14, 0x16,
+    0x19, 0x1B, 0x1D, 0x20, 0x22, 0x24, 0x27, 0x29, 0x2B, 0x2E,
+    0x30, 0x32, 0x34, 0x37, 0x39, 0x3B, 0x3E, 0x40, 0x42, 0x45,
+    0x47, 0x49, 0x4C, 0x4E, 0x50, 0x53, 0x55, 0x57, 0x5A, 0x5C,
+    0x5E, 0x61, 0x63, 0x65, 0x68, 0x6A, 0x6C, 0x6F, 0x71, 0x73
+};
+
+void pmw3325_set_cpi(uint16_t cpi) {
+    uint8_t cpival = CONSTRAIN((cpi / PMW3325_CPI_STEP), (PMW3325_CPI_MIN / PMW3325_CPI_STEP), (PMW3325_CPI_MAX / PMW3325_CPI_STEP)) - 1U;
+
+    pmw3325_write(0x1B, pmw3325_cpi_lut[cpival]);
+}
+
+uint16_t pmw3325_get_cpi(void) {
+    uint8_t cpival = pmw3325_read(0x1B);
+
+    for (uint8_t cpi = 0; cpi < 50; cpi++) {
+        if (pmw3325_cpi_lut[cpi] == cpival) {
+            return (cpi + 1) * PMW3325_CPI_STEP;
+        }
+    }
+
+    return 0;
+}
+
+report_mouse_t pmw3325_get_report(report_mouse_t mouse_report) {
+    report_pmw3325_t data = pmw3325_read_burst();
+
+    if (data.dx != 0 || data.dy != 0) {
+        pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy);
+        mouse_report.x = CONSTRAIN_HID_XY(data.dx);
+        mouse_report.y = CONSTRAIN_HID_XY(data.dy);
+    }
+
+    return mouse_report;
+}
+
+bool pmw3325_check_signature(void) {
+    uint8_t checkval_1 = pmw3325_read(0x00);
+    uint8_t checkval_2 = pmw3325_read(0x3F);
+
+    return (checkval_1 == 0x43 && checkval_2 == 0xBC);
+}

+ 44 - 0
drivers/sensors/pmw3325.h

@@ -0,0 +1,44 @@
+// Copyright 2021 Colin Lam (Ploopy Corporation)
+// Copyright 2026 HorrorTroll <https://github.com/HorrorTroll>
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "pointing_device.h"
+
+#ifndef PMW3325_CS_PIN
+#    ifdef POINTING_DEVICE_CS_PIN
+#        define PMW3325_CS_PIN POINTING_DEVICE_CS_PIN
+#    else
+#        error "No chip select pin defined -- missing POINTING_DEVICE_CS_PIN or PMW3325_CS_PIN define"
+#    endif
+#endif
+
+#ifndef PMW3325_SPI_DIVISOR
+#    error "No PMW3325 SPI divisor defined -- missing PMW3325_SPI_DIVISOR"
+#endif
+
+typedef struct {
+    int16_t dx;
+    int16_t dy;
+} report_pmw3325_t;
+
+extern const pointing_device_driver_t pmw3325_pointing_device_driver;
+
+bool             pmw3325_init(void);
+report_pmw3325_t pmw3325_read_burst(void);
+void             pmw3325_set_cpi(uint16_t cpi);
+uint16_t         pmw3325_get_cpi(void);
+report_mouse_t   pmw3325_get_report(report_mouse_t mouse_report);
+bool             pmw3325_check_signature(void);
+
+#if !defined(PMW3325_CPI)
+#    define PMW3325_CPI 2000
+#endif
+
+#define PMW3325_CPI_MIN 100
+#define PMW3325_CPI_MAX 5000
+#define PMW3325_CPI_STEP 100
+#define CONSTRAIN(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))

+ 4 - 0
quantum/pointing_device/pointing_device.h

@@ -43,6 +43,10 @@ typedef struct {
 #    include "spi_master.h"
 #    include "spi_master.h"
 #    include "drivers/sensors/paw3222.h"
 #    include "drivers/sensors/paw3222.h"
 #    define POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
 #    define POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
+#elif defined(POINTING_DEVICE_DRIVER_pmw3325)
+#    include "spi_master.h"
+#    include "drivers/sensors/pmw3325.h"
+#    define POINTING_DEVICE_MOTION_PIN_ACTIVE_LOW
 #elif defined(POINTING_DEVICE_DRIVER_adns9800)
 #elif defined(POINTING_DEVICE_DRIVER_adns9800)
 #    include "spi_master.h"
 #    include "spi_master.h"
 #    include "drivers/sensors/adns9800.h"
 #    include "drivers/sensors/adns9800.h"