Analog Devices 3-axis accelerometer. I2C interface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ADXL345.cpp Source File

ADXL345.cpp

00001 /*
00002  * mbed library program
00003  *  ADXL345: 3-axis accelerometer, made by Analog Devices
00004  *  http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf
00005  *
00006  * Copyright (c) 2017 Kenji Arai / JH1PJL
00007  *  http://www.page.sannet.ne.jp/kenjia/index.html
00008  *  http://mbed.org/users/kenjiArai/
00009  *      Modify:     August    13th, 2017
00010  *      Revised:    September 23rd, 2017
00011  *
00012  */
00013 
00014 #include "ADXL345.h"
00015 
00016 // definition for Nomalization
00017 #define ADXL345_SENSITIVITY_2G  4.0f
00018 #define ADXL345_SENSITIVITY_4G  8.0f
00019 #define ADXL345_SENSITIVITY_8G  16.0f
00020 #define ADXL345_SENSITIVITY_16G 32.0f
00021 #define ADXL345_SEN_FULL_RES    4.0f
00022 
00023 //Gravity at Earth's surface in m/s/s
00024 #define GRAVITY                (9.80665f / 1000)
00025 
00026 #if MBED_MAJOR_VERSION == 2
00027 #define WAIT_MS(x)       wait_ms(x)
00028 #elif  MBED_MAJOR_VERSION == 5
00029 #define WAIT_MS(x)       Thread::wait(x)
00030 #else
00031 #error "Running on Unknown OS"
00032 #endif
00033 
00034 ADXL345::ADXL345 (PinName p_sda, PinName p_scl,
00035     uint8_t addr, uint8_t data_rate, uint8_t fullscale) :
00036   _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
00037 {
00038     _i2c.frequency(400000);
00039     initialize (addr, data_rate, fullscale);
00040 }
00041 
00042 ADXL345::ADXL345 (PinName p_sda, PinName p_scl, uint8_t addr) :
00043   _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
00044 {
00045     _i2c.frequency(400000);
00046     initialize (addr, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G);
00047 }
00048 
00049 ADXL345::ADXL345 (PinName p_sda, PinName p_scl) :
00050   _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p)
00051 {
00052     _i2c.frequency(400000);
00053     initialize(ADXL345_V_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G);
00054     if (acc_ready == false){
00055         initialize(ADXL345_G_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G);
00056     }
00057 }
00058 
00059 ADXL345::ADXL345 (I2C& p_i2c,
00060     uint8_t addr, uint8_t data_rate, uint8_t fullscale) : _i2c(p_i2c)
00061 {
00062     _i2c.frequency(400000);
00063     initialize (addr, data_rate, fullscale);
00064 }
00065 
00066 ADXL345::ADXL345 (I2C& p_i2c, uint8_t addr) : _i2c(p_i2c)
00067 {
00068     _i2c.frequency(400000);
00069     initialize (addr, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G);
00070 }
00071 
00072 ADXL345::ADXL345 (I2C& p_i2c) : _i2c(p_i2c)
00073 {
00074     _i2c.frequency(400000);
00075     initialize(ADXL345_V_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G);
00076     if (acc_ready == false){
00077         initialize(ADXL345_G_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G);
00078     }
00079 }
00080 
00081 void ADXL345::initialize (uint8_t addr, uint8_t data_rate, uint8_t fullscale)
00082 {
00083     // Check acc is available or not
00084     acc_addr = addr;
00085     dt[0] = ADXL345_DEVID;
00086     _i2c.write(acc_addr, dt, 1, true);
00087     _i2c.read(acc_addr, dt, 1, false);
00088     if (dt[0] == ADXL345_DEVICE_ID){
00089         acc_ready = true;
00090     } else {
00091         acc_ready = false;
00092         return;     // acc chip is NOT on I2C line then terminate
00093     }
00094     //  BW Rate
00095     dt[0] = ADXL345_BW_RATE;
00096     dt[1] = data_rate | ADXL345_NOT_LOW_PWR;    // normal(not low power mode)
00097     setting_data[0] = dt[1];
00098     _i2c.write(acc_addr, dt, 2, false);
00099     //  Data format (measurement range)
00100     dt[0] = ADXL345_DATA_FORMAT;
00101     dt[1] = fullscale;
00102     setting_data[1] = dt[1];
00103     _i2c.write(acc_addr, dt, 2, false);
00104     switch (fullscale){
00105         case ADXL345_FS_2G:
00106             fs_factor = ADXL345_SENSITIVITY_2G;
00107             break;
00108         case ADXL345_FS_4G:
00109             fs_factor = ADXL345_SENSITIVITY_4G;
00110             break;
00111         case ADXL345_FS_8G:
00112             fs_factor = ADXL345_SENSITIVITY_8G;
00113             break;
00114         case ADXL345_FS_16G:
00115             fs_factor = ADXL345_SENSITIVITY_16G;
00116             break;
00117         case ADXL345_FULL_RES_16G:
00118             fs_factor = ADXL345_SEN_FULL_RES;
00119             break;
00120         default:
00121             fs_factor = 1.0f;
00122             break;
00123     }
00124     //  Data ready flag
00125     dt[0] = ADXL345_INT_ENABLE;
00126     dt[1] = 0x80;
00127     setting_data[2] = dt[1];
00128     _i2c.write(acc_addr, dt, 2, false);
00129     //  Start measurement mode
00130     dt[0] = ADXL345_POWER_CTL;
00131     dt[1] = 0x08;
00132     setting_data[3] = dt[1];
00133     _i2c.write(acc_addr, dt, 2, false);
00134     // offset compensation
00135     dt[0] = ADXL345_OFSX;
00136     dt[1] = 0x01; 
00137     _i2c.write(acc_addr, dt, 2, false);
00138     dt[0] = ADXL345_OFSY;
00139     dt[1] = 0x00;
00140     _i2c.write(acc_addr, dt, 2, false);
00141     dt[0] = ADXL345_OFSZ;
00142     dt[1] = 0x00;
00143     _i2c.write(acc_addr, dt, 2, false);
00144 }
00145 
00146 void ADXL345::read_reg_data(char *data)
00147 {
00148     // read all of X,Y & Z
00149     dt[0] = ADXL345_DATAX0;
00150     _i2c.write(acc_addr, dt, 1, true);
00151     _i2c.read(acc_addr, data, 6, false);
00152 }
00153 
00154 void ADXL345::read_mg_data(float *dt_usr)
00155 {
00156     return read_mg_g_data(dt_usr, 0);
00157 }
00158 
00159 void ADXL345::read_g_data(float *dt_usr)
00160 {
00161     return read_mg_g_data(dt_usr, 1);
00162 }
00163 
00164 void ADXL345::read_data(float *dt_usr)
00165 {
00166     return read_mg_g_data(dt_usr, 2);
00167 }
00168 
00169 void ADXL345::read_mg_g_data(float *dt_usr, uint8_t n)
00170 {
00171     char    data[6];
00172     float   fct;
00173 
00174     if (acc_ready == false){
00175         dt_usr[0] = 0;
00176         dt_usr[1] = 0;
00177         dt_usr[2] = 0;
00178         return;
00179     }
00180     read_reg_data(data);
00181     if (n == 0){
00182         fct = fs_factor;
00183     } else if (n == 1){
00184         fct = fs_factor / 1000.0f;
00185     } else {
00186         fct = fs_factor * GRAVITY;
00187     }  
00188     // change data type
00189     dt_usr[0] = float(int16_t((data[1] << 8) | data[0])) * fct;
00190     dt_usr[1] = float(int16_t((data[3] << 8) | data[2])) * fct;
00191     dt_usr[2] = float(int16_t((data[5] << 8) | data[4])) * fct;
00192 }
00193 
00194 uint8_t ADXL345::read_id()
00195 {
00196     dt[0] = ADXL345_DEVID;
00197     _i2c.write(acc_addr, dt, 1, true);
00198     _i2c.read(acc_addr, dt, 1, false);
00199     return (uint8_t)dt[0];
00200 }
00201 
00202 bool ADXL345::data_ready()
00203 {
00204     if (acc_ready == true){
00205         dt[0] = ADXL345_INT_SOURCE;
00206         _i2c.write(acc_addr, dt, 1, true);
00207         _i2c.read(acc_addr, dt, 1, false);
00208         if (dt[0] & 0x80){  // Check ready bit
00209             return true;
00210         } else {
00211             return false;
00212         }
00213     }
00214     return false;
00215 }
00216 
00217 void ADXL345::frequency(int hz)
00218 {
00219     _i2c.frequency(hz);
00220 }
00221 
00222 uint8_t ADXL345::read_reg(uint8_t addr)
00223 {
00224     if (acc_ready == true){
00225         dt[0] = addr;
00226         _i2c.write(acc_addr, dt, 1, true);
00227         _i2c.read(acc_addr, dt, 1, false);
00228     } else {
00229         dt[0] = 0xff;
00230     }
00231     return (uint8_t)dt[0];
00232 }
00233 
00234 void ADXL345::write_reg(uint8_t addr, uint8_t data)
00235 {
00236     if (acc_ready == true){
00237         dt[0] = addr;
00238         dt[1] = data;
00239         _i2c.write(acc_addr, dt, 2, false);
00240     }
00241 }
00242 
00243 void ADXL345::debug_print(void)
00244 {
00245     printf("ADXL345 3-axes accelerometer\r\n");
00246     printf(" DEVID=0x%02x\r\n", read_reg(ADXL345_DEVID));
00247     printf(" THRESH_TAP=0x%02x\r\n", read_reg(ADXL345_THRESH_TAP));
00248     printf(" OFSX=0x%02x,", read_reg(ADXL345_OFSX));
00249     printf(" OFSY=0x%02x,", read_reg(ADXL345_OFSY));
00250     printf(" OFSZ=0x%02x\r\n", read_reg(ADXL345_OFSZ));
00251     printf(" DUR=0x%02x,", read_reg(ADXL345_DUR));
00252     printf(" LATENT=0x%02x,", read_reg(ADXL345_LATENT));
00253     printf(" WINDOW=0x%02x\r\n", read_reg(ADXL345_WINDOW));
00254     printf(" THRESH_ACT=0x%02x,", read_reg(ADXL345_THRESH_ACT));
00255     printf(" THRESH_INACT=0x%02x\r\n", read_reg(ADXL345_THRESH_INACT));
00256     printf(" TIME_INACT=0x%02x,", read_reg(ADXL345_TIME_INACT));
00257     printf(" ACT_INACT_CTL=0x%02x\r\n",
00258                     read_reg(ADXL345_ACT_INACT_CTL));
00259     printf(" THRESH_FF=0x%02x,", read_reg(ADXL345_THRESH_FF));
00260     printf(" TIME_FF=0x%02x,", read_reg(ADXL345_TIME_FF));
00261     printf(" TAP_AXES=0x%02x,", read_reg(ADXL345_TAP_AXES));
00262     printf(" ACT_TAP_STATUS=0x%02x\r\n",
00263                     read_reg(ADXL345_ACT_TAP_STATUS));
00264     printf(" BW_RATE=0x%02x\r\n", read_reg(ADXL345_BW_RATE));
00265     printf(" POWER_CTL=0x%02x\r\n", read_reg(ADXL345_POWER_CTL));
00266     printf(" INT_ENABLE=0x%02x,", read_reg(ADXL345_INT_ENABLE));
00267     printf(" INT_MAP=0x%02x,", read_reg(ADXL345_INT_MAP));
00268     printf(" INT_SOURCE=0x%02x\r\n", read_reg(ADXL345_INT_SOURCE));
00269     printf(" DATA_FORMAT=0x%02x\r\n", read_reg(ADXL345_DATA_FORMAT));
00270     printf(" DATAX0=0x%02x,", read_reg(ADXL345_DATAX0));
00271     printf(" 1=0x%02x,", read_reg(ADXL345_DATAX1));
00272     printf(" DATAY0=0x%02x,", read_reg(ADXL345_DATAY0));
00273     printf(" 1=0x%02x,", read_reg(ADXL345_DATAY1));
00274     printf(" DATAZ0=0x%02x,", read_reg(ADXL345_DATAZ0));
00275     printf(" 1=0x%02x\r\n", read_reg(ADXL345_DATAZ1));
00276     printf(" FIFO_CTL=0x%02x,", read_reg(ADXL345_FIFO_CTL));
00277     printf(" FIFO_STATUS=0x%02x\r\n", read_reg(ADXL345_FIFO_STATUS));
00278     // internal data
00279     printf(" ---- fs_factor=%f, acc_addr=0x%02x\r\n", fs_factor, acc_addr);
00280 }
00281 
00282 void ADXL345::self_test(void)
00283 {
00284     float dt0[3] ={0};
00285     float dt1[3] ={0};
00286     float dt2[3];
00287 
00288     dt[0] = ADXL345_DATA_FORMAT;
00289     dt[1] = 0x0B;
00290     _i2c.write(acc_addr, dt, 2, false);
00291     dt[0] = ADXL345_POWER_CTL;
00292     dt[1] = 0x08;
00293     _i2c.write(acc_addr, dt, 2, false);
00294     dt[0] = ADXL345_INT_ENABLE;
00295     dt[1] = 0x80;
00296     _i2c.write(acc_addr, dt, 2, false);
00297     WAIT_MS(40);
00298     for(uint8_t n = 0; n < 100; n++){
00299         read_data(dt2);
00300         dt0[0] += dt2[0];
00301         dt0[1] += dt2[1];
00302         dt0[2] += dt2[2];
00303     }
00304     dt0[0] /= 100;
00305     dt0[1] /= 100;
00306     dt0[2] /= 100;
00307     //
00308     dt[0] = ADXL345_DATA_FORMAT;
00309     dt[1] = 0x8B;
00310     _i2c.write(acc_addr, dt, 2, false);
00311     WAIT_MS(40);
00312     for(uint8_t n = 0; n < 100; n++){
00313         read_data(dt2);
00314         dt1[0] += dt2[0];
00315         dt1[1] += dt2[1];
00316         dt1[2] += dt2[2];
00317     }
00318     dt1[0] /= 100;
00319     dt1[1] /= 100;
00320     dt1[2] /= 100;
00321     printf("X, 1st, %+8.4f, 2nd, %+8.4f, diff, %+8.4f\r\n",
00322             dt0[0], dt1[0], dt0[0] - dt1[0]);
00323     printf("Y, 1st, %+8.4f, 2nd, %+8.4f, diff, %+8.4f\r\n",
00324             dt0[1], dt1[1], dt0[1] - dt1[1]);
00325     printf("Z, 1st, %+8.4f, 2nd, %+8.4f, diff, %+8.4f\r\n",
00326             dt0[2], dt1[2], dt0[2] - dt1[2]);
00327     //Recover original setting
00328     //  BW Rate
00329     dt[0] = ADXL345_BW_RATE;
00330     dt[1] = setting_data[0];
00331     _i2c.write(acc_addr, dt, 2, false);
00332     //  Data format (measurement range)
00333     dt[0] = ADXL345_DATA_FORMAT;
00334     dt[1] = setting_data[1];
00335     _i2c.write(acc_addr, dt, 2, false);
00336     //  Data ready flag
00337     dt[0] = ADXL345_INT_ENABLE;
00338     dt[1] = setting_data[2];
00339     _i2c.write(acc_addr, dt, 2, false);
00340     //  Start measurement mode
00341     dt[0] = ADXL345_POWER_CTL;
00342     dt[1] = setting_data[3];
00343     _i2c.write(acc_addr, dt, 2, false);
00344     WAIT_MS(40);
00345     read_data(dt2); // dummy read
00346 }