My implementation of Bosh BMI160 Only I2C is tested so far.
Dependents: test_BMI160 TFT_test_MAX32630FTHR
BMI160.cpp
- Committer:
- Rhyme
- Date:
- 2017-09-12
- Revision:
- 4:93f16677f730
- Parent:
- 3:9d3079170b35
File content as of revision 4:93f16677f730:
#include "mbed.h" #include "BMI160.h" /* register address defintions */ #define REG_CHIP_ID 0x00 /* chip id */ #define REG_ERR_REG 0x02 #define REG_PMU_STATUS 0x03 #define REG_DATA_0 0x04 /* MAG_X_LSB */ #define REG_DATA_1 0x05 /* MAG_X_MSB */ #define REG_DATA_2 0x06 /* MAG_Y_LSB */ #define REG_DATA_3 0x07 /* MAG_Y_MSB */ #define REG_DATA_4 0x08 /* MAG_Z_LSB */ #define REG_DATA_5 0x09 /* MAG_Z_MSB */ #define REG_DATA_6 0x0A /* RHALL_LSB */ #define REG_DATA_7 0x0B /* RHALL_MSB */ #define REG_DATA_8 0x0C /* GRY_X_LSB */ #define REG_DATA_9 0x0D /* GRY_X_MSB */ #define REG_DATA_10 0x0E /* GRY_Y_LSB */ #define REG_DATA_11 0x0F /* GRY_Y_MSB */ #define REG_DATA_12 0x10 /* GRY_Z_LSB */ #define REG_DATA_13 0x11 /* GRY_Z_MSB */ #define REG_DATA_14 0x12 /* ACC_X_LSB */ #define REG_DATA_15 0x13 /* ACC_X_MSB */ #define REG_DATA_16 0x14 /* ACC_Y_LSB */ #define REG_DATA_17 0x15 /* ACC_Y_MSB */ #define REG_DATA_18 0x16 /* ACC_Z_LSB */ #define REG_DATA_19 0x17 /* ACC_Z_MSB */ #define REG_SENSORTIME_0 0x18 /* SENSOR_TIME_LSB */ #define REG_SENSORTIME_1 0x19 /* SENSOR_TIME_CSB */ #define REG_SENSORTIME_2 0x1A /* SENSOR_TIME_MSB */ #define REG_STATUS 0x1B #define REG_INT_STATUS_0 0x1C #define REG_INT_STATUS_1 0x1D #define REG_INT_STATUS_2 0x1E #define REG_INT_STATUS_3 0x1F #define REG_TEMPERATURE_0 0x20 #define REG_TEMPERATURE_1 0x21 #define REG_FIFO_LENGTH_0 0x22 #define REG_FIFO_LENGTH_1 0x23 #define REG_FIFO_DATA 0x24 #define REG_ACC_CONF 0x40 #define REG_ACC_RANGE 0x41 #define REG_GYR_CONF 0x42 #define REG_GYR_RANGE 0x43 #define REG_MAG_CONF 0x44 #define REG_FIFO_DOWNS 0x45 #define REG_FIFO_CONFIG_0 0x46 #define REG_FIFO_CONFIG_1 0x47 #define REG_MAG_IF_0 0x4B #define REG_MAG_IF_1 0x4C #define REG_MAG_IF_2 0x4D #define REG_MAG_IF_3 0x4E #define REG_MAG_IF_4 0x4F #define REG_INT_EN_0 0x50 #define REG_INT_EN_1 0x51 #define REG_INT_EN_2 0x52 #define REG_INT_OUT_CTRL 0x53 #define REG_INT_LATCH 0x54 #define REG_INT_MAP_0 0x55 #define REG_INT_MAP_1 0x56 #define REG_INT_MAP_2 0x57 #define REG_INT_DATA_0 0x58 #define REG_INT_DATA_1 0x59 #define REG_LOWHIGHT_0 0x5A #define REG_LOWHIGHT_1 0x5B #define REG_LOWHIGHT_2 0x5C #define REG_LOWHIGHT_3 0x5D #define REG_LOWHIGHT_4 0x5E #define REG_INT_MOTION_0 0x5F #define REG_INT_MOTION_1 0x60 #define REG_INT_MOTION_2 0x61 #define REG_INT_MOTION_3 0x62 #define REG_INT_TAP_0 0x63 #define REG_INT_TAP_1 0x64 #define REG_INT_ORIENT_0 0x65 #define REG_INT_ORIENT_1 0x66 #define REG_INT_FLAT_0 0x67 #define REG_INT_FLAT_1 0x68 #define REG_FOC_CONF 0x69 #define REG_CONF 0x6A #define REG_IF_CONF 0x6B #define REG_PMU_TRIGGER 0x6C #define REG_SELF_TEST 0x6D #define REG_NV_CONF 0x70 #define REG_OFFSET_0 0x71 #define REG_OFFSET_1 0x72 #define REG_OFFSET_2 0x73 #define REG_OFFSET_3 0x74 #define REG_OFFSET_4 0x75 #define REG_OFFSET_5 0x76 #define REG_OFFSET_6 0x77 #define REG_STEP_CNT_0 0x78 #define REG_STEP_CNT_1 0x79 #define REG_STEP_CONF_0 0x7A #define REG_STEP_CONF_1 0x7B #define REG_CMD 0x7E #define FLOAT_MAX_16BIT 32768.0 /* 0x00 CHIP_ID reset value = 0xD1 */ /* 0x02 ERR_REG Reports sensor error flags. Flags are cleared when read. * bit[7] mag_drdy_err * bit[6] drop_cmd_err Dropped command to Register * bit[5] i2c_fail_err * bit[4:1] err_code error code * 0000: no error * 0001: error * 0010: error * 0011: low-power mode and interrupt uses pre-filtered data * 0100-0101: reserved * 0110: ODRs of enabled sensors in headerless mode do not match * 0111: pre-filtered data are used in low power mode * 1000-1111: reserved * The first reported error will be shown in the error code * bit[0] fatal_err : Chip not operatable */ /* 0x03 PMU_STATUS * bit[7:6] (reserved) * bit[5:4] acc_pmu_status * bit[3:2] gyr_pmu_status * bit[1:0] mag_pmu_status */ /* 0x04 DATA_0 : MAG_X[7:0] */ /* 0x05 DATA_1 : MAG_X[15:8] */ /* 0x06 DATA_2 : MAG_Y[7:0] */ /* 0x07 DATA_3 : MAG_Y[15:8] */ /* 0x08 DATA_4 : MAG_Z[7:0] */ /* 0x09 DATA_5 : MAG_Z[15:8] */ /* 0x0A DATA_6 : RHALL[7:0] */ /* 0x0B DATA_7 : RHALL[15:8] */ /* 0x0C DATA_8 : GYR_X[7:0] */ /* 0x0D DATA_9 : GYR_X[15:8] */ /* 0x0E DATA_10 : GYR_Y[7:0] */ /* 0x0F DATA_11 : GYR_Y[15:8] */ /* 0x10 DATA_12 : GYR_Z[7:0] */ /* 0x11 DATA_13 : GYR_Z[15:8] */ /* 0x12 DATA_14 : ACC_X[7:0] */ /* 0x13 DATA_15 : ACC_X[15:8] */ /* 0x14 DATA_16 : ACC_Y[7:0] */ /* 0x15 DATA_17 : ACC_Y[15:8] */ /* 0x16 DATA_18 : ACC_Z[7:0] */ /* 0x17 DATA_19 : ACC_Z[15:8] */ /* 0x18 SENSORTIME_0 : sensor_time[7:0] */ /* 0x19 SENSORTIME_1 : sensor_time[15:8] */ /* 0x1A SENSORTIME_2 : sensor_time[23:16] */ /* 0x1B STATUS * bit[7] drdy_acc * bit[6] drdy_gyr * bit[5] drfy_mag * bit[4] nvm_rdy * bit[3] foc_rdy * bit[2] mag_man_op * bit[1] gry_self_test_of * bit[0] (reserved) */ /* 0x1C INT_STATUS_0 * bit[7] flat_int * bit[6] orient_int * bit[5] s_tap_int * bit[4] d_tap_int * bit[3] pmu_trigger_int * bit[2] anym_int * bit[1] sigmot_int * bit[0] step_int */ /* 0x1D INT_STATUS_1 * bit[7] nomo_int * bit[6] fwm_int * bit[5] ffull_int * bit[4] drdy_int * bit[3] lowg_int * bit[2] highg_int * bit[1:0] (reserved) */ /* 0x1E INT_STATUS_2 * bit[7] tap_sign * bit[6] tap_first_z * bit[5] tap_first_y * bit[4] tap_first_x * bit[3] anym_sign * bit[2] anym_first_z * bit[1] anym_first_y * bit[0] anym_first_x */ /* 0x1F INT_STATUS_3 * bit[7] flat * bit[6] orient_2 * bit[5] orient_1 * bit[4] orient_0 * bit[3] high_sign * bit[2] high_first_z * bit[1] high_first_y * bit[0] high_first_x */ /* 0x20 TEMPERATURE_0 temperature[7:0] */ /* 0x21 TEMPERATURE_1 reset value = 0x80 temperature[15:8] */ /* 0x22 FIFO_LENGTH_0 fifo_byte_counter[7:0] */ /* 0x23 FIFO_LENGTH_1 * bit[7:3] (reserved) * bit[2:0] fifo_byte_counter[10:8] */ /* 0x40 ACC_CONF reset value 0x28 * bit[7] acc_us * bit[6:4] acc_bwp * bit[3:0] acc_odr */ /* 0x41 ACC_RANGE reset value = 0x03 * bit[7:4] (reserved) * bit[3:0] acc_range */ /* 0x42 GYR_CONF reset value = 0x28 * bit[7:6] (reserved) * bit[5:4] gyr_bwp * bit[3:0] gyr_odr */ /* 0x43 GYR_RANGE * bit[7:3] (reserved) * bit[2:0] gyr_range */ /* 0x44 MAG_CONF reset value = 0x0B * bit[7:4] (reserved) * bit[3:0] mag_odr */ /* 0x45 FIFO_DOWNS reset value = 0x88 * bit[7] acc_fifo_filt_data * bit[6:4] acc_fifo_downs * bit[3] gyr_fifo_filt_data * bit[2:0] gyr_fifo_downs */ /* 0x46 FIFO_CONFIG_0 reset value = 0x80 * bit[7:0] fifo_water_mark */ /* 0x47 FIFO_CONFIG_1 reset value = 0x10 * bit[7] fifo_gyr_en * bit[6] fifo_acc_en * bit[5] fifo_mag_en * bit[4] fifo_header_en * bit[3] fifo_tag_int1_en * bit[2] fifo_tag_int2_en * bit[1] fifo_time_en * bit[0] (reserved) */ /* 0x4B MAG_IF_0 reset value = 0x20 * bit[7:1] i2c_device_addr */ /* 0x4C MAG_IF_1 reset value = 0x80 * bit[7] mag_manual_en * bit[6] (reserved) * bit[5:2] mag_offset * bit[1:0] mag_rd_burst */ /* 0x4D MAG_IF_2 reset value = 0x42 * bit[7:0] read_addr */ /* 0x4E MAG_IF_3 reset value = 0x4C * bit[7:0] write_addr */ /* 0x4F MAG_IF_4 bit[7:0] write data */ /* 0x50 INT_EN_0 * bit[7] int_flat_en * bit[6] int_orient_en * bit[5] int_s_tap_en * bit[4] int_d_tap_en * bit[3] (reserved) * bit[2] int_anymo_z_en * bit[1] int_anymo_y_en * bit[0] int_anymo_x_en */ /* 0x51 INT_EN_1 * bit[7] (reserved) * bit[6] int_fwm_en * bit[5] int_ffull_en * bit[4] int_drdy_en * bit[3] int_low_en * bit[2] int_highg_z_en * bit[1] int_highg_y_en * bit[0] int_highg_x_en */ /* 0x52 INT_EN_2 * bit[7:4] (reserved) * bit[3] int_step_det_en * bit[2] int_nomoz_en * bit[1] int_nomoy_en * bit[0] int_nomox_en */ /* 0x53 INT_OUT_CTRL * bit[7] int2_output_en * bit[6] int2_od * bit[5] int2_lvl * bit[4] int2_edge_ctrl * bit[3] int1_output_en * bit[2] int1_od * bit[1] int1_lvl * bit[0] itn1_edge_ctrl */ /* 0x54 INT_LATCH * bit[7:6] (reserved) * bit[5] int2_input_en * bit[4] int1_input_en * bit[3:0] int_latch */ /* 0x55 INT_MAP_0 * bit[7] int1_flat * bit[6] int1_orient * bit[5] int1_s_tap * bit[4] int1_d_tap * bit[3] int1_nomotion * bit[2] int1_anymotion * bit[1] int1_highg * bit[0] int1_lowg_step */ /* 0x56 INT_MAP_1 * bit[7] int1_drdy * bit[6] int1_fwm * bit[5] int1_ffull * bit[4] int1_pmu_trig * bit[3] int2_drdy * bit[2] itn2_fwm * bit[1] int2_ffull * bit[0] int2_pmu_trig */ /* 0x57 INT_MAP_2 * bit[7] int2_flat * bit[6] int2_orient * bit[5] int2_s_tap * bit[4] int2_d_tap * bit[3] int2_nomotion * bit[2] int2_anymotion * bit[1] int2_highg * bit[0] int2_lowg_steop */ /* 0x58 INT_DATA_0 * bit[7] int_low_high_src * bit[6:4] (reserved) * bit[3] int_tap_src * bit[2:0] (reserved) */ /* 0x59 INT_DATA_1 * bit[7] int_motion_src * bit[6:0] (reseved) */ /* 0x5A INT_LOWHIGH_0 reset value = 0x07 * bit[7:0] int_low_dur */ /* 0x5B INT_LOWHIGH_1 reset value = 0x30 * bit[7:0] int_low_th */ /* 0x5C INT_LOWHIGH_2 reset value = 0x81 * bit[7:6] int_high_hy * bit[5:3] (reserved) * bit[2] int_low_mode * bit[1:0] int_low_hy */ /* 0x5D INT_LOWHIGH_3 reset value = 0x0B * bit[7:0] int_high_dur */ /* 0x5E INT_LOWHIGH_4 reset value = 0xC0 * bit[7:0] int_high_th */ /* 0x5F INT_MOTION_0 * bit[7:2] int_slo_nomo_dur * bit[1:0] int_anym_dur */ /* 0x60 INT_MOTION_1 reset value = 0x14 * bit[7:0] int_anymo_th */ /* 0x61 INT_MOTION_2 reset value = 0x14 * bit[7:0] int_slo_nomo_th */ /* 0x62 INT_MOTION_3 reset value = 0x24 * bit[7:6] (reserved) * bit[5:4] int_sig_mot_proof */ /* 0x63 INT_TAP_0 reset value = 0x04 * bit[7] int_tap_quiet * bit[6] int_tap_shock * bit[5:3] (reserved) * bit[2:0] int_tap_dur */ /* 0x64 INT_TAP_1 reset value = 0x0A * bit[7:5] (reserved) * bit[4:0] int_tap_th */ /* 0x65 INT_ORIENT_0 reset value = 0x18 * bit[7:4] int_orient_hy * bit[3:2] int_orient_blocking * bit[1:0] int_orient_mode */ /* 0x66 INT_ORIENT_1 reset value = 0x48 * bit[7] int_orient_axes_ex * bit[6] int_orient_ud_en * bit[5:0] int_orient_theta */ /* 0x67 INT_FLAT_0 reset value = 0x08 * bit[7:6] (reserved) * bit[5:0] int_flat_theta */ /* 0x68 INT_FLAT_1 reset value = 0x11 * bit[7:6] (reserved) * bit[5:4] int_flat_hold * bit[3:0] int_flat_hy */ /* 0x69 FOC_CONF * bit[7] (reserved) * bit[6] foc_gyr_en * bit[5:4] foc_acc_x * bit[3:2] foc_acc_y * bit[1:0] foc_acc_z */ /* 0x6A CONF * bit[7:2] (reserved) * bit[1] nvm_prog_en * bit[0] (reserved) */ /* 0x6B IF_CONF * bit[7:6] (reserved) * bit[5:4] if_mode * bit[3:1] (reserved) * bit[0] spi3 */ /* 0x6C PMU_TRIGGER * bit[7] (reserved) * bit[6] wakeup_int * bit[5] gyr_sleep_state * bit[4:3] gyr_wakeup_trigger * bit[2:0] gyr_sleep_trigger */ /* 0x6D SELF_TEST * bit[7:5] (reserved) * bit[4] gyr_self_test_enable * bit[3] acc_self_test_amp * bit[2] acc_self_test_sign * bit[1:0] acc_self_test_enable */ /* 0x70 NV_CONF * bit[7:4] (reserved) * bit[3] u_spare_0 * bit[2] i2c_wdt_en * bit[1] i2c_wdt_sel * bit[0] i2c_spi_en */ /* 0x71 OFFSET_0 bit[7:0] off_acc_x */ /* 0x72 OFFSET_1 bit[7:0] off_acc_y */ /* 0x73 OFFSET_2 bit[7:0] off_acc_z */ /* 0x74 OFFSET_3 bit[7:0] off_gyr_x_7_0 */ /* 0x75 OFFSET_4 bit[7:0] off_gyr_y_7_0 */ /* 0x76 OFFSET_5 bit[7:0] off_gyr_z_7_0 */ /* 0x77 OFFSET_6 * bit[7] gyr_off_en * bit[6] acc_off_en * bit[5:4] off_gyr_Z_9_8 * bit[3:2] off_gyr_y_9_8 * bit[1:0] off_gyr_x_9_8 */ /* 0x78 STEP_CNT_0 bit[7:0] step_cnt_7_0 */ /* 0x79 STEP_CNT_1 bit[7:0] step_cnt_15_8 */ /* 0x7A STEP_CONF_0 reset value = 0x15 * bit[7:5] (alpha) * bit[4:3] min_threshold * bit[2:0] steptime_min */ /* 0x7B STEP_CONF_1 reset value = 0x03 * bit[7:4] (reserved) * bit[3] step_cnt_en * bit[2:0] min_step_buf */ /* 0x7E CMD bit[7:0] cmd */ BMI160::BMI160(PinName sda, PinName scl, int addr) { m_i2c = new I2C(sda, scl) ; m_addr = (addr << 1) ; m_spi = 0 ; m_cs = 0 ; init() ; } BMI160::BMI160(PinName sck, PinName miso, PinName mosi, PinName cs) { m_cs = new DigitalOut(cs, 1) ; m_spi = new SPI(mosi, miso, sck) ; m_spi->format(8, 3) ; m_i2c = 0 ; m_addr = 0 ; init() ; } BMI160::~BMI160() { if (m_spi) { delete m_spi ; delete m_cs ; } if (m_i2c) { delete m_i2c ; m_addr = 0 ; } } void BMI160::i2c_readRegs(int addr, uint8_t *data, int len) { char t[1] = {addr} ; m_i2c->write(m_addr, t, 1, true) ; m_i2c->read(m_addr, (char*)data, len) ; } void BMI160::i2c_writeRegs(uint8_t *data, int len) { m_i2c->write(m_addr, (char *)data, len) ; } void BMI160::spi_readRegs(int addr, uint8_t *data, int len) { *m_cs = 0 ; m_spi->write(addr | 0x80) ; for (int i = 0 ; i < len ; i++ ) { data[i] = m_spi->write((addr+i)|0x80) ; } m_spi->write(0x00) ; // to terminate read mode *m_cs = 1 ; } void BMI160::spi_writeRegs(uint8_t *data, int len) { *m_cs = 0 ; for (int i = 0 ; i < len-1 ; i++ ) { m_spi->write((data[0]+i)^0x80) ; /* register address */ m_spi->write(data[i+1]) ; /* data to write */ } *m_cs = 1 ; } void BMI160::readRegs(int addr, uint8_t *data, int len) { if (m_spi) { spi_readRegs(addr, data, len) ; } else if (m_i2c) { i2c_readRegs(addr, data, len) ; } } void BMI160::writeRegs(uint8_t *data, int len) { if (m_spi) { spi_writeRegs(data, len) ; } else if (m_i2c) { i2c_writeRegs(data, len) ; } } void BMI160::init(void) { acc_range = getAccRange() ; gyr_range = getGyrRange() ; } void BMI160::setCMD(uint8_t cmd) { uint8_t data[2] ; data[0] = REG_CMD ; data[1] = cmd ; writeRegs(data, 2) ; } uint8_t BMI160::getStatus(void) { uint8_t status ; readRegs(REG_STATUS, &status, 1) ; return(status) ; } uint8_t BMI160::getChipID(void) { uint8_t data ; readRegs(REG_CHIP_ID, &data, 1) ; return( data ) ; } uint8_t BMI160::getAccRange(void) { uint8_t data = 0 ; uint8_t range = 0 ; readRegs(REG_ACC_RANGE, &data, 1) ; switch(data & 0x0F) { case 3: /* +/- 2g */ range = 2 ; break ; case 5: /* +/- 4g */ range = 4 ; break ; case 8: /* +/- 8g */ range = 8 ; break ; default: printf("illegal Acc Range %X detected\n", data & 0x0F) ; break ; } acc_range = range ; return(range) ; } int16_t BMI160::getGyrRange(void) { uint8_t data = 0 ; int16_t range = 0 ; readRegs(REG_GYR_RANGE, &data, 1) ; switch(data & 0x07) { case 0: range = 2000 ; break ; case 1: range = 1000 ; break ; case 2: range = 500 ; break ; case 3: range = 250 ; break ; case 4: range = 125 ; break ; default: printf("illegal Gyr Range %d detected\n", data & 0x07) ; break ; } gyr_range = range ; return(range) ; } int16_t BMI160::getAccRawX(void) { uint8_t data[2] ; int16_t value = 0 ; readRegs(REG_DATA_14, data, 2) ; value = (data[1] << 8) | data[0] ; return( value ) ; } int16_t BMI160::getAccRawY(void) { uint8_t data[2] ; int16_t value = 0 ; readRegs(REG_DATA_16, data, 2) ; value = (data[1] << 8) | data[0] ; return( value ) ; } int16_t BMI160::getAccRawZ(void) { uint8_t data[2] ; int16_t value = 0 ; readRegs(REG_DATA_18, data, 2) ; value = (data[1] << 8) | data[0] ; return( value ) ; } void BMI160::getAccRaw(int16_t *value) { uint8_t data[6] ; readRegs(REG_DATA_14, data, 6) ; value[0] = (data[1] << 8) | data[0] ; value[1] = (data[3] << 8) | data[2] ; value[2] = (data[5] << 8) | data[4] ; } int16_t BMI160::getGyrRawX(void) { uint8_t data[2] ; int16_t value = 0 ; readRegs(REG_DATA_8, data, 2) ; value = (data[1] << 8) | data[0] ; return( value ) ; } int16_t BMI160::getGyrRawY(void) { uint8_t data[2] ; int16_t value = 0 ; readRegs(REG_DATA_10, data, 2) ; value = (data[1] << 8) | data[0] ; return( value ) ; } int16_t BMI160::getGyrRawZ(void) { uint8_t data[2] ; int16_t value = 0 ; readRegs(REG_DATA_12, data, 2) ; value = (data[1] << 8) | data[0] ; return( value ) ; } void BMI160::getGyrRaw(int16_t *value) { uint8_t data[6] ; readRegs(REG_DATA_8, data, 6) ; value[0] = (data[1] << 8) | data[0] ; value[1] = (data[3] << 8) | data[2] ; value[2] = (data[5] << 8) | data[4] ; } float BMI160::getAccX(void) { float value ; value = acc_range * getAccRawX() / FLOAT_MAX_16BIT ; return(value) ; } float BMI160::getAccY(void) { float value ; value = acc_range * getAccRawY() / FLOAT_MAX_16BIT ; return(value) ; } float BMI160::getAccZ(void) { float value ; value = acc_range * getAccRawZ() / FLOAT_MAX_16BIT ; return(value) ; } void BMI160::getAcc(float *value) { int16_t data[3] ; getAccRaw(data) ; value[0] = acc_range * data[0] / FLOAT_MAX_16BIT ; value[1] = acc_range * data[1] / FLOAT_MAX_16BIT ; value[2] = acc_range * data[2] / FLOAT_MAX_16BIT ; } float BMI160::getGyrX(void) { float value ; value = gyr_range * getGyrRawX() / FLOAT_MAX_16BIT ; return(value) ; } float BMI160::getGyrY(void) { float value ; value = gyr_range * getGyrRawY() / FLOAT_MAX_16BIT ; return(value) ; } float BMI160::getGyrZ(void) { float value ; value = gyr_range * getGyrRawZ() / FLOAT_MAX_16BIT ; return(value) ; } void BMI160::getGyr(float *value) { int16_t data[3] ; getGyrRaw(data) ; value[0] = gyr_range * data[0] / FLOAT_MAX_16BIT ; value[1] = gyr_range * data[1] / FLOAT_MAX_16BIT ; value[2] = gyr_range * data[2] / FLOAT_MAX_16BIT ; }