parent
2464ef59db
commit
63d96c0059
@ -0,0 +1,224 @@
|
|||||||
|
/* -*- mode: c++ -*-
|
||||||
|
* Kaleidoscope - Firmware for computer input devices
|
||||||
|
* Copyright (C) 2022 Keyboard.io, Inc
|
||||||
|
*
|
||||||
|
* 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 3 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
|
||||||
|
|
||||||
|
#if defined(__AVR__)
|
||||||
|
|
||||||
|
#include <stdint.h> // for uint8_t
|
||||||
|
#include "kaleidoscope/device/avr/pins_and_ports.h"
|
||||||
|
|
||||||
|
namespace kaleidoscope {
|
||||||
|
namespace driver {
|
||||||
|
namespace sensor {
|
||||||
|
|
||||||
|
struct ADNS5050BaseProps {
|
||||||
|
static constexpr uint8_t clock_pin = NO_PIN;
|
||||||
|
static constexpr uint8_t io_pin = NO_PIN;
|
||||||
|
static constexpr uint8_t chip_select_pin = NO_PIN;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename _Props>
|
||||||
|
class ADNS5050 {
|
||||||
|
public:
|
||||||
|
ADNS5050() {}
|
||||||
|
|
||||||
|
typedef struct Report {
|
||||||
|
int8_t dx;
|
||||||
|
int8_t dy;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class CPI {
|
||||||
|
CPI125 = 0x11,
|
||||||
|
CPI250 = 0x12,
|
||||||
|
CPI375 = 0x13,
|
||||||
|
CPI500 = 0x14,
|
||||||
|
CPI625 = 0x15,
|
||||||
|
CPI750 = 0x16,
|
||||||
|
CPI875 = 0x17,
|
||||||
|
CPI1000 = 0x18,
|
||||||
|
CPI1125 = 0x19,
|
||||||
|
CPI1250 = 0x1a,
|
||||||
|
CPI1375 = 0x1b
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
static_assert(_Props::clock_pin != NO_PIN, "No clock pin specified!");
|
||||||
|
static_assert(_Props::io_pin != NO_PIN, "No IO pin specified!");
|
||||||
|
static_assert(_Props::chip_select_pin != NO_PIN, "No chip select pin specified!");
|
||||||
|
|
||||||
|
DDR_OUTPUT(_Props::clock_pin);
|
||||||
|
DDR_OUTPUT(_Props::io_pin);
|
||||||
|
DDR_OUTPUT(_Props::chip_select_pin);
|
||||||
|
|
||||||
|
// 0x5a is chip reset (datasheet page 26)
|
||||||
|
writeRegister(Register::CHIP_RESET, 0x5a);
|
||||||
|
delay(55);
|
||||||
|
|
||||||
|
// read an initial report from the sensor, and discard it.
|
||||||
|
readReport();
|
||||||
|
}
|
||||||
|
|
||||||
|
void sync() {
|
||||||
|
cs_select();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
cs_deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
Report readReport() {
|
||||||
|
Report report;
|
||||||
|
|
||||||
|
cs_select();
|
||||||
|
|
||||||
|
serialWrite(Register::MOTION_BURST);
|
||||||
|
|
||||||
|
uint8_t x = serialRead();
|
||||||
|
uint8_t y = serialRead();
|
||||||
|
|
||||||
|
cs_deselect();
|
||||||
|
|
||||||
|
report.dx = convertTwosComp(x);
|
||||||
|
report.dy = convertTwosComp(y);
|
||||||
|
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCPI(CPI cpi) {
|
||||||
|
uint8_t cpival = cpi / 125;
|
||||||
|
if (cpival < 0x01) {
|
||||||
|
cpival = 0x1;
|
||||||
|
}
|
||||||
|
if (cpival > 0x0d) {
|
||||||
|
cpival = 0x0d;
|
||||||
|
}
|
||||||
|
|
||||||
|
writeRegister(Register::MOUSE_CONTROL2, 0b10000 | cpival);
|
||||||
|
}
|
||||||
|
CPI getCPI() {
|
||||||
|
// not implemented yet
|
||||||
|
return CPI::CPI125;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkSignature() {
|
||||||
|
uint8_t rid = readRegister(Register::REVISION_ID);
|
||||||
|
uint8_t pid = readRegister(Register::PRODUCT_ID);
|
||||||
|
uint8_t pid2 = readRegister(Register::PRODUCT_ID2);
|
||||||
|
|
||||||
|
return (pid == 0x12 && rid == 0x01 && pid2 == 0x26);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum class Register {
|
||||||
|
PRODUCT_ID = 0x00,
|
||||||
|
REVISION_ID = 0x01,
|
||||||
|
MOTION = 0x02,
|
||||||
|
DELTA_X = 0x03,
|
||||||
|
DELTA_Y = 0x04,
|
||||||
|
MOUSE_CONTROL2 = 0x19,
|
||||||
|
CHIP_RESET = 0x3a,
|
||||||
|
PRODUCT_ID2 = 0x3e,
|
||||||
|
MOTION_BURST = 0x63
|
||||||
|
};
|
||||||
|
|
||||||
|
int8_t convertTwosComp(uint8_t data) {
|
||||||
|
if ((data & 0x80) == 0x80)
|
||||||
|
return -128 + (data & 0x7F);
|
||||||
|
else
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t serialRead() {
|
||||||
|
DDR_INPUT(_Props::io_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
uint8_t byte;
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
OUTPUT_LOW(_Props::clock_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
byte = (byte << 1) | READ_PIN(_Props::io_pin);
|
||||||
|
|
||||||
|
OUTPUT_HIGH(_Props::clock_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
void serialWrite(uint8_t data) {
|
||||||
|
DDR_OUTPUT(_Props::io_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
for (int8_t i = 7; i >= 0; i--) {
|
||||||
|
OUTPUT_LOW(_Props::clock_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
if (data && (1 << i)) {
|
||||||
|
OUTPUT_HIGH(_Props::io_pin);
|
||||||
|
} else {
|
||||||
|
OUTPUT_LOW(_Props::io_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
delayMicroseconds(2);
|
||||||
|
|
||||||
|
OUTPUT_HIGH(_Props::clock_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
delayMicroseconds(4);
|
||||||
|
}
|
||||||
|
void serialWrite(Register reg) {
|
||||||
|
serialWrite((uint8_t) reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t readRegister(Register reg) {
|
||||||
|
cs_select();
|
||||||
|
|
||||||
|
serialWrite(reg);
|
||||||
|
uint8_t byte = serialRead();
|
||||||
|
|
||||||
|
delayMicroseconds(1);
|
||||||
|
|
||||||
|
cs_deselect();
|
||||||
|
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
void writeRegister(Register reg, uint8_t data) {
|
||||||
|
cs_select();
|
||||||
|
serialWrite(0b10000000 | (uint8_t)reg);
|
||||||
|
serialWrite(data);
|
||||||
|
cs_deselect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void cs_select() {
|
||||||
|
OUTPUT_LOW(_Props::chip_select_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
void cs_deselect() {
|
||||||
|
OUTPUT_HIGH(_Props::chip_select_pin);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace sensor
|
||||||
|
} // namespace driver
|
||||||
|
} // namespace kaleidoscope
|
||||||
|
|
||||||
|
#endif // define(__AVR__)
|
Loading…
Reference in new issue