aboutsummaryrefslogtreecommitdiff
path: root/keyboards/oddball/adns.c
diff options
context:
space:
mode:
Diffstat (limited to 'keyboards/oddball/adns.c')
-rw-r--r--keyboards/oddball/adns.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/keyboards/oddball/adns.c b/keyboards/oddball/adns.c
new file mode 100644
index 000000000..35225f042
--- /dev/null
+++ b/keyboards/oddball/adns.c
@@ -0,0 +1,270 @@
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include "quantum.h"
4#include "pointing_device.h"
5#include "adns9800_srom_A4.h"
6#include "../../lib/lufa/LUFA/Drivers/Peripheral/SPI.h"
7
8// registers
9#define REG_Product_ID 0x00
10#define REG_Revision_ID 0x01
11#define REG_Motion 0x02
12#define REG_Delta_X_L 0x03
13#define REG_Delta_X_H 0x04
14#define REG_Delta_Y_L 0x05
15#define REG_Delta_Y_H 0x06
16#define REG_SQUAL 0x07
17#define REG_Pixel_Sum 0x08
18#define REG_Maximum_Pixel 0x09
19#define REG_Minimum_Pixel 0x0a
20#define REG_Shutter_Lower 0x0b
21#define REG_Shutter_Upper 0x0c
22#define REG_Frame_Period_Lower 0x0d
23#define REG_Frame_Period_Upper 0x0e
24#define REG_Configuration_I 0x0f
25#define REG_Configuration_II 0x10
26#define REG_Frame_Capture 0x12
27#define REG_SROM_Enable 0x13
28#define REG_Run_Downshift 0x14
29#define REG_Rest1_Rate 0x15
30#define REG_Rest1_Downshift 0x16
31#define REG_Rest2_Rate 0x17
32#define REG_Rest2_Downshift 0x18
33#define REG_Rest3_Rate 0x19
34#define REG_Frame_Period_Max_Bound_Lower 0x1a
35#define REG_Frame_Period_Max_Bound_Upper 0x1b
36#define REG_Frame_Period_Min_Bound_Lower 0x1c
37#define REG_Frame_Period_Min_Bound_Upper 0x1d
38#define REG_Shutter_Max_Bound_Lower 0x1e
39#define REG_Shutter_Max_Bound_Upper 0x1f
40#define REG_LASER_CTRL0 0x20
41#define REG_Observation 0x24
42#define REG_Data_Out_Lower 0x25
43#define REG_Data_Out_Upper 0x26
44#define REG_SROM_ID 0x2a
45#define REG_Lift_Detection_Thr 0x2e
46#define REG_Configuration_V 0x2f
47#define REG_Configuration_IV 0x39
48#define REG_Power_Up_Reset 0x3a
49#define REG_Shutdown 0x3b
50#define REG_Inverse_Product_ID 0x3f
51#define REG_Motion_Burst 0x50
52#define REG_SROM_Load_Burst 0x62
53#define REG_Pixel_Burst 0x64
54
55// pins
56#define NCS 0
57
58extern const uint16_t firmware_length;
59extern const uint8_t firmware_data[];
60
61enum motion_burst_property{
62 motion = 0,
63 observation,
64 delta_x_l,
65 delta_x_h,
66 delta_y_l,
67 delta_y_h,
68 squal,
69 pixel_sum,
70 maximum_pixel,
71 minimum_pixel,
72 shutter_upper,
73 shutter_lower,
74 frame_period_upper,
75 frame_period_lower,
76 end_data
77};
78
79// used to track the motion delta between updates
80volatile int32_t delta_x;
81volatile int32_t delta_y;
82
83void adns_begin(void){
84 PORTB &= ~ (1 << NCS);
85}
86
87void adns_end(void){
88 PORTB |= (1 << NCS);
89}
90
91void adns_write(uint8_t reg_addr, uint8_t data){
92
93 adns_begin();
94
95 //send address of the register, with MSBit = 1 to indicate it's a write
96 SPI_TransferByte(reg_addr | 0x80 );
97 SPI_TransferByte(data);
98
99 // tSCLK-NCS for write operation
100 wait_us(20);
101
102 adns_end();
103
104 // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
105 wait_us(100);
106}
107
108uint8_t adns_read(uint8_t reg_addr){
109
110 adns_begin();
111
112 // send adress of the register, with MSBit = 0 to indicate it's a read
113 SPI_TransferByte(reg_addr & 0x7f );
114 uint8_t data = SPI_TransferByte(0);
115
116 // tSCLK-NCS for read operation is 120ns
117 wait_us(1);
118
119 adns_end();
120
121 // tSRW/tSRR (=20us) minus tSCLK-NCS
122 wait_us(19);
123
124 return data;
125}
126
127void pointing_device_init(void) {
128
129 if(!is_keyboard_master())
130 return;
131
132 // interrupt 2
133 EICRA &= ~(1 << 4);
134 EICRA |= (1 << 5);
135 EIMSK |= (1<<INT2);
136
137 // mode 3
138 SPI_Init(
139 SPI_SPEED_FCPU_DIV_8 |
140 SPI_ORDER_MSB_FIRST |
141 SPI_SCK_LEAD_FALLING |
142 SPI_SAMPLE_TRAILING |
143 SPI_MODE_MASTER);
144
145 // set B0 output
146 DDRB |= (1 << 0);
147
148 // reset serial port
149 adns_end();
150 adns_begin();
151 adns_end();
152
153 // reboot
154 adns_write(REG_Power_Up_Reset, 0x5a);
155 wait_ms(50);
156
157 // read registers and discard
158 adns_read(REG_Motion);
159 adns_read(REG_Delta_X_L);
160 adns_read(REG_Delta_X_H);
161 adns_read(REG_Delta_Y_L);
162 adns_read(REG_Delta_Y_H);
163
164 // upload firmware
165
166 // set the configuration_IV register in 3k firmware mode
167 // bit 1 = 1 for 3k mode, other bits are reserved
168 adns_write(REG_Configuration_IV, 0x02);
169
170 // write 0x1d in SROM_enable reg for initializing
171 adns_write(REG_SROM_Enable, 0x1d);
172
173 // wait for more than one frame period
174 // assume that the frame rate is as low as 100fps... even if it should never be that low
175 wait_ms(10);
176
177 // write 0x18 to SROM_enable to start SROM download
178 adns_write(REG_SROM_Enable, 0x18);
179
180 // write the SROM file (=firmware data)
181 adns_begin();
182
183 // write burst destination adress
184 SPI_TransferByte(REG_SROM_Load_Burst | 0x80);
185 wait_us(15);
186
187 // send all bytes of the firmware
188 unsigned char c;
189 for(int i = 0; i < firmware_length; i++){
190 c = (unsigned char)pgm_read_byte(firmware_data + i);
191 SPI_TransferByte(c);
192 wait_us(15);
193 }
194
195 adns_end();
196
197 wait_ms(10);
198
199 // enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b)
200 // reading the actual value of the register is important because the real
201 // default value is different from what is said in the datasheet, and if you
202 // change the reserved bytes (like by writing 0x00...) it would not work.
203 uint8_t laser_ctrl0 = adns_read(REG_LASER_CTRL0);
204 adns_write(REG_LASER_CTRL0, laser_ctrl0 & 0xf0);
205
206 wait_ms(1);
207
208 // set the configuration_I register to set the CPI
209 // 0x01 = 50, minimum
210 // 0x44 = 3400, default
211 // 0x8e = 7100
212 // 0xA4 = 8200, maximum
213 adns_write(REG_Configuration_I, 0x04);
214
215 wait_ms(100);
216}
217
218void pointing_device_task(void) {
219
220 if(!is_keyboard_master())
221 return;
222
223 report_mouse_t report = pointing_device_get_report();
224
225 // clamp deltas from -127 to 127
226 report.x = delta_x < -127 ? 127 : delta_x > 127 ? 127 : delta_x;
227 report.x = -report.x;
228
229 report.y = delta_y < -127 ? 127 : delta_y > 127 ? 127 : delta_y;
230
231 // reset deltas
232 delta_x = 0;
233 delta_y = 0;
234
235 pointing_device_set_report(report);
236 pointing_device_send();
237}
238
239int16_t convertDeltaToInt(uint8_t high, uint8_t low){
240
241 // join bytes into twos compliment
242 uint16_t twos_comp = (high << 8) | low;
243
244 // convert twos comp to int
245 if (twos_comp & 0x8000)
246 return -1 * ((twos_comp ^ 0xffff) + 1);
247
248 return twos_comp;
249}
250
251ISR(INT2_vect) {
252 // called on interrupt 2 when sensed motion
253 // copy burst data from the respective registers
254
255 adns_begin();
256
257 // send adress of the register, with MSBit = 1 to indicate it's a write
258 SPI_TransferByte(REG_Motion_Burst & 0x7f);
259
260 uint8_t burst_data[pixel_sum];
261
262 for (int i = 0; i < pixel_sum; ++i) {
263 burst_data[i] = SPI_TransferByte(0);
264 }
265
266 delta_x += convertDeltaToInt(burst_data[delta_x_h], burst_data[delta_x_l]);
267 delta_y += convertDeltaToInt(burst_data[delta_y_h], burst_data[delta_y_l]);
268
269 adns_end();
270}