pmw3320.c (6585B)
1 /* Copyright 2021 Colin Lam (Ploopy Corporation) 2 * Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> 3 * Copyright 2019 Sunjun Kim 4 * Copyright 2019 Hiroyuki Okada 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 #include "pmw3320.h" 21 #include "wait.h" 22 #include "debug.h" 23 #include "gpio.h" 24 #include "pointing_device_internal.h" 25 26 const pointing_device_driver_t pmw3320_pointing_device_drivera = { 27 .init = pmw3320_init, 28 .get_report = pmw3320_get_report, 29 .set_cpi = pmw3320_set_cpi, 30 .get_cpi = pmw3320_get_cpi, 31 }; 32 33 bool pmw3320_init(void) { 34 // Initialize sensor serial pins. 35 gpio_set_pin_output(PMW3320_SCLK_PIN); 36 gpio_set_pin_output(PMW3320_SDIO_PIN); 37 gpio_set_pin_output(PMW3320_CS_PIN); 38 39 // reboot the sensor. 40 pmw3320_write_reg(REG_Power_Up_Reset, 0x5a); 41 42 // wait maximum time before sensor is ready. 43 // this ensures that the sensor is actually ready after reset. 44 wait_ms(55); 45 46 // read a burst from the sensor and then discard it. 47 // gets the sensor ready for write commands 48 // (for example, setting the dpi). 49 pmw3320_read_burst(); 50 51 // Pretty sure that this shouldn't be in the driver. 52 // Probably device specific? 53 // Set rest mode to default 54 pmw3320_write_reg(REG_Rest_Mode_Status, 0x00); 55 // Set LED to be always on 56 pmw3320_write_reg(REG_Led_Control, 0x4); 57 // Disable rest mode 58 pmw3320_write_reg(REG_Performance, 0x80); 59 60 return pmw3320_check_signature(); 61 } 62 63 // Perform a synchronization with sensor. 64 // Just as with the serial protocol, this is used by the slave to send a 65 // synchronization signal to the master. 66 void pmw3320_sync(void) { 67 gpio_write_pin_low(PMW3320_CS_PIN); 68 wait_us(1); 69 gpio_write_pin_high(PMW3320_CS_PIN); 70 } 71 72 void pmw3320_cs_select(void) { 73 gpio_write_pin_low(PMW3320_CS_PIN); 74 } 75 76 void pmw3320_cs_deselect(void) { 77 gpio_write_pin_high(PMW3320_CS_PIN); 78 } 79 80 uint8_t pmw3320_serial_read(void) { 81 gpio_set_pin_input(PMW3320_SDIO_PIN); 82 uint8_t byte = 0; 83 84 for (uint8_t i = 0; i < 8; ++i) { 85 gpio_write_pin_low(PMW3320_SCLK_PIN); 86 wait_us(1); 87 88 byte = (byte << 1) | gpio_read_pin(PMW3320_SDIO_PIN); 89 90 gpio_write_pin_high(PMW3320_SCLK_PIN); 91 wait_us(1); 92 } 93 94 return byte; 95 } 96 97 void pmw3320_serial_write(uint8_t data) { 98 gpio_set_pin_output(PMW3320_SDIO_PIN); 99 100 for (int8_t b = 7; b >= 0; b--) { 101 gpio_write_pin_low(PMW3320_SCLK_PIN); 102 103 if (data & (1 << b)) 104 gpio_write_pin_high(PMW3320_SDIO_PIN); 105 else 106 gpio_write_pin_low(PMW3320_SDIO_PIN); 107 108 wait_us(2); 109 110 gpio_write_pin_high(PMW3320_SCLK_PIN); 111 } 112 113 // This was taken from ADNS5050 driver. 114 // There's no any info in PMW3320 datasheet about this... 115 // tSWR. See page 15 of the ADNS5050 spec sheet. 116 // Technically, this is only necessary if the next operation is an SDIO 117 // read. This is not guaranteed to be the case, but we're being lazy. 118 wait_us(4); 119 120 // Note that tSWW is never necessary. All write operations require at 121 // least 32us, which exceeds tSWW, so there's never a need to wait for it. 122 } 123 124 // Read a byte of data from a register on the sensor. 125 uint8_t pmw3320_read_reg(uint8_t reg_addr) { 126 pmw3320_cs_select(); 127 128 pmw3320_serial_write(reg_addr); 129 130 uint8_t byte = pmw3320_serial_read(); 131 132 // This was taken directly from ADNS5050 driver... 133 // tSRW & tSRR. See page 15 of the ADNS5050 spec sheet. 134 // Technically, this is only necessary if the next operation is an SDIO 135 // read or write. This is not guaranteed to be the case. 136 // Honestly, this wait could probably be removed. 137 wait_us(1); 138 139 pmw3320_cs_deselect(); 140 141 return byte; 142 } 143 144 void pmw3320_write_reg(uint8_t reg_addr, uint8_t data) { 145 pmw3320_cs_select(); 146 pmw3320_serial_write(0b10000000 | reg_addr); 147 pmw3320_serial_write(data); 148 pmw3320_cs_deselect(); 149 } 150 151 report_pmw3320_t pmw3320_read_burst(void) { 152 pmw3320_cs_select(); 153 154 report_pmw3320_t data; 155 data.dx = 0; 156 data.dy = 0; 157 158 pmw3320_serial_write(REG_Motion_Burst); 159 160 uint8_t x = pmw3320_serial_read(); 161 uint8_t y = pmw3320_serial_read(); 162 163 // Probably burst mode may include contents of delta_xy register, 164 // which contain HI parts of x/y deltas, but I had no luck finding it. 165 // Probably it's required to activate 12-bit mode to access this data. 166 // So we end burst mode early to not read unneeded information. 167 pmw3320_cs_deselect(); 168 169 data.dx = convert_twoscomp(x); 170 data.dy = convert_twoscomp(y); 171 172 return data; 173 } 174 175 // Convert a two's complement byte from an unsigned data type into a signed 176 // data type. 177 int8_t convert_twoscomp(uint8_t data) { 178 if ((data & 0x80) == 0x80) 179 return -128 + (data & 0x7F); 180 else 181 return data; 182 } 183 184 uint16_t pmw3320_get_cpi(void) { 185 uint8_t cpival = pmw3320_read_reg(REG_Resolution); 186 // 0x1F is an inversion of 0x20 which is 0b100000 187 return (uint16_t)((cpival & 0x1F) * PMW3320_CPI_STEP); 188 } 189 190 void pmw3320_set_cpi(uint16_t cpi) { 191 uint8_t cpival = constrain((cpi / PMW3320_CPI_STEP), (PMW3320_CPI_MIN / PMW3320_CPI_STEP), (PMW3320_CPI_MAX / PMW3320_CPI_STEP)) - 1U; 192 // Fifth bit is probably a control bit. 193 // PMW3320 datasheet don't have any info on this, so this is a pure guess. 194 pmw3320_write_reg(REG_Resolution, 0x20 | cpival); 195 } 196 197 bool __attribute__((weak)) pmw3320_check_signature(void) { 198 uint8_t pid = pmw3320_read_reg(REG_Product_ID); 199 uint8_t pid2 = pmw3320_read_reg(REG_Inverse_Product_ID); 200 201 return (pid == 0x3b && pid2 == 0xc4); 202 } 203 204 report_mouse_t pmw3320_get_report(report_mouse_t mouse_report) { 205 report_pmw3320_t data = pmw3320_read_burst(); 206 207 if (data.dx != 0 || data.dy != 0) { 208 pd_dprintf("Raw ] X: %d, Y: %d\n", data.dx, data.dy); 209 mouse_report.x = (mouse_xy_report_t)data.dx; 210 mouse_report.y = (mouse_xy_report_t)data.dy; 211 } 212 213 return mouse_report; 214 }