ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
bmi160.cpp
Go to the documentation of this file.
1#include "bmi160.h"
2#include "esphome/core/hal.h"
3#include "esphome/core/log.h"
4
5namespace esphome::bmi160 {
6
7ESPHOME_LOG_TAG(TAG, "bmi160");
8static constexpr uint32_t GYRO_WAKEUP_TIMEOUT_MS = 100;
9
10const uint8_t BMI160_REGISTER_CHIPID = 0x00;
11
12const uint8_t BMI160_REGISTER_CMD = 0x7E;
13enum class Cmd : uint8_t {
14 START_FOC = 0x03,
15 ACCL_SET_PMU_MODE = 0b00010000, // last 2 bits are mode
16 GYRO_SET_PMU_MODE = 0b00010100, // last 2 bits are mode
17 MAG_SET_PMU_MODE = 0b00011000, // last 2 bits are mode
18 PROG_NVM = 0xA0,
19 FIFO_FLUSH = 0xB0,
20 INT_RESET = 0xB1,
21 SOFT_RESET = 0xB6,
22 STEP_CNT_CLR = 0xB2,
23};
24enum class GyroPmuMode : uint8_t {
25 SUSPEND = 0b00,
26 NORMAL = 0b01,
27 LOW_POWER = 0b10,
28};
29enum class AcclPmuMode : uint8_t {
30 SUSPEND = 0b00,
31 NORMAL = 0b01,
32 FAST_STARTUP = 0b11,
33};
34enum class MagPmuMode : uint8_t {
35 SUSPEND = 0b00,
36 NORMAL = 0b01,
37 LOW_POWER = 0b10,
38};
39
40const uint8_t BMI160_REGISTER_ACCEL_CONFIG = 0x40;
41enum class AcclFilterMode : uint8_t {
42 POWER_SAVING = 0b00000000,
43 PERF = 0b10000000,
44};
45enum class AcclBandwidth : uint8_t {
46 OSR4_AVG1 = 0b00000000,
47 OSR2_AVG2 = 0b00010000,
48 NORMAL_AVG4 = 0b00100000,
49 RES_AVG8 = 0b00110000,
50 RES_AVG16 = 0b01000000,
51 RES_AVG32 = 0b01010000,
52 RES_AVG64 = 0b01100000,
53 RES_AVG128 = 0b01110000,
54};
55enum class AccelOutputDataRate : uint8_t {
56 HZ_25_32 = 0b0001, // 25/32 Hz
57 HZ_25_16 = 0b0010, // 25/16 Hz
58 HZ_25_8 = 0b0011, // 25/8 Hz
59 HZ_25_4 = 0b0100, // 25/4 Hz
60 HZ_25_2 = 0b0101, // 25/2 Hz
61 HZ_25 = 0b0110, // 25 Hz
62 HZ_50 = 0b0111, // 50 Hz
63 HZ_100 = 0b1000, // 100 Hz
64 HZ_200 = 0b1001, // 200 Hz
65 HZ_400 = 0b1010, // 400 Hz
66 HZ_800 = 0b1011, // 800 Hz
67 HZ_1600 = 0b1100, // 1600 Hz
68};
69const uint8_t BMI160_REGISTER_ACCEL_RANGE = 0x41;
70enum class AccelRange : uint8_t {
71 RANGE_2G = 0b0011,
72 RANGE_4G = 0b0101,
73 RANGE_8G = 0b1000,
74 RANGE_16G = 0b1100,
75};
76
77const uint8_t BMI160_REGISTER_GYRO_CONFIG = 0x42;
78enum class GyroBandwidth : uint8_t {
79 OSR4 = 0x00,
80 OSR2 = 0x10,
81 NORMAL = 0x20,
82};
83enum class GyroOuputDataRate : uint8_t {
84 HZ_25 = 0x06,
85 HZ_50 = 0x07,
86 HZ_100 = 0x08,
87 HZ_200 = 0x09,
88 HZ_400 = 0x0A,
89 HZ_800 = 0x0B,
90 HZ_1600 = 0x0C,
91 HZ_3200 = 0x0D,
92};
93const uint8_t BMI160_REGISTER_GYRO_RANGE = 0x43;
94enum class GyroRange : uint8_t {
95 RANGE_2000_DPS = 0x0, // ±2000 °/s
96 RANGE_1000_DPS = 0x1,
97 RANGE_500_DPS = 0x2,
98 RANGE_250_DPS = 0x3,
99 RANGE_125_DPS = 0x4,
100};
101
114const uint8_t BMI160_REGISTER_DATA_TEMP_LSB = 0x20;
115const uint8_t BMI160_REGISTER_DATA_TEMP_MSB = 0x21;
116
117const float GRAVITY_EARTH = 9.80665f;
118
120 if (!this->setup_stage_(stage))
121 this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
122}
123
125 switch (stage) {
126 case 0: {
127 uint8_t chipid;
128 if (!this->read_byte(BMI160_REGISTER_CHIPID, &chipid) || (chipid != 0b11010001)) {
129 return false;
130 }
131
132 ESP_LOGV(TAG, " Bringing accelerometer out of sleep");
133 if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::ACCL_SET_PMU_MODE | (uint8_t) AcclPmuMode::NORMAL)) {
134 return false;
135 }
136 ESP_LOGV(TAG, " Waiting for accelerometer to wake up");
137 // need to wait (max delay in datasheet) because we can't send commands while another is in progress
138 // min 5ms, 10ms
139 this->set_timeout(10, [this]() { this->internal_setup_(1); });
140 break;
141 }
142 case 1:
143 ESP_LOGV(TAG, " Bringing gyroscope out of sleep");
144 if (!this->write_byte(BMI160_REGISTER_CMD, (uint8_t) Cmd::GYRO_SET_PMU_MODE | (uint8_t) GyroPmuMode::NORMAL)) {
145 return false;
146 }
147 ESP_LOGV(TAG, " Waiting for gyroscope to wake up");
148 // wait between 51 & 81ms, doing 100 to be safe
149 this->set_timeout(GYRO_WAKEUP_TIMEOUT_MS, [this]() { this->internal_setup_(2); });
150 break;
151
152 case 2: {
153 ESP_LOGV(TAG, " Setting up Gyro Config");
154 uint8_t gyro_config = (uint8_t) GyroBandwidth::OSR4 | (uint8_t) GyroOuputDataRate::HZ_25;
155 ESP_LOGV(TAG, " Output gyro_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_config));
156 if (!this->write_byte(BMI160_REGISTER_GYRO_CONFIG, gyro_config)) {
157 return false;
158 }
159 ESP_LOGV(TAG, " Setting up Gyro Range");
160 uint8_t gyro_range = (uint8_t) GyroRange::RANGE_2000_DPS;
161 ESP_LOGV(TAG, " Output gyro_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(gyro_range));
162 if (!this->write_byte(BMI160_REGISTER_GYRO_RANGE, gyro_range)) {
163 return false;
164 }
165
166 ESP_LOGV(TAG, " Setting up Accel Config");
167 uint8_t accel_config =
169 ESP_LOGV(TAG, " Output accel_config: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_config));
170 if (!this->write_byte(BMI160_REGISTER_ACCEL_CONFIG, accel_config)) {
171 return false;
172 }
173 ESP_LOGV(TAG, " Setting up Accel Range");
174 uint8_t accel_range = (uint8_t) AccelRange::RANGE_16G;
175 ESP_LOGV(TAG, " Output accel_range: 0b" BYTE_TO_BINARY_PATTERN, BYTE_TO_BINARY(accel_range));
176 if (!this->write_byte(BMI160_REGISTER_ACCEL_RANGE, accel_range)) {
177 return false;
178 }
179
180 this->setup_complete_ = true;
181 break;
182 }
183 default:
184 break;
185 }
186 return true;
187}
188
191 ESP_LOGCONFIG(TAG, "BMI160:");
192 LOG_I2C_DEVICE(this);
193 LOG_UPDATE_INTERVAL(this);
194 LOG_SENSOR(" ", "Acceleration X", this->accel_x_sensor_);
195 LOG_SENSOR(" ", "Acceleration Y", this->accel_y_sensor_);
196 LOG_SENSOR(" ", "Acceleration Z", this->accel_z_sensor_);
197 LOG_SENSOR(" ", "Gyro X", this->gyro_x_sensor_);
198 LOG_SENSOR(" ", "Gyro Y", this->gyro_y_sensor_);
199 LOG_SENSOR(" ", "Gyro Z", this->gyro_z_sensor_);
200 LOG_SENSOR(" ", "Temperature", this->temperature_sensor_);
201}
202
204 if (!this->setup_complete_) {
205 return;
206 }
207
208 ESP_LOGV(TAG, " Updating BMI160");
209 int16_t data[6];
210 if (!this->read_bytes_16_le(BMI160_REGISTER_DATA_GYRO_X_LSB, data, 6)) {
211 this->status_set_warning();
212 return;
213 }
214
215 float gyro_x = (float) data[0] / (float) INT16_MAX * 2000.f;
216 float gyro_y = (float) data[1] / (float) INT16_MAX * 2000.f;
217 float gyro_z = (float) data[2] / (float) INT16_MAX * 2000.f;
218 float accel_x = (float) data[3] / (float) INT16_MAX * 16 * GRAVITY_EARTH;
219 float accel_y = (float) data[4] / (float) INT16_MAX * 16 * GRAVITY_EARTH;
220 float accel_z = (float) data[5] / (float) INT16_MAX * 16 * GRAVITY_EARTH;
221
222 int16_t raw_temperature;
223 if (!this->read_bytes_16_le(BMI160_REGISTER_DATA_TEMP_LSB, &raw_temperature, 1)) {
224 this->status_set_warning();
225 return;
226 }
227 float temperature = (float) raw_temperature / (float) INT16_MAX * 64.5f + 23.f;
228
229 ESP_LOGD(TAG,
230 "Got accel={x=%.3f m/s², y=%.3f m/s², z=%.3f m/s²}, "
231 "gyro={x=%.3f °/s, y=%.3f °/s, z=%.3f °/s}, temp=%.3f°C",
232 accel_x, accel_y, accel_z, gyro_x, gyro_y, gyro_z, temperature);
233
234 if (this->accel_x_sensor_ != nullptr)
235 this->accel_x_sensor_->publish_state(accel_x);
236 if (this->accel_y_sensor_ != nullptr)
237 this->accel_y_sensor_->publish_state(accel_y);
238 if (this->accel_z_sensor_ != nullptr)
239 this->accel_z_sensor_->publish_state(accel_z);
240
241 if (this->temperature_sensor_ != nullptr)
242 this->temperature_sensor_->publish_state(temperature);
243
244 if (this->gyro_x_sensor_ != nullptr)
245 this->gyro_x_sensor_->publish_state(gyro_x);
246 if (this->gyro_y_sensor_ != nullptr)
247 this->gyro_y_sensor_->publish_state(gyro_y);
248 if (this->gyro_z_sensor_ != nullptr)
249 this->gyro_z_sensor_->publish_state(gyro_z);
250
251 this->status_clear_warning();
252}
253
254} // namespace esphome::bmi160
void mark_failed()
Mark this component as failed.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
Definition component.cpp:96
void status_clear_warning()
Definition component.h:296
sensor::Sensor * accel_z_sensor_
Definition bmi160.h:27
bool setup_stage_(int stage)
Run one setup stage; false on an I2C failure.
Definition bmi160.cpp:124
sensor::Sensor * gyro_y_sensor_
Definition bmi160.h:30
sensor::Sensor * gyro_x_sensor_
Definition bmi160.h:29
sensor::Sensor * accel_x_sensor_
Definition bmi160.h:25
sensor::Sensor * gyro_z_sensor_
Definition bmi160.h:31
void internal_setup_(int stage)
Definition bmi160.cpp:119
sensor::Sensor * temperature_sensor_
Definition bmi160.h:28
sensor::Sensor * accel_y_sensor_
Definition bmi160.h:26
bool read_bytes_16_le(uint8_t a_register, uint16_t *data, uint8_t len)
Read len 16-bit values stored least significant byte first; no conversion is compiled on little-endia...
Definition i2c.h:284
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:312
bool read_byte(uint8_t a_register, uint8_t *data)
Definition i2c.h:272
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
const uint8_t BMI160_REGISTER_DATA_ACCEL_X_LSB
Definition bmi160.cpp:108
const uint8_t BMI160_REGISTER_DATA_ACCEL_Z_MSB
Definition bmi160.cpp:113
const uint8_t BMI160_REGISTER_DATA_TEMP_MSB
Definition bmi160.cpp:115
const uint8_t BMI160_REGISTER_DATA_ACCEL_X_MSB
Definition bmi160.cpp:109
const uint8_t BMI160_REGISTER_GYRO_RANGE
Definition bmi160.cpp:93
const uint8_t BMI160_REGISTER_DATA_ACCEL_Z_LSB
Definition bmi160.cpp:112
const uint8_t BMI160_REGISTER_DATA_GYRO_Y_LSB
Definition bmi160.cpp:104
const uint8_t BMI160_REGISTER_DATA_GYRO_Z_LSB
Definition bmi160.cpp:106
const uint8_t BMI160_REGISTER_ACCEL_RANGE
Definition bmi160.cpp:69
const uint8_t BMI160_REGISTER_DATA_TEMP_LSB
Definition bmi160.cpp:114
ESPHOME_LOG_TAG(TAG, "bmi160")
const uint8_t BMI160_REGISTER_DATA_GYRO_X_LSB
Definition bmi160.cpp:102
const uint8_t BMI160_REGISTER_GYRO_CONFIG
Definition bmi160.cpp:77
const uint8_t BMI160_REGISTER_DATA_GYRO_Z_MSB
Definition bmi160.cpp:107
const uint8_t BMI160_REGISTER_DATA_ACCEL_Y_LSB
Definition bmi160.cpp:110
const uint8_t BMI160_REGISTER_DATA_GYRO_Y_MSB
Definition bmi160.cpp:105
const uint8_t BMI160_REGISTER_CMD
Definition bmi160.cpp:12
const uint8_t BMI160_REGISTER_CHIPID
Definition bmi160.cpp:10
const uint8_t BMI160_REGISTER_DATA_ACCEL_Y_MSB
Definition bmi160.cpp:111
const uint8_t BMI160_REGISTER_DATA_GYRO_X_MSB
Definition bmi160.cpp:103
const float GRAVITY_EARTH
Definition bmi160.cpp:117
const uint8_t BMI160_REGISTER_ACCEL_CONFIG
Definition bmi160.cpp:40
static void uint32_t
uint16_t temperature
Definition sun_gtil2.cpp:12