qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

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 }