aboutsummaryrefslogtreecommitdiff
path: root/drivers/sensors/adns9800.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/sensors/adns9800.c')
-rw-r--r--drivers/sensors/adns9800.c219
1 files changed, 219 insertions, 0 deletions
diff --git a/drivers/sensors/adns9800.c b/drivers/sensors/adns9800.c
new file mode 100644
index 000000000..36213179f
--- /dev/null
+++ b/drivers/sensors/adns9800.c
@@ -0,0 +1,219 @@
1/* Copyright 2020 Alexander Tulloh
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include "spi_master.h"
18#include "quantum.h"
19#include "adns9800_srom_A6.h"
20#include "adns9800.h"
21
22// registers
23#define REG_Product_ID 0x00
24#define REG_Revision_ID 0x01
25#define REG_Motion 0x02
26#define REG_Delta_X_L 0x03
27#define REG_Delta_X_H 0x04
28#define REG_Delta_Y_L 0x05
29#define REG_Delta_Y_H 0x06
30#define REG_SQUAL 0x07
31#define REG_Pixel_Sum 0x08
32#define REG_Maximum_Pixel 0x09
33#define REG_Minimum_Pixel 0x0a
34#define REG_Shutter_Lower 0x0b
35#define REG_Shutter_Upper 0x0c
36#define REG_Frame_Period_Lower 0x0d
37#define REG_Frame_Period_Upper 0x0e
38#define REG_Configuration_I 0x0f
39#define REG_Configuration_II 0x10
40#define REG_Frame_Capture 0x12
41#define REG_SROM_Enable 0x13
42#define REG_Run_Downshift 0x14
43#define REG_Rest1_Rate 0x15
44#define REG_Rest1_Downshift 0x16
45#define REG_Rest2_Rate 0x17
46#define REG_Rest2_Downshift 0x18
47#define REG_Rest3_Rate 0x19
48#define REG_Frame_Period_Max_Bound_Lower 0x1a
49#define REG_Frame_Period_Max_Bound_Upper 0x1b
50#define REG_Frame_Period_Min_Bound_Lower 0x1c
51#define REG_Frame_Period_Min_Bound_Upper 0x1d
52#define REG_Shutter_Max_Bound_Lower 0x1e
53#define REG_Shutter_Max_Bound_Upper 0x1f
54#define REG_LASER_CTRL0 0x20
55#define REG_Observation 0x24
56#define REG_Data_Out_Lower 0x25
57#define REG_Data_Out_Upper 0x26
58#define REG_SROM_ID 0x2a
59#define REG_Lift_Detection_Thr 0x2e
60#define REG_Configuration_V 0x2f
61#define REG_Configuration_IV 0x39
62#define REG_Power_Up_Reset 0x3a
63#define REG_Shutdown 0x3b
64#define REG_Inverse_Product_ID 0x3f
65#define REG_Motion_Burst 0x50
66#define REG_SROM_Load_Burst 0x62
67#define REG_Pixel_Burst 0x64
68
69#define ADNS_CLOCK_SPEED 2000000
70#define MIN_CPI 200
71#define MAX_CPI 8200
72#define CPI_STEP 200
73#define CLAMP_CPI(value) value < MIN_CPI ? MIN_CPI : value > MAX_CPI ? MAX_CPI : value
74#define SPI_MODE 3
75#define SPI_DIVISOR (F_CPU / ADNS_CLOCK_SPEED)
76#define US_BETWEEN_WRITES 120
77#define US_BETWEEN_READS 20
78#define US_BEFORE_MOTION 100
79#define MSB1 0x80
80
81extern const uint16_t adns_firmware_length;
82extern const uint8_t adns_firmware_data[];
83
84void adns_spi_start(void){
85 spi_start(SPI_SS_PIN, false, SPI_MODE, SPI_DIVISOR);
86}
87
88void adns_write(uint8_t reg_addr, uint8_t data){
89
90 adns_spi_start();
91 spi_write(reg_addr | MSB1);
92 spi_write(data);
93 spi_stop();
94 wait_us(US_BETWEEN_WRITES);
95}
96
97uint8_t adns_read(uint8_t reg_addr){
98
99 adns_spi_start();
100 spi_write(reg_addr & 0x7f );
101 uint8_t data = spi_read();
102 spi_stop();
103 wait_us(US_BETWEEN_READS);
104
105 return data;
106}
107
108void adns_init() {
109
110 setPinOutput(SPI_SS_PIN);
111
112 spi_init();
113
114 // reboot
115 adns_write(REG_Power_Up_Reset, 0x5a);
116 wait_ms(50);
117
118 // read registers and discard
119 adns_read(REG_Motion);
120 adns_read(REG_Delta_X_L);
121 adns_read(REG_Delta_X_H);
122 adns_read(REG_Delta_Y_L);
123 adns_read(REG_Delta_Y_H);
124
125 // upload firmware
126
127 // 3k firmware mode
128 adns_write(REG_Configuration_IV, 0x02);
129
130 // enable initialisation
131 adns_write(REG_SROM_Enable, 0x1d);
132
133 // wait a frame
134 wait_ms(10);
135
136 // start SROM download
137 adns_write(REG_SROM_Enable, 0x18);
138
139 // write the SROM file
140
141 adns_spi_start();
142
143 spi_write(REG_SROM_Load_Burst | 0x80);
144 wait_us(15);
145
146 // send all bytes of the firmware
147 unsigned char c;
148 for(int i = 0; i < adns_firmware_length; i++){
149 c = (unsigned char)pgm_read_byte(adns_firmware_data + i);
150 spi_write(c);
151 wait_us(15);
152 }
153
154 spi_stop();
155
156 wait_ms(10);
157
158 // enable laser
159 uint8_t laser_ctrl0 = adns_read(REG_LASER_CTRL0);
160 adns_write(REG_LASER_CTRL0, laser_ctrl0 & 0xf0);
161}
162
163config_adns_t adns_get_config(void) {
164 uint8_t config_1 = adns_read(REG_Configuration_I);
165 return (config_adns_t){ (config_1 & 0xFF) * CPI_STEP };
166}
167
168void adns_set_config(config_adns_t config) {
169 uint8_t config_1 = (CLAMP_CPI(config.cpi) / CPI_STEP) & 0xFF;
170 adns_write(REG_Configuration_I, config_1);
171}
172
173static int16_t convertDeltaToInt(uint8_t high, uint8_t low){
174
175 // join bytes into twos compliment
176 uint16_t twos_comp = (high << 8) | low;
177
178 // convert twos comp to int
179 if (twos_comp & 0x8000)
180 return -1 * (~twos_comp + 1);
181
182 return twos_comp;
183}
184
185report_adns_t adns_get_report(void) {
186
187 report_adns_t report = {0, 0};
188
189 adns_spi_start();
190
191 // start burst mode
192 spi_write(REG_Motion_Burst & 0x7f);
193
194 wait_us(US_BEFORE_MOTION);
195
196 uint8_t motion = spi_read();
197
198 if(motion & 0x80) {
199
200 // clear observation register
201 spi_read();
202
203 // delta registers
204 uint8_t delta_x_l = spi_read();
205 uint8_t delta_x_h = spi_read();
206 uint8_t delta_y_l = spi_read();
207 uint8_t delta_y_h = spi_read();
208
209 report.x = convertDeltaToInt(delta_x_h, delta_x_l);
210 report.y = convertDeltaToInt(delta_y_h, delta_y_l);
211 }
212
213 // clear residual motion
214 spi_write(REG_Motion & 0x7f);
215
216 spi_stop();
217
218 return report;
219}