adns.c (7981B)
1 /* Copyright 2020 Richard Sutherland <rich@brickbots.com> 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 #include "spi_master.h" 17 #include "adns.h" 18 #include "debug.h" 19 #include "wait.h" 20 #include "pointing_device.h" 21 #include "adns9800_srom_A6.h" 22 23 // registers 24 #define REG_Product_ID 0x00 25 #define REG_Revision_ID 0x01 26 #define REG_Motion 0x02 27 #define REG_Delta_X_L 0x03 28 #define REG_Delta_X_H 0x04 29 #define REG_Delta_Y_L 0x05 30 #define REG_Delta_Y_H 0x06 31 #define REG_SQUAL 0x07 32 #define REG_Pixel_Sum 0x08 33 #define REG_Maximum_Pixel 0x09 34 #define REG_Minimum_Pixel 0x0a 35 #define REG_Shutter_Lower 0x0b 36 #define REG_Shutter_Upper 0x0c 37 #define REG_Frame_Period_Lower 0x0d 38 #define REG_Frame_Period_Upper 0x0e 39 #define REG_Configuration_I 0x0f 40 #define REG_Configuration_II 0x10 41 #define REG_Frame_Capture 0x12 42 #define REG_SROM_Enable 0x13 43 #define REG_Run_Downshift 0x14 44 #define REG_Rest1_Rate 0x15 45 #define REG_Rest1_Downshift 0x16 46 #define REG_Rest2_Rate 0x17 47 #define REG_Rest2_Downshift 0x18 48 #define REG_Rest3_Rate 0x19 49 #define REG_Frame_Period_Max_Bound_Lower 0x1a 50 #define REG_Frame_Period_Max_Bound_Upper 0x1b 51 #define REG_Frame_Period_Min_Bound_Lower 0x1c 52 #define REG_Frame_Period_Min_Bound_Upper 0x1d 53 #define REG_Shutter_Max_Bound_Lower 0x1e 54 #define REG_Shutter_Max_Bound_Upper 0x1f 55 #define REG_LASER_CTRL0 0x20 56 #define REG_Observation 0x24 57 #define REG_Data_Out_Lower 0x25 58 #define REG_Data_Out_Upper 0x26 59 #define REG_SROM_ID 0x2a 60 #define REG_Lift_Detection_Thr 0x2e 61 #define REG_Configuration_V 0x2f 62 #define REG_Configuration_IV 0x39 63 #define REG_Power_Up_Reset 0x3a 64 #define REG_Shutdown 0x3b 65 #define REG_Inverse_Product_ID 0x3f 66 #define REG_Motion_Burst 0x50 67 #define REG_SROM_Load_Burst 0x62 68 #define REG_Pixel_Burst 0x64 69 70 // pins 71 #define NCS F7 72 73 extern const uint16_t firmware_length; 74 extern const uint8_t firmware_data[]; 75 76 enum motion_burst_propertr{ 77 motion = 0, 78 observation, 79 delta_x_l, 80 delta_x_h, 81 delta_y_l, 82 delta_y_h, 83 squal, 84 pixel_sum, 85 maximum_pixel, 86 minimum_pixel, 87 shutter_upper, 88 shutter_lower, 89 frame_period_upper, 90 frame_period_lower, 91 end_data 92 }; 93 94 void adns_begin(void){ 95 spi_start(NCS, false, 3, 8); 96 } 97 98 void adns_end(void){ 99 spi_stop(); 100 } 101 102 void adns_write(uint8_t reg_addr, uint8_t data){ 103 104 adns_begin(); 105 //send address of the register, with MSBit = 1 to indicate it's a write 106 spi_write(reg_addr | 0x80 ); 107 spi_write(data); 108 109 // tSCLK-NCS for write operation 110 wait_us(20); 111 112 113 // tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound 114 wait_us(100); 115 adns_end(); 116 } 117 118 uint8_t adns_read(uint8_t reg_addr){ 119 120 121 adns_begin(); 122 // send adress of the register, with MSBit = 0 to indicate it's a read 123 spi_write(reg_addr & 0x7f ); 124 uint8_t data = spi_read(); 125 126 // tSCLK-NCS for read operation is 120ns 127 wait_us(1); 128 129 130 // tSRW/tSRR (=20us) minus tSCLK-NCS 131 wait_us(19); 132 133 adns_end(); 134 return data; 135 } 136 137 void pointing_device_init(void) { 138 dprint("STARTING INTI\n"); 139 140 spi_init(); 141 // reset serial port 142 adns_begin(); 143 adns_end(); 144 145 // reboot 146 adns_write(REG_Power_Up_Reset, 0x5a); 147 wait_ms(50); 148 // read registers and discard 149 adns_read(REG_Motion); 150 adns_read(REG_Delta_X_L); 151 adns_read(REG_Delta_X_H); 152 adns_read(REG_Delta_Y_L); 153 adns_read(REG_Delta_Y_H); 154 155 // upload firmware 156 157 // set the configuration_IV register in 3k firmware mode 158 // bit 1 = 1 for 3k mode, other bits are reserved 159 adns_write(REG_Configuration_IV, 0x02); 160 161 // write 0x1d in SROM_enable reg for initializing 162 adns_write(REG_SROM_Enable, 0x1d); 163 164 // wait for more than one frame period 165 // assume that the frame rate is as low as 100fps... even if it should never be that low 166 wait_ms(10); 167 168 // write 0x18 to SROM_enable to start SROM download 169 adns_write(REG_SROM_Enable, 0x18); 170 171 // write the SROM file (=firmware data) 172 173 // write burst destination adress 174 adns_begin(); 175 spi_write(REG_SROM_Load_Burst | 0x80); 176 wait_us(15); 177 // send all bytes of the firmware 178 unsigned char c; 179 for(int i = 0; i < firmware_length; i++){ 180 c = (unsigned char)pgm_read_byte(firmware_data + i); 181 spi_write(c); 182 wait_us(15); 183 } 184 185 adns_end(); 186 wait_ms(10); 187 188 // enable laser(bit 0 = 0b), in normal mode (bits 3,2,1 = 000b) 189 // reading the actual value of the register is important because the real 190 // default value is different from what is said in the datasheet, and if you 191 // change the reserved bytes (like by writing 0x00...) it would not work. 192 uint8_t laser_ctrl0 = adns_read(REG_LASER_CTRL0); 193 adns_write(REG_LASER_CTRL0, laser_ctrl0 & 0xf0); 194 195 wait_ms(1); 196 197 // set the configuration_I register to set the CPI 198 // 0x01 = 50, minimum 199 // 0x44 = 3400, default 200 // 0x8e = 7100 201 // 0xA4 = 8200, maximum 202 adns_write(REG_Configuration_I, 0x10); 203 204 wait_ms(100); 205 dprint("INIT ENDED\n"); 206 } 207 208 int16_t convertDeltaToInt(uint8_t high, uint8_t low){ 209 210 // join bytes into twos compliment 211 //int16_t twos_comp = (high << 8) | low; 212 //return twos_comp; 213 return (high << 8) | low; 214 } 215 216 motion_delta_t readSensor(void) { 217 adns_begin(); 218 219 // read from Motion_Burst to enable burt mode 220 spi_write(REG_Motion_Burst & 0x7f); 221 222 // Wait one frame per docs, thanks u/kbjunky 223 wait_us(100); 224 uint8_t burst_data[pixel_sum]; 225 226 for (int i = 0; i < pixel_sum; ++i) { 227 burst_data[i] = spi_read(); 228 } 229 230 uint16_t delta_x = convertDeltaToInt(burst_data[delta_x_h], burst_data[delta_x_l]); 231 uint16_t delta_y = convertDeltaToInt(burst_data[delta_y_h], burst_data[delta_y_l]); 232 // Only consider the MSB for motion as this byte has other status bits 233 uint8_t motion_ind = burst_data[motion] & 0b10000000; 234 adns_end(); 235 236 motion_delta_t delta = {delta_x, delta_y, motion_ind}; 237 return delta; 238 } 239 240 bool pointing_device_task(void) { 241 motion_delta_t delta = readSensor(); 242 243 report_mouse_t report = pointing_device_get_report(); 244 245 if(delta.motion_ind) { 246 // clamp deltas from -127 to 127 247 report.x = delta.delta_x < -127 ? -127 : delta.delta_x > 127 ? 127 : delta.delta_x; 248 report.x = -report.x; 249 report.y = delta.delta_y < -127 ? -127 : delta.delta_y > 127 ? 127 : delta.delta_y; 250 } 251 252 pointing_device_set_report(report); 253 return pointing_device_send(); 254 }