Eric Tsai / LIS3DH

Fork of LIS3DH by Kenji Arai

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers LIS3DH.cpp Source File

LIS3DH.cpp

00001 /*
00002  * 2018:  Eric Tsai's Modifications of Kenji Arai's original LIS3DH library 
00003  * modified <initialize> and added threshold <setAct> call
00004  *
00005  *
00006  * mbed library program
00007  *  LIS3DH MEMS motion sensor: 3-axis "nano" accelerometer, made by STMicroelectronics
00008  *      http://www.st-japan.co.jp/web/jp/catalog/sense_power/FM89/SC444/PF250725
00009  *
00010  * Copyright (c) 2014,'15,'17 Kenji Arai / JH1PJL
00011  *  http://www.page.sannet.ne.jp/kenjia/index.html
00012  *  http://mbed.org/users/kenjiArai/
00013  *      Created: July       14th, 2014
00014  *      Revised: August     23rd, 2017
00015  */
00016 
00017 #include "LIS3DH.h"
00018 
00019 LIS3DH::LIS3DH (PinName p_sda, PinName p_scl,
00020                 uint8_t addr, uint8_t data_rate, uint8_t fullscale)
00021  : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
00022 {
00023     _i2c.frequency(400000);
00024     initialize (addr, data_rate, fullscale);
00025 }
00026 
00027 LIS3DH::LIS3DH (PinName p_sda, PinName p_scl, uint8_t addr)
00028  : _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
00029 {
00030     _i2c.frequency(400000);
00031     //initialize (addr, LIS3DH_DR_NR_LP_50HZ, LIS3DH_FS_8G);  //tsai:  change this to 10Hz, 16uA to 8uA.
00032     //itialize (addr, LIS3DH_DR_NR_LP_10HZ, LIS3DH_FS_8G);  //8uA consumption at 10Hz
00033     
00034     initialize (addr, LIS3DH_DR_NR_LP_10HZ, LIS3DH_FS_2G); //8uA @ 10Hz, 2G scale, really sensitive.
00035     // LIS3DH_DR_NR_LP_10HZ = 2
00036     // LIS3DH_FS_8G = 2, full scale
00037 }
00038 
00039 LIS3DH::LIS3DH (I2C& p_i2c,
00040                 uint8_t addr, uint8_t data_rate, uint8_t fullscale)
00041  : _i2c(p_i2c)
00042 {
00043     _i2c.frequency(400000);
00044     initialize (addr, data_rate, fullscale);
00045 }
00046 
00047 LIS3DH::LIS3DH (I2C& p_i2c, uint8_t addr)
00048  : _i2c(p_i2c)
00049 {
00050     _i2c.frequency(400000);
00051     initialize (addr, LIS3DH_DR_NR_LP_50HZ, LIS3DH_FS_8G);
00052 }
00053 
00054 void LIS3DH::initialize (uint8_t addr, uint8_t data_rate, uint8_t fullscale)
00055 {
00056     // Check acc is available of not
00057     acc_addr = addr;
00058     dt[0] = LIS3DH_WHO_AM_I;
00059     _i2c.write(acc_addr, dt, 1, true);
00060     _i2c.read(acc_addr, dt, 1, false);
00061     if (dt[0] == I_AM_LIS3DH) {
00062         acc_ready = 1;
00063     } else {
00064         acc_ready = 0;
00065         return;     // acc chip is NOT on I2C line then terminate
00066     }
00067     //  Reg.1
00068     dt[0] = LIS3DH_CTRL_REG1;
00069     dt[1] = 0x07;   //0000 0111
00070     dt[1] |= data_rate << 4;    // 0000 0111 |= 0010 0000  ---> 0010 0111;  10Hz, high res, xyz enbabled.
00071     
00072     //note:  dt[1]=0x0F;    //low resolution; @ datarate;  Must also zero out CTRL_REG4[3]
00073     //dt[1] = 0x07;
00074     _i2c.write(acc_addr, dt, 2, false);     //address, command, bytes
00075     
00076     
00077     
00078     //  Reg.4
00079     dt[0] = LIS3DH_CTRL_REG4;
00080     dt[1] = 0x08;  // High resolution       //0000 1000
00081     dt[1] |= fullscale << 4;                //
00082     //fullscale = 0000 0010
00083     //fullscale << 4 = 0010 0000
00084     //result of OR = 0010 1000   ----> 
00085     //  continuous update
00086     //  endian, LSB @ lowest address
00087     //  10 = 8G scale
00088     //  High resolution (10bit) ENABLED
00089     //  0, 0 N/A
00090     
00091     _i2c.write(acc_addr, dt, 2, false);
00092     
00093     
00094     
00095     
00096 
00097     
00098     switch (fullscale) {
00099         case LIS3DH_FS_2G:
00100             fs_factor = LIS3DH_SENSITIVITY_2G;
00101             break;
00102         case LIS3DH_FS_4G:
00103             fs_factor = LIS3DH_SENSITIVITY_4G;
00104             break;
00105         case LIS3DH_FS_8G:
00106             fs_factor = LIS3DH_SENSITIVITY_8G;
00107             break;
00108         case LIS3DH_FS_16G:
00109             fs_factor = LIS3DH_SENSITIVITY_16G;
00110             break;
00111         default:
00112             ;
00113     }
00114 }
00115 
00116 
00117 
00118 void LIS3DH::read_reg_data(char *data)
00119 {
00120     // X,Y & Z
00121     // manual said that
00122     // In order to read multiple bytes, it is necessary to assert the most significant bit
00123     // of the subaddress field.
00124     // In other words, SUB(7) must be equal to ‘1’ while SUB(6-0) represents the address
00125     // of the first register to be read.
00126     dt[0] = LIS3DH_OUT_X_L | 0x80;
00127     _i2c.write(acc_addr, dt, 1, true);
00128     _i2c.read(acc_addr, data, 6, false);
00129 }
00130 
00131 void LIS3DH::read_mg_data(float *dt_usr)
00132 {
00133     char data[6];
00134 
00135     if (acc_ready == 0) {
00136         dt_usr[0] = 0;
00137         dt_usr[1] = 0;
00138         dt_usr[2] = 0;
00139         return;
00140     }
00141     read_reg_data(data);
00142     // change data type
00143 #if OLD_REV // Fixed bugs -> (1) unit is not mg but g (2) shift right 4bit = /16
00144     dt_usr[0] = float(short((data[1] << 8) | data[0])) * fs_factor / 15;
00145     dt_usr[1] = float(short((data[3] << 8) | data[2])) * fs_factor / 15;
00146     dt_usr[2] = float(short((data[5] << 8) | data[4])) * fs_factor / 15;
00147 #else
00148     dt_usr[0] = float(short((data[1] << 8) | data[0]) >> 4) * fs_factor;
00149     dt_usr[1] = float(short((data[3] << 8) | data[2]) >> 4) * fs_factor;
00150     dt_usr[2] = float(short((data[5] << 8) | data[4]) >> 4) * fs_factor;
00151 #endif
00152 }
00153 
00154 void LIS3DH::read_data(float *dt_usr)
00155 {
00156     char data[6];
00157 
00158     if (acc_ready == 0) {
00159         dt_usr[0] = 0;
00160         dt_usr[1] = 0;
00161         dt_usr[2] = 0;
00162         return;
00163     }
00164     read_reg_data(data);
00165     // change data type
00166 #if OLD_REV // Fixed bugs -> shift right 4bit = /16 (not /15)
00167     dt_usr[0] = float(short((data[1] << 8) | data[0])) * fs_factor / 15 * GRAVITY;
00168     dt_usr[1] = float(short((data[3] << 8) | data[2])) * fs_factor / 15 * GRAVITY;
00169     dt_usr[2] = float(short((data[5] << 8) | data[4])) * fs_factor / 15 * GRAVITY;
00170 #else
00171     dt_usr[0] = float(short((data[1] << 8) | data[0]) >> 4) * fs_factor * GRAVITY;
00172     dt_usr[1] = float(short((data[3] << 8) | data[2]) >> 4) * fs_factor * GRAVITY;
00173     dt_usr[2] = float(short((data[5] << 8) | data[4]) >> 4) * fs_factor * GRAVITY;
00174 #endif
00175 }
00176 
00177 uint8_t LIS3DH::read_id()
00178 {
00179     dt[0] = LIS3DH_WHO_AM_I;
00180     _i2c.write(acc_addr, dt, 1, true);
00181     _i2c.read(acc_addr, dt, 1, false);
00182     return (uint8_t)dt[0];
00183 }
00184 
00185 uint8_t LIS3DH::data_ready()
00186 {
00187     if (acc_ready == 1) {
00188         dt[0] = LIS3DH_STATUS_REG_AUX;
00189         _i2c.write(acc_addr, dt, 1, true);
00190         _i2c.read(acc_addr, dt, 1, false);
00191         if (!(dt[0] & 0x01)) {
00192             return 0;
00193         }
00194     }
00195     return 1;
00196 }
00197 
00198 void LIS3DH::frequency(int hz)
00199 {
00200     _i2c.frequency(hz);
00201 }
00202 
00203 uint8_t LIS3DH::read_reg(uint8_t addr)
00204 {
00205     if (acc_ready == 1) {
00206         dt[0] = addr;
00207         _i2c.write(acc_addr, dt, 1, true);
00208         _i2c.read(acc_addr, dt, 1, false);
00209     } else {
00210         dt[0] = 0xff;
00211     }
00212     return (uint8_t)dt[0];
00213 }
00214 
00215 void LIS3DH::write_reg(uint8_t addr, uint8_t data)
00216 {
00217     if (acc_ready == 1) {
00218         dt[0] = addr;
00219         dt[1] = data;
00220         _i2c.write(acc_addr, dt, 2, false);
00221     }
00222 }
00223 
00224 // Tsai
00225 // See ST app note AN3308
00226 // Add interrupt output from motion.
00227 // Should parameterize threshold, latch, etc... 
00228 uint8_t LIS3DH::setAct(uint8_t addr)
00229 {
00230     uint8_t ret_val;
00231     
00232     // Check acc is available of not
00233     acc_addr = addr;
00234     dt[0] = LIS3DH_WHO_AM_I;
00235     _i2c.write(acc_addr, dt, 1, true);
00236     _i2c.read(acc_addr, dt, 1, false);
00237     if (dt[0] == I_AM_LIS3DH) {
00238         acc_ready = 1;
00239         ret_val=1;
00240     } else {
00241         acc_ready = 0;
00242         ret_val=2;
00243         return ret_val;     // acc chip is NOT on I2C line then terminate
00244     }
00245     
00246     //Tsai:  set CTRL_REG2, high pass filter, 
00247     //value = 0100 0000
00248     dt[0] = LIS3DH_CTRL_REG2;
00249     dt[1] = 0x09;  // 0000 1001, enable filter, on IA1
00250     _i2c.write(acc_addr, dt, 2, false);
00251     
00252 
00253     //Tsai:  set CTRL_REG3, 
00254     //value = 0100 0000
00255     dt[0] = LIS3DH_CTRL_REG3;
00256     dt[1] = 0x40;  // 0100 0000, enable I1_IA1 INT1
00257     _i2c.write(acc_addr, dt, 2, false);
00258 
00259 
00260     //tsai:  reg. INT1_CFG
00261     dt[0] = LIS3DH_INT1_CFG;
00262     dt[1] = 0x7f;  // 0111 1111 = movement in all xyz
00263     _i2c.write(acc_addr, dt, 2, false);
00264     
00265     
00266     //tsai:  reg. LIS3DH_INT1_THS, threshold for activity
00267     dt[0] = LIS3DH_INT1_THS;
00268     //0-127;  I was at 10 out of 127 @ 16mg LSB;  
00269     dt[1] = 0x02;  // 0000 0010 //@2G scale-> 16mg*3 = 48mg motion
00270     _i2c.write(acc_addr, dt, 2, false);
00271     
00272     /*
00273     //tsai:  reg. INT1_DURATION
00274     dt[0] = LIS3DH_INT1_DURATION;
00275     dt[1] = 0x01;  // short?
00276     _i2c.write(acc_addr, dt, 2, false);
00277     */
00278     
00279     //tsai:  reg. LIS3DH_CTRL_REG5, latching interrupt?
00280     dt[0] = LIS3DH_CTRL_REG5;
00281     //0-127;  I was at 10 out of 127 @ 16mg LSB;  
00282     //dt[1] = 0x00;  // 0000 0000, don't latch interrupt 
00283     //dt[1] = 0x08;  // 0000 1000, latch int1
00284     dt[1] = 0x0C;  // 0000 1100, latch int1, enable 4D
00285     //dt[1] = 0x04;  // 0000 0100, dont latch int1, enable 4D
00286     _i2c.write(acc_addr, dt, 2, false);
00287     
00288     
00289     return ret_val;
00290 }