forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move optical sensor code to drivers folder (qmk#13044)
- Loading branch information
Showing
13 changed files
with
4,280 additions
and
45 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
/* Copyright 2021 Colin Lam (Ploopy Corporation) | ||
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | ||
* Copyright 2019 Sunjun Kim | ||
* Copyright 2019 Hiroyuki Okada | ||
* | ||
* 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/>. | ||
*/ | ||
|
||
|
||
#include "adns5050.h" | ||
#include "wait.h" | ||
#include "debug.h" | ||
#include "print.h" | ||
#include "gpio.h" | ||
|
||
#ifndef OPTIC_ROTATED | ||
# define OPTIC_ROTATED false | ||
#endif | ||
|
||
// Definitions for the ADNS serial line. | ||
#ifndef ADNS_SCLK_PIN | ||
# define ADNS_SCLK_PIN B7 | ||
#endif | ||
|
||
#ifndef ADNS_SDIO_PIN | ||
# define ADNS_SDIO_PIN C6 | ||
#endif | ||
|
||
#ifndef ADNS_CS_PIN | ||
# define ADNS_CS_PIN B4 | ||
#endif | ||
|
||
#ifdef CONSOLE_ENABLE | ||
void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); } | ||
#endif | ||
|
||
// Initialize the ADNS serial pins. | ||
void adns_init(void) { | ||
setPinOutput(ADNS_SCLK_PIN); | ||
setPinOutput(ADNS_SDIO_PIN); | ||
setPinOutput(ADNS_CS_PIN); | ||
} | ||
|
||
// Perform a synchronization with the ADNS. | ||
// Just as with the serial protocol, this is used by the slave to send a | ||
// synchronization signal to the master. | ||
void adns_sync(void) { | ||
writePinLow(ADNS_CS_PIN); | ||
wait_us(1); | ||
writePinHigh(ADNS_CS_PIN); | ||
} | ||
|
||
void adns_cs_select(void) { | ||
writePinLow(ADNS_CS_PIN); | ||
} | ||
|
||
void adns_cs_deselect(void) { | ||
writePinHigh(ADNS_CS_PIN); | ||
} | ||
|
||
uint8_t adns_serial_read(void) { | ||
setPinInput(ADNS_SDIO_PIN); | ||
uint8_t byte = 0; | ||
|
||
for (uint8_t i = 0; i < 8; ++i) { | ||
writePinLow(ADNS_SCLK_PIN); | ||
wait_us(1); | ||
|
||
byte = (byte << 1) | readPin(ADNS_SDIO_PIN); | ||
|
||
writePinHigh(ADNS_SCLK_PIN); | ||
wait_us(1); | ||
} | ||
|
||
return byte; | ||
} | ||
|
||
void adns_serial_write(uint8_t data) { | ||
setPinOutput(ADNS_SDIO_PIN); | ||
|
||
for (int8_t b = 7; b >= 0; b--) { | ||
writePinLow(ADNS_SCLK_PIN); | ||
|
||
if (data & (1 << b)) | ||
writePinHigh(ADNS_SDIO_PIN); | ||
else | ||
writePinLow(ADNS_SDIO_PIN); | ||
|
||
wait_us(2); | ||
|
||
writePinHigh(ADNS_SCLK_PIN); | ||
} | ||
|
||
// tSWR. See page 15 of the ADNS spec sheet. | ||
// Technically, this is only necessary if the next operation is an SDIO | ||
// read. This is not guaranteed to be the case, but we're being lazy. | ||
wait_us(4); | ||
|
||
// Note that tSWW is never necessary. All write operations require at | ||
// least 32us, which exceeds tSWW, so there's never a need to wait for it. | ||
} | ||
|
||
// Read a byte of data from a register on the ADNS. | ||
// Don't forget to use the register map (as defined in the header file). | ||
uint8_t adns_read_reg(uint8_t reg_addr) { | ||
adns_cs_select(); | ||
|
||
adns_serial_write(reg_addr); | ||
|
||
// We don't need a minimum tSRAD here. That's because a 4ms wait time is | ||
// already included in adns_serial_write(), so we're good. | ||
// See page 10 and 15 of the ADNS spec sheet. | ||
//wait_us(4); | ||
|
||
uint8_t byte = adns_serial_read(); | ||
|
||
// tSRW & tSRR. See page 15 of the ADNS spec sheet. | ||
// Technically, this is only necessary if the next operation is an SDIO | ||
// read or write. This is not guaranteed to be the case. | ||
// Honestly, this wait could probably be removed. | ||
wait_us(1); | ||
|
||
adns_cs_deselect(); | ||
|
||
return byte; | ||
} | ||
|
||
void adns_write_reg(uint8_t reg_addr, uint8_t data) { | ||
adns_cs_select(); | ||
adns_serial_write(reg_addr); | ||
adns_serial_write(data); | ||
adns_cs_deselect(); | ||
} | ||
|
||
report_adns_t adns_read_burst(void) { | ||
adns_cs_select(); | ||
|
||
report_adns_t data; | ||
data.dx = 0; | ||
data.dy = 0; | ||
|
||
adns_serial_write(REG_MOTION_BURST); | ||
|
||
// We don't need a minimum tSRAD here. That's because a 4ms wait time is | ||
// already included in adns_serial_write(), so we're good. | ||
// See page 10 and 15 of the ADNS spec sheet. | ||
//wait_us(4); | ||
|
||
uint8_t x = adns_serial_read(); | ||
uint8_t y = adns_serial_read(); | ||
|
||
// Burst mode returns a bunch of other shit that we don't really need. | ||
// Setting CS to high ends burst mode early. | ||
adns_cs_deselect(); | ||
|
||
data.dx = convert_twoscomp(x); | ||
data.dy = convert_twoscomp(y); | ||
|
||
return data; | ||
} | ||
|
||
// Convert a two's complement byte from an unsigned data type into a signed | ||
// data type. | ||
int8_t convert_twoscomp(uint8_t data) { | ||
if ((data & 0x80) == 0x80) | ||
return -128 + (data & 0x7F); | ||
else | ||
return data; | ||
} | ||
|
||
// Don't forget to use the definitions for CPI in the header file. | ||
void adns_set_cpi(uint8_t cpi) { | ||
adns_write_reg(REG_MOUSE_CONTROL2, cpi); | ||
} | ||
|
||
bool adns_check_signature(void) { | ||
uint8_t pid = adns_read_reg(REG_PRODUCT_ID); | ||
uint8_t rid = adns_read_reg(REG_REVISION_ID); | ||
uint8_t pid2 = adns_read_reg(REG_PRODUCT_ID2); | ||
|
||
return (pid == 0x12 && rid == 0x01 && pid2 == 0x26); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* Copyright 2021 Colin Lam (Ploopy Corporation) | ||
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com> | ||
* Copyright 2019 Sunjun Kim | ||
* Copyright 2019 Hiroyuki Okada | ||
* | ||
* 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 <stdbool.h> | ||
|
||
// Registers | ||
#define REG_PRODUCT_ID 0x00 | ||
#define REG_REVISION_ID 0x01 | ||
#define REG_MOTION 0x02 | ||
#define REG_DELTA_X 0x03 | ||
#define REG_DELTA_Y 0x04 | ||
#define REG_SQUAL 0x05 | ||
#define REG_SHUTTER_UPPER 0x06 | ||
#define REG_SHUTTER_LOWER 0x07 | ||
#define REG_MAXIMUM_PIXEL 0x08 | ||
#define REG_PIXEL_SUM 0x09 | ||
#define REG_MINIMUM_PIXEL 0x0a | ||
#define REG_PIXEL_GRAB 0x0b | ||
#define REG_MOUSE_CONTROL 0x0d | ||
#define REG_MOUSE_CONTROL2 0x19 | ||
#define REG_LED_DC_MODE 0x22 | ||
#define REG_CHIP_RESET 0x3a | ||
#define REG_PRODUCT_ID2 0x3e | ||
#define REG_INV_REV_ID 0x3f | ||
#define REG_MOTION_BURST 0x63 | ||
|
||
// CPI values | ||
#define CPI125 0x11 | ||
#define CPI250 0x12 | ||
#define CPI375 0x13 | ||
#define CPI500 0x14 | ||
#define CPI625 0x15 | ||
#define CPI750 0x16 | ||
#define CPI875 0x17 | ||
#define CPI1000 0x18 | ||
#define CPI1125 0x19 | ||
#define CPI1250 0x1a | ||
#define CPI1375 0x1b | ||
|
||
#ifdef CONSOLE_ENABLE | ||
void print_byte(uint8_t byte); | ||
#endif | ||
|
||
typedef struct { | ||
int8_t dx; | ||
int8_t dy; | ||
} report_adns_t; | ||
|
||
// A bunch of functions to implement the ADNS5050-specific serial protocol. | ||
// Note that the "serial.h" driver is insufficient, because it does not | ||
// manually manipulate a serial clock signal. | ||
void adns_init(void); | ||
void adns_sync(void); | ||
uint8_t adns_serial_read(void); | ||
void adns_serial_write(uint8_t data); | ||
uint8_t adns_read_reg(uint8_t reg_addr); | ||
void adns_write_reg(uint8_t reg_addr, uint8_t data); | ||
report_adns_t adns_read_burst(void); | ||
int8_t convert_twoscomp(uint8_t data); | ||
void adns_set_cpi(uint8_t cpi); | ||
bool adns_check_signature(void); |
Oops, something went wrong.