Analog Devices 3-axis accelerometer. I2C interface
Revision 0:21a3f84ad1c9, committed 2017-09-23
- Comitter:
- kenjiArai
- Date:
- Sat Sep 23 22:21:33 2017 +0000
- Commit message:
- 1st rev. I2C interface. Analog Devices 3-axis accelerometer
Changed in this revision
ADXL345.cpp | Show annotated file Show diff for this revision Revisions of this file |
ADXL345.h | Show annotated file Show diff for this revision Revisions of this file |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ADXL345.cpp Sat Sep 23 22:21:33 2017 +0000 @@ -0,0 +1,346 @@ +/* + * mbed library program + * ADXL345: 3-axis accelerometer, made by Analog Devices + * http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf + * + * Copyright (c) 2017 Kenji Arai / JH1PJL + * http://www.page.sannet.ne.jp/kenjia/index.html + * http://mbed.org/users/kenjiArai/ + * Modify: August 13th, 2017 + * Revised: September 23rd, 2017 + * + */ + +#include "ADXL345.h" + +// definition for Nomalization +#define ADXL345_SENSITIVITY_2G 4.0f +#define ADXL345_SENSITIVITY_4G 8.0f +#define ADXL345_SENSITIVITY_8G 16.0f +#define ADXL345_SENSITIVITY_16G 32.0f +#define ADXL345_SEN_FULL_RES 4.0f + +//Gravity at Earth's surface in m/s/s +#define GRAVITY (9.80665f / 1000) + +#if MBED_MAJOR_VERSION == 2 +#define WAIT_MS(x) wait_ms(x) +#elif MBED_MAJOR_VERSION == 5 +#define WAIT_MS(x) Thread::wait(x) +#else +#error "Running on Unknown OS" +#endif + +ADXL345::ADXL345 (PinName p_sda, PinName p_scl, + uint8_t addr, uint8_t data_rate, uint8_t fullscale) : + _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) +{ + _i2c.frequency(400000); + initialize (addr, data_rate, fullscale); +} + +ADXL345::ADXL345 (PinName p_sda, PinName p_scl, uint8_t addr) : + _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) +{ + _i2c.frequency(400000); + initialize (addr, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G); +} + +ADXL345::ADXL345 (PinName p_sda, PinName p_scl) : + _i2c_p(new I2C(p_sda, p_scl)), _i2c(*_i2c_p) +{ + _i2c.frequency(400000); + initialize(ADXL345_V_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G); + if (acc_ready == false){ + initialize(ADXL345_G_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G); + } +} + +ADXL345::ADXL345 (I2C& p_i2c, + uint8_t addr, uint8_t data_rate, uint8_t fullscale) : _i2c(p_i2c) +{ + _i2c.frequency(400000); + initialize (addr, data_rate, fullscale); +} + +ADXL345::ADXL345 (I2C& p_i2c, uint8_t addr) : _i2c(p_i2c) +{ + _i2c.frequency(400000); + initialize (addr, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G); +} + +ADXL345::ADXL345 (I2C& p_i2c) : _i2c(p_i2c) +{ + _i2c.frequency(400000); + initialize(ADXL345_V_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G); + if (acc_ready == false){ + initialize(ADXL345_G_CHIP_ADDR, ADXL345_DR_200HZ, ADXL345_FULL_RES_16G); + } +} + +void ADXL345::initialize (uint8_t addr, uint8_t data_rate, uint8_t fullscale) +{ + // Check acc is available or not + acc_addr = addr; + dt[0] = ADXL345_DEVID; + _i2c.write(acc_addr, dt, 1, true); + _i2c.read(acc_addr, dt, 1, false); + if (dt[0] == ADXL345_DEVICE_ID){ + acc_ready = true; + } else { + acc_ready = false; + return; // acc chip is NOT on I2C line then terminate + } + // BW Rate + dt[0] = ADXL345_BW_RATE; + dt[1] = data_rate | ADXL345_NOT_LOW_PWR; // normal(not low power mode) + setting_data[0] = dt[1]; + _i2c.write(acc_addr, dt, 2, false); + // Data format (measurement range) + dt[0] = ADXL345_DATA_FORMAT; + dt[1] = fullscale; + setting_data[1] = dt[1]; + _i2c.write(acc_addr, dt, 2, false); + switch (fullscale){ + case ADXL345_FS_2G: + fs_factor = ADXL345_SENSITIVITY_2G; + break; + case ADXL345_FS_4G: + fs_factor = ADXL345_SENSITIVITY_4G; + break; + case ADXL345_FS_8G: + fs_factor = ADXL345_SENSITIVITY_8G; + break; + case ADXL345_FS_16G: + fs_factor = ADXL345_SENSITIVITY_16G; + break; + case ADXL345_FULL_RES_16G: + fs_factor = ADXL345_SEN_FULL_RES; + break; + default: + fs_factor = 1.0f; + break; + } + // Data ready flag + dt[0] = ADXL345_INT_ENABLE; + dt[1] = 0x80; + setting_data[2] = dt[1]; + _i2c.write(acc_addr, dt, 2, false); + // Start measurement mode + dt[0] = ADXL345_POWER_CTL; + dt[1] = 0x08; + setting_data[3] = dt[1]; + _i2c.write(acc_addr, dt, 2, false); + // offset compensation + dt[0] = ADXL345_OFSX; + dt[1] = 0x01; + _i2c.write(acc_addr, dt, 2, false); + dt[0] = ADXL345_OFSY; + dt[1] = 0x00; + _i2c.write(acc_addr, dt, 2, false); + dt[0] = ADXL345_OFSZ; + dt[1] = 0x00; + _i2c.write(acc_addr, dt, 2, false); +} + +void ADXL345::read_reg_data(char *data) +{ + // read all of X,Y & Z + dt[0] = ADXL345_DATAX0; + _i2c.write(acc_addr, dt, 1, true); + _i2c.read(acc_addr, data, 6, false); +} + +void ADXL345::read_mg_data(float *dt_usr) +{ + return read_mg_g_data(dt_usr, 0); +} + +void ADXL345::read_g_data(float *dt_usr) +{ + return read_mg_g_data(dt_usr, 1); +} + +void ADXL345::read_data(float *dt_usr) +{ + return read_mg_g_data(dt_usr, 2); +} + +void ADXL345::read_mg_g_data(float *dt_usr, uint8_t n) +{ + char data[6]; + float fct; + + if (acc_ready == false){ + dt_usr[0] = 0; + dt_usr[1] = 0; + dt_usr[2] = 0; + return; + } + read_reg_data(data); + if (n == 0){ + fct = fs_factor; + } else if (n == 1){ + fct = fs_factor / 1000.0f; + } else { + fct = fs_factor * GRAVITY; + } + // change data type + dt_usr[0] = float(int16_t((data[1] << 8) | data[0])) * fct; + dt_usr[1] = float(int16_t((data[3] << 8) | data[2])) * fct; + dt_usr[2] = float(int16_t((data[5] << 8) | data[4])) * fct; +} + +uint8_t ADXL345::read_id() +{ + dt[0] = ADXL345_DEVID; + _i2c.write(acc_addr, dt, 1, true); + _i2c.read(acc_addr, dt, 1, false); + return (uint8_t)dt[0]; +} + +bool ADXL345::data_ready() +{ + if (acc_ready == true){ + dt[0] = ADXL345_INT_SOURCE; + _i2c.write(acc_addr, dt, 1, true); + _i2c.read(acc_addr, dt, 1, false); + if (dt[0] & 0x80){ // Check ready bit + return true; + } else { + return false; + } + } + return false; +} + +void ADXL345::frequency(int hz) +{ + _i2c.frequency(hz); +} + +uint8_t ADXL345::read_reg(uint8_t addr) +{ + if (acc_ready == true){ + dt[0] = addr; + _i2c.write(acc_addr, dt, 1, true); + _i2c.read(acc_addr, dt, 1, false); + } else { + dt[0] = 0xff; + } + return (uint8_t)dt[0]; +} + +void ADXL345::write_reg(uint8_t addr, uint8_t data) +{ + if (acc_ready == true){ + dt[0] = addr; + dt[1] = data; + _i2c.write(acc_addr, dt, 2, false); + } +} + +void ADXL345::debug_print(void) +{ + printf("ADXL345 3-axes accelerometer\r\n"); + printf(" DEVID=0x%02x\r\n", read_reg(ADXL345_DEVID)); + printf(" THRESH_TAP=0x%02x\r\n", read_reg(ADXL345_THRESH_TAP)); + printf(" OFSX=0x%02x,", read_reg(ADXL345_OFSX)); + printf(" OFSY=0x%02x,", read_reg(ADXL345_OFSY)); + printf(" OFSZ=0x%02x\r\n", read_reg(ADXL345_OFSZ)); + printf(" DUR=0x%02x,", read_reg(ADXL345_DUR)); + printf(" LATENT=0x%02x,", read_reg(ADXL345_LATENT)); + printf(" WINDOW=0x%02x\r\n", read_reg(ADXL345_WINDOW)); + printf(" THRESH_ACT=0x%02x,", read_reg(ADXL345_THRESH_ACT)); + printf(" THRESH_INACT=0x%02x\r\n", read_reg(ADXL345_THRESH_INACT)); + printf(" TIME_INACT=0x%02x,", read_reg(ADXL345_TIME_INACT)); + printf(" ACT_INACT_CTL=0x%02x\r\n", + read_reg(ADXL345_ACT_INACT_CTL)); + printf(" THRESH_FF=0x%02x,", read_reg(ADXL345_THRESH_FF)); + printf(" TIME_FF=0x%02x,", read_reg(ADXL345_TIME_FF)); + printf(" TAP_AXES=0x%02x,", read_reg(ADXL345_TAP_AXES)); + printf(" ACT_TAP_STATUS=0x%02x\r\n", + read_reg(ADXL345_ACT_TAP_STATUS)); + printf(" BW_RATE=0x%02x\r\n", read_reg(ADXL345_BW_RATE)); + printf(" POWER_CTL=0x%02x\r\n", read_reg(ADXL345_POWER_CTL)); + printf(" INT_ENABLE=0x%02x,", read_reg(ADXL345_INT_ENABLE)); + printf(" INT_MAP=0x%02x,", read_reg(ADXL345_INT_MAP)); + printf(" INT_SOURCE=0x%02x\r\n", read_reg(ADXL345_INT_SOURCE)); + printf(" DATA_FORMAT=0x%02x\r\n", read_reg(ADXL345_DATA_FORMAT)); + printf(" DATAX0=0x%02x,", read_reg(ADXL345_DATAX0)); + printf(" 1=0x%02x,", read_reg(ADXL345_DATAX1)); + printf(" DATAY0=0x%02x,", read_reg(ADXL345_DATAY0)); + printf(" 1=0x%02x,", read_reg(ADXL345_DATAY1)); + printf(" DATAZ0=0x%02x,", read_reg(ADXL345_DATAZ0)); + printf(" 1=0x%02x\r\n", read_reg(ADXL345_DATAZ1)); + printf(" FIFO_CTL=0x%02x,", read_reg(ADXL345_FIFO_CTL)); + printf(" FIFO_STATUS=0x%02x\r\n", read_reg(ADXL345_FIFO_STATUS)); + // internal data + printf(" ---- fs_factor=%f, acc_addr=0x%02x\r\n", fs_factor, acc_addr); +} + +void ADXL345::self_test(void) +{ + float dt0[3] ={0}; + float dt1[3] ={0}; + float dt2[3]; + + dt[0] = ADXL345_DATA_FORMAT; + dt[1] = 0x0B; + _i2c.write(acc_addr, dt, 2, false); + dt[0] = ADXL345_POWER_CTL; + dt[1] = 0x08; + _i2c.write(acc_addr, dt, 2, false); + dt[0] = ADXL345_INT_ENABLE; + dt[1] = 0x80; + _i2c.write(acc_addr, dt, 2, false); + WAIT_MS(40); + for(uint8_t n = 0; n < 100; n++){ + read_data(dt2); + dt0[0] += dt2[0]; + dt0[1] += dt2[1]; + dt0[2] += dt2[2]; + } + dt0[0] /= 100; + dt0[1] /= 100; + dt0[2] /= 100; + // + dt[0] = ADXL345_DATA_FORMAT; + dt[1] = 0x8B; + _i2c.write(acc_addr, dt, 2, false); + WAIT_MS(40); + for(uint8_t n = 0; n < 100; n++){ + read_data(dt2); + dt1[0] += dt2[0]; + dt1[1] += dt2[1]; + dt1[2] += dt2[2]; + } + dt1[0] /= 100; + dt1[1] /= 100; + dt1[2] /= 100; + printf("X, 1st, %+8.4f, 2nd, %+8.4f, diff, %+8.4f\r\n", + dt0[0], dt1[0], dt0[0] - dt1[0]); + printf("Y, 1st, %+8.4f, 2nd, %+8.4f, diff, %+8.4f\r\n", + dt0[1], dt1[1], dt0[1] - dt1[1]); + printf("Z, 1st, %+8.4f, 2nd, %+8.4f, diff, %+8.4f\r\n", + dt0[2], dt1[2], dt0[2] - dt1[2]); + //Recover original setting + // BW Rate + dt[0] = ADXL345_BW_RATE; + dt[1] = setting_data[0]; + _i2c.write(acc_addr, dt, 2, false); + // Data format (measurement range) + dt[0] = ADXL345_DATA_FORMAT; + dt[1] = setting_data[1]; + _i2c.write(acc_addr, dt, 2, false); + // Data ready flag + dt[0] = ADXL345_INT_ENABLE; + dt[1] = setting_data[2]; + _i2c.write(acc_addr, dt, 2, false); + // Start measurement mode + dt[0] = ADXL345_POWER_CTL; + dt[1] = setting_data[3]; + _i2c.write(acc_addr, dt, 2, false); + WAIT_MS(40); + read_data(dt2); // dummy read +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ADXL345.h Sat Sep 23 22:21:33 2017 +0000 @@ -0,0 +1,247 @@ +/* + * mbed library program + * ADXL345: 3-axis accelerometer, made by Analog Devices + * http://www.analog.com/static/imported-files/data_sheets/ADXL345.pdf + * + * Copyright (c) 2017 Kenji Arai / JH1PJL + * http://www.page.sannet.ne.jp/kenjia/index.html + * http://mbed.org/users/kenjiArai/ + * Modify: August 13th, 2017 + * Revised: September 23rd, 2017 + * + */ + +#ifndef ADXL345_H +#define ADXL345_H + +#include "mbed.h" + +// ADXL345 Address +// 7bit address = 0x1D or 0x53 (depends on ALT ADDRESS pin) +#define ADXL345_G_CHIP_ADDR (0x53 << 1) // ALT ADDRESS = Ground +#define ADXL345_V_CHIP_ADDR (0x1D << 1) // ALT ADDRESS = Vdd + +// ADXL345 ID +#define ADXL345_DEVICE_ID 0xE5 + +// Register's definition +#define ADXL345_DEVID 0x00 +#define ADXL345_THRESH_TAP 0x1D +#define ADXL345_OFSX 0x1E +#define ADXL345_OFSY 0x1F +#define ADXL345_OFSZ 0x20 +#define ADXL345_DUR 0x21 +#define ADXL345_LATENT 0x22 +#define ADXL345_WINDOW 0x23 +#define ADXL345_THRESH_ACT 0x24 +#define ADXL345_THRESH_INACT 0x25 +#define ADXL345_TIME_INACT 0x26 +#define ADXL345_ACT_INACT_CTL 0x27 +#define ADXL345_THRESH_FF 0x28 +#define ADXL345_TIME_FF 0x29 +#define ADXL345_TAP_AXES 0x2A +#define ADXL345_ACT_TAP_STATUS 0x2B +#define ADXL345_BW_RATE 0x2C +#define ADXL345_POWER_CTL 0x2D +#define ADXL345_INT_ENABLE 0x2E +#define ADXL345_INT_MAP 0x2F +#define ADXL345_INT_SOURCE 0x30 +#define ADXL345_DATA_FORMAT 0x31 +#define ADXL345_DATAX0 0x32 +#define ADXL345_DATAX1 0x33 +#define ADXL345_DATAY0 0x34 +#define ADXL345_DATAY1 0x35 +#define ADXL345_DATAZ0 0x36 +#define ADXL345_DATAZ1 0x37 +#define ADXL345_FIFO_CTL 0x38 +#define ADXL345_FIFO_STATUS 0x39 + +// Data Rate +#define ADXL345_LOW_PWR 0x10 +#define ADXL345_NOT_LOW_PWR 0x00 +#define ADXL345_DR_R10HZ 0x00 +#define ADXL345_DR_R20HZ 0x01 +#define ADXL345_DR_R39HZ 0x02 +#define ADXL345_DR_R78HZ 0x03 +#define ADXL345_DR_1R56HZ 0x04 +#define ADXL345_DR_3R13HZ 0x05 +#define ADXL345_DR_6R25HZ 0x06 +#define ADXL345_DR_12R5HZ 0x07 +#define ADXL345_DR_25HZ 0x08 +#define ADXL345_DR_50HZ 0x09 +#define ADXL345_DR_100HZ 0x0A +#define ADXL345_DR_200HZ 0x0B +#define ADXL345_DR_400HZ 0x0C +#define ADXL345_DR_800HZ 0x0D +#define ADXL345_DR_1R6KHZ 0x0E +#define ADXL345_DR_3R2KHZ 0x0F + +// FIFO Mode +#define ADXL345_FIFO_BYPASS 0x00 // Not use FIFO +#define ADXL345_FIFO_FIFO 0x40 // FIFO collects 32 then stop +#define ADXL345_FIFO_STREAM 0x80 // last 32 & continue sampling +#define ADXL345_FIFO_TRIGER 0xC0 // Start by trigger + +// FIFO Trigger Source +#define ADXL345_FIFO_TRG_INT1 0x00 +#define ADXL345_FIFO_TRG_INT2 0x20 + +// FIFO Trigger Source +#define ADXL345_FIFO_SAMPLES 0x31 // default value + +// Full Scale +#define ADXL345_FS_2G 0x00 +#define ADXL345_FS_4G 0x01 +#define ADXL345_FS_8G 0x02 +#define ADXL345_FS_16G 0x03 +#define ADXL345_FULL_RES_16G 0x0B + +/** Interface for Analog Devices : 3-axis accelerometer + * Chip: ADXL345 + * + * @code + * #include "mbed.h" + * + * // I2C Communication + * I2C i2c(D14,D15); // SDA, SCL + * ADXL345 acc(i2c); + * + * int main() { + * float f[3]; + * while(1){ + * acc.read_data(f); + * } + * } + * @endcode + */ + +class ADXL345 +{ +public: + /** Configure data pin (with other devices on I2C line) + * @param I2C PinName SDA &SDL + * @param device address + * @param output data rate selection, power down mode, 0.1Hz to 3.2KHz + * @param full scale selection, +/-2g to +/-16g + */ + ADXL345(PinName p_sda, PinName p_scl, + uint8_t addr, uint8_t data_rate, uint8_t fullscale); + + /** Configure data pin (with other devices on I2C line) + * @param I2C previous definition + * @param device address + */ + ADXL345(PinName p_sda, PinName p_scl, uint8_t addr); + + /** Configure data pin (with other devices on I2C line) + * @param I2C previous definition + */ + ADXL345(PinName p_sda, PinName p_scl); + + /** Configure data pin (with other devices on I2C line) + * @param I2C previous definition + * @param device address + * @param output data rate selection, power down mode, 0.1Hz to 3.2KHz + * @param full scale selection, +/-2g to +/-16g + */ + ADXL345(I2C& p_i2c, + uint8_t addr, uint8_t data_rate, uint8_t fullscale); + + /** Configure data pin (with other devices on I2C line) + * @param I2C previous definition + * @default output data rate selection = 100Hz + * @default full scale selection = +/-2g + */ + ADXL345(I2C& p_i2c, uint8_t addr); + + /** Configure data pin (with other devices on I2C line) + * @param I2C previous definition + * @default address check both G & V + * @default output data rate selection = 100Hz + * @default full scale selection = +/-2g + */ + ADXL345(I2C& p_i2c); + + /** Read a float type data from acc + * @param float type of three arry's address, e.g. float dt_usr[3]; + * @return acc motion data unit: m/s/s(m/s2) + * @return dt_usr[0]->x, dt_usr[1]->y, dt_usr[2]->z + */ + void read_data(float *dt_usr); + + /** Read a float type data from acc + * @param float type of three arry's address, e.g. float dt_usr[3]; + * @return acc motion data unit: mg + * @return dt_usr[0]->x, dt_usr[1]->y, dt_usr[2]->z + */ + void read_mg_data(float *dt_usr); + + /** Read a float type data from acc + * @param float type of three arry's address, e.g. float dt_usr[3]; + * @return acc motion data unit: g + * @return dt_usr[0]->x, dt_usr[1]->y, dt_usr[2]->z + */ + void read_g_data(float *dt_usr); + + /** Read a acc ID number + * @param none + * @return ID is okay (I_AM_ ADXL345(0x33)) or not + */ + uint8_t read_id(); + + /** Read Data Ready flag + * @param none + * @return true = Ready + */ + bool data_ready(); + + /** Set I2C clock frequency + * @param freq. + * @return none + */ + void frequency(int hz); + + /** Read register (general purpose) + * @param register's address + * @return register data + */ + uint8_t read_reg(uint8_t addr); + + /** Write register (general purpose) + * @param register's address + * @param data + * @return none + */ + void write_reg(uint8_t addr, uint8_t data); + + /** data print for debug + * @param none + * @return none + */ + void debug_print(void); + + /** Self-Test Feature + * @param none + * @return none + */ + void self_test(void); + +protected: + void initialize(uint8_t, uint8_t, uint8_t); + void read_reg_data(char *data); + void read_mg_g_data(float *dt_usr, uint8_t n); + + I2C *_i2c_p; + I2C &_i2c; + +private: + float fs_factor; // full scale factor + char dt[2]; // working buffer + uint8_t acc_addr; // acc sensor address + uint8_t acc_id; // acc ID + bool acc_ready; // acc is on I2C line = 1, not = 0 + uint8_t setting_data[4]; // Reg. recovery data + +}; + +#endif // ADXL345_H