|
|
|
@ -62,31 +62,19 @@ static int16_t compensate_z(trim_data_t trim_data, int16_t mag_data_z, uint16_t |
|
|
|
|
return (int16_t)retval; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int16_t parse_xy(uint8_t lsb, uint8_t msb){ |
|
|
|
|
// 13 bit
|
|
|
|
|
uint16_t combined = (uint16_t(msb) << 5) | uint16_t(lsb >> 3); |
|
|
|
|
return int16_t(combined << 3) / (1 << 3); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int16_t parse_z(uint8_t lsb, uint8_t msb){ |
|
|
|
|
// 15 bit
|
|
|
|
|
uint16_t combined = (uint16_t(msb) << 7) | uint16_t(lsb >> 1); |
|
|
|
|
return int16_t(combined << 1) / (1 << 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static uint16_t parse_rhall(uint8_t lsb, uint8_t msb){ |
|
|
|
|
// 14 bit
|
|
|
|
|
return (uint16_t(msb) << 6) | uint16_t(lsb >> 2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
BMX055_Magn::BMX055_Magn(I2CBus *bus) : I2CSensor(bus) {} |
|
|
|
|
|
|
|
|
|
int BMX055_Magn::init(){ |
|
|
|
|
int ret; |
|
|
|
|
uint8_t buffer[1]; |
|
|
|
|
uint8_t trim_x1y1[2] = {0}; |
|
|
|
|
uint8_t trim_xyz_data[4] = {0}; |
|
|
|
|
uint8_t trim_xy1xy2[10] = {0}; |
|
|
|
|
uint8_t trim_x2y2[2] = {0}; |
|
|
|
|
uint8_t trim_xy1xy2[2] = {0}; |
|
|
|
|
uint8_t trim_z1[2] = {0}; |
|
|
|
|
uint8_t trim_z2[2] = {0}; |
|
|
|
|
uint8_t trim_z3[2] = {0}; |
|
|
|
|
uint8_t trim_z4[2] = {0}; |
|
|
|
|
uint8_t trim_xyz1[2] = {0}; |
|
|
|
|
|
|
|
|
|
// suspend -> sleep
|
|
|
|
|
ret = set_register(BMX055_MAGN_I2C_REG_PWR_0, 0x01); |
|
|
|
@ -110,83 +98,139 @@ int BMX055_Magn::init(){ |
|
|
|
|
|
|
|
|
|
// Load magnetometer trim
|
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_X1, trim_x1y1, 2); |
|
|
|
|
if(ret < 0){ |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_Z4, trim_xyz_data, 4); |
|
|
|
|
if(ret < 0){ |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_Z2, trim_xy1xy2, 10); |
|
|
|
|
if(ret < 0){ |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_X2, trim_x2y2, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_XY2, trim_xy1xy2, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_Z1_LSB, trim_z1, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_Z2_LSB, trim_z2, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_Z3_LSB, trim_z3, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_Z4_LSB, trim_z4, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
ret = read_register(BMX055_MAGN_I2C_REG_DIG_XYZ1_LSB, trim_xyz1, 2); |
|
|
|
|
if(ret < 0) goto fail; |
|
|
|
|
|
|
|
|
|
// Read trim data
|
|
|
|
|
trim_data.dig_x1 = (int8_t)trim_x1y1[0]; |
|
|
|
|
trim_data.dig_y1 = (int8_t)trim_x1y1[1]; |
|
|
|
|
trim_data.dig_x1 = trim_x1y1[0]; |
|
|
|
|
trim_data.dig_y1 = trim_x1y1[1]; |
|
|
|
|
|
|
|
|
|
trim_data.dig_x2 = (int8_t)trim_xyz_data[2]; |
|
|
|
|
trim_data.dig_y2 = (int8_t)trim_xyz_data[3]; |
|
|
|
|
trim_data.dig_x2 = trim_x2y2[0]; |
|
|
|
|
trim_data.dig_y2 = trim_x2y2[1]; |
|
|
|
|
|
|
|
|
|
trim_data.dig_z1 = read_16_bit(trim_xy1xy2[2], trim_xy1xy2[3]); |
|
|
|
|
trim_data.dig_z2 = read_16_bit(trim_xy1xy2[0], trim_xy1xy2[1]); |
|
|
|
|
trim_data.dig_z3 = read_16_bit(trim_xy1xy2[6], trim_xy1xy2[7]); |
|
|
|
|
trim_data.dig_z4 = read_16_bit(trim_xyz_data[0], trim_xyz_data[1]); |
|
|
|
|
trim_data.dig_xy1 = trim_xy1xy2[1]; // NB: MSB/LSB swapped
|
|
|
|
|
trim_data.dig_xy2 = trim_xy1xy2[0]; |
|
|
|
|
|
|
|
|
|
trim_data.dig_xy1 = trim_xy1xy2[9]; |
|
|
|
|
trim_data.dig_xy2 = (int8_t)trim_xy1xy2[8]; |
|
|
|
|
trim_data.dig_z1 = read_16_bit(trim_z1[0], trim_z1[1]); |
|
|
|
|
trim_data.dig_z2 = read_16_bit(trim_z2[0], trim_z2[1]); |
|
|
|
|
trim_data.dig_z3 = read_16_bit(trim_z3[0], trim_z3[1]); |
|
|
|
|
trim_data.dig_z4 = read_16_bit(trim_z4[0], trim_z4[1]); |
|
|
|
|
|
|
|
|
|
trim_data.dig_xyz1 = read_16_bit(trim_xy1xy2[4], trim_xy1xy2[5] & 0x7f); |
|
|
|
|
trim_data.dig_xyz1 = read_16_bit(trim_xyz1[0], trim_xyz1[1] & 0x7f); |
|
|
|
|
assert(trim_data.dig_xyz1 != 0); |
|
|
|
|
|
|
|
|
|
// TODO: perform self-test
|
|
|
|
|
perform_self_test(); |
|
|
|
|
|
|
|
|
|
// 9 REPXY and 15 REPZ for 100 Hz
|
|
|
|
|
// 3 REPXY and 3 REPZ for > 300 Hz
|
|
|
|
|
ret = set_register(BMX055_MAGN_I2C_REG_REPXY, (3 - 1) / 2); |
|
|
|
|
// f_max = 1 / (145us * nXY + 500us * NZ + 980us)
|
|
|
|
|
// Chose NXY = 7, NZ = 12, which gives 125 Hz,
|
|
|
|
|
// and has the same ratio as the high accuracy preset
|
|
|
|
|
ret = set_register(BMX055_MAGN_I2C_REG_REPXY, (7 - 1) / 2); |
|
|
|
|
if (ret < 0){ |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = set_register(BMX055_MAGN_I2C_REG_REPZ, 3 - 1); |
|
|
|
|
ret = set_register(BMX055_MAGN_I2C_REG_REPZ, 12 - 1); |
|
|
|
|
if (ret < 0){ |
|
|
|
|
goto fail; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
fail: |
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void BMX055_Magn::get_event(cereal::SensorEventData::Builder &event){ |
|
|
|
|
uint64_t start_time = nanos_since_boot(); |
|
|
|
|
bool BMX055_Magn::perform_self_test(){ |
|
|
|
|
uint8_t buffer[8]; |
|
|
|
|
int16_t x, y; |
|
|
|
|
int16_t neg_z, pos_z; |
|
|
|
|
|
|
|
|
|
int len = read_register(BMX055_MAGN_I2C_REG_DATAX_LSB, buffer, sizeof(buffer)); |
|
|
|
|
assert(len == sizeof(buffer)); |
|
|
|
|
// Increase z reps for less false positives (~30 Hz ODR)
|
|
|
|
|
set_register(BMX055_MAGN_I2C_REG_REPXY, 1); |
|
|
|
|
set_register(BMX055_MAGN_I2C_REG_REPZ, 64 - 1); |
|
|
|
|
|
|
|
|
|
// Clean existing measurement
|
|
|
|
|
read_register(BMX055_MAGN_I2C_REG_DATAX_LSB, buffer, sizeof(buffer)); |
|
|
|
|
|
|
|
|
|
uint8_t forced = BMX055_MAGN_FORCED; |
|
|
|
|
|
|
|
|
|
// Negative current
|
|
|
|
|
set_register(BMX055_MAGN_I2C_REG_MAG, forced | (uint8_t(0b10) << 6)); |
|
|
|
|
util::sleep_for(100); |
|
|
|
|
|
|
|
|
|
read_register(BMX055_MAGN_I2C_REG_DATAX_LSB, buffer, sizeof(buffer)); |
|
|
|
|
parse_xyz(buffer, &x, &y, &neg_z); |
|
|
|
|
|
|
|
|
|
// Positive current
|
|
|
|
|
set_register(BMX055_MAGN_I2C_REG_MAG, forced | (uint8_t(0b11) << 6)); |
|
|
|
|
util::sleep_for(100); |
|
|
|
|
|
|
|
|
|
read_register(BMX055_MAGN_I2C_REG_DATAX_LSB, buffer, sizeof(buffer)); |
|
|
|
|
parse_xyz(buffer, &x, &y, &pos_z); |
|
|
|
|
|
|
|
|
|
// Put back in normal mode
|
|
|
|
|
set_register(BMX055_MAGN_I2C_REG_MAG, 0); |
|
|
|
|
|
|
|
|
|
int16_t diff = pos_z - neg_z; |
|
|
|
|
bool passed = (diff > 180) && (diff < 240); |
|
|
|
|
|
|
|
|
|
if (!passed){ |
|
|
|
|
LOGE("self test failed: neg %d pos %d diff %d", neg_z, pos_z, diff); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return passed; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool BMX055_Magn::parse_xyz(uint8_t buffer[8], int16_t *x, int16_t *y, int16_t *z){ |
|
|
|
|
bool ready = buffer[6] & 0x1; |
|
|
|
|
if (ready){ |
|
|
|
|
int16_t x = parse_xy(buffer[0], buffer[1]); |
|
|
|
|
int16_t y = parse_xy(buffer[2], buffer[3]); |
|
|
|
|
int16_t z = parse_z(buffer[4], buffer[5]); |
|
|
|
|
int16_t rhall = parse_rhall(buffer[5], buffer[6]); |
|
|
|
|
int16_t mdata_x = (int16_t) (((int16_t)buffer[1] << 8) | buffer[0]) >> 3; |
|
|
|
|
int16_t mdata_y = (int16_t) (((int16_t)buffer[3] << 8) | buffer[2]) >> 3; |
|
|
|
|
int16_t mdata_z = (int16_t) (((int16_t)buffer[5] << 8) | buffer[4]) >> 1; |
|
|
|
|
uint16_t data_r = (uint16_t) (((uint16_t)buffer[7] << 8) | buffer[6]) >> 2; |
|
|
|
|
assert(data_r != 0); |
|
|
|
|
|
|
|
|
|
*x = compensate_x(trim_data, mdata_x, data_r); |
|
|
|
|
*y = compensate_y(trim_data, mdata_y, data_r); |
|
|
|
|
*z = compensate_z(trim_data, mdata_z, data_r); |
|
|
|
|
} |
|
|
|
|
return ready; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
x = compensate_x(trim_data, x, rhall); |
|
|
|
|
y = compensate_y(trim_data, y, rhall); |
|
|
|
|
z = compensate_z(trim_data, z, rhall); |
|
|
|
|
|
|
|
|
|
// TODO: convert to micro tesla:
|
|
|
|
|
// https://github.com/BoschSensortec/BMM150-Sensor-API/blob/master/bmm150.c#L1614
|
|
|
|
|
void BMX055_Magn::get_event(cereal::SensorEventData::Builder &event){ |
|
|
|
|
uint64_t start_time = nanos_since_boot(); |
|
|
|
|
uint8_t buffer[8]; |
|
|
|
|
int16_t x, y, z; |
|
|
|
|
|
|
|
|
|
int len = read_register(BMX055_MAGN_I2C_REG_DATAX_LSB, buffer, sizeof(buffer)); |
|
|
|
|
assert(len == sizeof(buffer)); |
|
|
|
|
|
|
|
|
|
if (parse_xyz(buffer, &x, &y, &z)){ |
|
|
|
|
event.setSource(cereal::SensorEventData::SensorSource::BMX055); |
|
|
|
|
event.setVersion(1); |
|
|
|
|
event.setSensor(SENSOR_MAGNETOMETER_UNCALIBRATED); |
|
|
|
|
event.setType(SENSOR_TYPE_MAGNETIC_FIELD_UNCALIBRATED); |
|
|
|
|
event.setTimestamp(start_time); |
|
|
|
|
|
|
|
|
|
// Axis convention
|
|
|
|
|
x = -x; |
|
|
|
|
y = -y; |
|
|
|
|
|
|
|
|
|
float xyz[] = {(float)x, (float)y, (float)z}; |
|
|
|
|
auto svec = event.initMagneticUncalibrated(); |
|
|
|
|
svec.setV(xyz); |
|
|
|
|