31#include "driver/gpio.h"
32#include "driver/i2c_master.h"
36#include "freertos/FreeRTOS.h"
37#include "freertos/task.h"
45static constexpr const char* TAG_I2C =
"BNO08x_I2C";
69 i2c_port_t
port = I2C_NUM_0;
90 : config_(config), bus_handle_(nullptr), dev_handle_(nullptr), initialized_(false) {}
138 int Write(
const uint8_t* data, uint32_t length)
noexcept {
139 if (!initialized_ || dev_handle_ ==
nullptr) {
140 ESP_LOGE(TAG_I2C,
"I2C bus not initialized");
144 esp_err_t ret = i2c_master_transmit(dev_handle_, data, length, pdMS_TO_TICKS(1000));
146 ESP_LOGE(TAG_I2C,
"I2C write failed: %s (addr=0x%02X, len=%lu)", esp_err_to_name(ret),
151 return static_cast<int>(length);
172 int Read(uint8_t* data, uint32_t length)
noexcept {
173 if (!initialized_ || dev_handle_ ==
nullptr) {
174 ESP_LOGE(TAG_I2C,
"I2C bus not initialized");
184 esp_err_t ret = i2c_master_receive(dev_handle_, data, length, pdMS_TO_TICKS(1000));
188 if (ret == ESP_ERR_TIMEOUT) {
191 ESP_LOGE(TAG_I2C,
"I2C read failed: %s (addr=0x%02X, len=%lu)", esp_err_to_name(ret),
196 return static_cast<int>(length);
211 if (!initialized_ || dev_handle_ ==
nullptr) {
219 esp_err_t ret = i2c_master_receive(dev_handle_, &dummy, 1, pdMS_TO_TICKS(100));
222 if (ret != ESP_OK && ret != ESP_ERR_TIMEOUT) {
223 ESP_LOGW(TAG_I2C,
"Probe at 0x%02X returned: %s (0x%x)", config_.
device_address,
224 esp_err_to_name(ret), ret);
233 if (ret == ESP_OK || ret == ESP_ERR_TIMEOUT) {
240 if (ret == ESP_ERR_INVALID_RESPONSE) {
241 ESP_LOGI(TAG_I2C,
"Probe got NAK during data phase, but address was ACKed - device present");
257 if (config_.
int_pin == GPIO_NUM_NC) {
261 return (gpio_get_level(config_.
int_pin) == 0);
269 vTaskDelay(pdMS_TO_TICKS(ms));
277 return static_cast<uint32_t
>(esp_timer_get_time());
293 if (config_.
rst_pin != GPIO_NUM_NC) {
295 gpio_set_level(config_.
rst_pin,
320 ESP_LOGW(TAG_I2C,
"I2C bus already initialized");
325 "Initializing I2C bus on port %d (SDA:GPIO%d, SCL:GPIO%d, "
326 "Freq:%lu Hz, Addr:0x%02X)",
332 ESP_LOGE(TAG_I2C,
"Failed to initialize GPIO pins");
337 i2c_master_bus_config_t bus_config = {};
338 bus_config.i2c_port = config_.
port;
339 bus_config.sda_io_num = config_.
sda_pin;
340 bus_config.scl_io_num = config_.
scl_pin;
341 bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
342 bus_config.glitch_ignore_cnt = 7;
343 bus_config.flags.enable_internal_pullup = config_.
pullup_enable;
344 bus_config.intr_priority = 0;
345 bus_config.trans_queue_depth = 0;
347 esp_err_t ret = i2c_new_master_bus(&bus_config, &bus_handle_);
349 ESP_LOGE(TAG_I2C,
"Failed to create I2C master bus: %s", esp_err_to_name(ret));
357 i2c_device_config_t dev_config = {
358 .dev_addr_length = I2C_ADDR_BIT_LEN_7,
361 .scl_wait_us = 50000,
365 ret = i2c_master_bus_add_device(bus_handle_, &dev_config, &dev_handle_);
367 ESP_LOGE(TAG_I2C,
"Failed to add device 0x%02X: %s", config_.
device_address,
368 esp_err_to_name(ret));
369 i2c_del_master_bus(bus_handle_);
370 bus_handle_ =
nullptr;
375 ESP_LOGI(TAG_I2C,
"I2C bus initialized successfully");
388 if (dev_handle_ !=
nullptr) {
389 i2c_master_bus_rm_device(dev_handle_);
390 dev_handle_ =
nullptr;
393 if (bus_handle_ !=
nullptr) {
394 i2c_del_master_bus(bus_handle_);
395 bus_handle_ =
nullptr;
399 if (config_.
int_pin != GPIO_NUM_NC) {
400 gpio_reset_pin(config_.
int_pin);
402 if (config_.
rst_pin != GPIO_NUM_NC) {
403 gpio_reset_pin(config_.
rst_pin);
406 initialized_ =
false;
407 ESP_LOGI(TAG_I2C,
"I2C bus deinitialized");
437 void HardwareReset(uint32_t lowMs = 2, uint32_t bootDelayMs = 200) noexcept {
438 if (config_.
rst_pin == GPIO_NUM_NC) {
439 ESP_LOGW(TAG_I2C,
"Reset pin not configured, skipping hardware reset");
443 ESP_LOGI(TAG_I2C,
"Performing hardware reset: asserting RSTN for %lu ms",
444 static_cast<unsigned long>(lowMs));
452 ESP_LOGI(TAG_I2C,
"Reset released, waiting %lu ms for sensor boot",
453 static_cast<unsigned long>(bootDelayMs));
459 i2c_master_bus_handle_t bus_handle_;
460 i2c_master_dev_handle_t dev_handle_;
467 bool initGPIO() noexcept {
469 if (config_.int_pin != GPIO_NUM_NC) {
470 gpio_config_t io_conf = {};
471 io_conf.pin_bit_mask = (1ULL << config_.int_pin);
472 io_conf.mode = GPIO_MODE_INPUT;
473 io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
474 io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
475 io_conf.intr_type = GPIO_INTR_DISABLE;
477 esp_err_t ret = gpio_config(&io_conf);
479 ESP_LOGE(TAG_I2C,
"Failed to configure interrupt pin: %s", esp_err_to_name(ret));
482 ESP_LOGI(TAG_I2C,
"Interrupt pin configured: GPIO%d", config_.int_pin);
486 if (config_.rst_pin != GPIO_NUM_NC) {
487 gpio_config_t io_conf = {};
488 io_conf.pin_bit_mask = (1ULL << config_.rst_pin);
489 io_conf.mode = GPIO_MODE_OUTPUT;
490 io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
491 io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
492 io_conf.intr_type = GPIO_INTR_DISABLE;
494 esp_err_t ret = gpio_config(&io_conf);
496 ESP_LOGE(TAG_I2C,
"Failed to configure reset pin: %s", esp_err_to_name(ret));
501 gpio_set_level(config_.rst_pin, 1);
502 ESP_LOGI(TAG_I2C,
"Reset pin configured: GPIO%d", config_.rst_pin);
519 auto bus = std::make_unique<Esp32Bno08xI2cBus>(config);
521 ESP_LOGE(TAG_I2C,
"Failed to initialize I2C bus");
CRTP-based communication interface for the BNO08x IMU family.
BNO085Interface
Identifies the host interface type that a CommInterface provides.
Definition bno08x_comm_interface.hpp:25
@ I2C
I2C bus (PS1=0, PS0=0). Supports SH-2 and DFU.
ESP32 implementation of bno08x::CommInterface using ESP-IDF I2C master driver.
Definition esp32_bno08x_bus.hpp:63
void Delay(uint32_t ms) noexcept
Delay execution for specified time (required by CommInterface)
Definition esp32_bno08x_bus.hpp:268
bool Probe() noexcept
Probe the I2C device to verify it's responding.
Definition esp32_bno08x_bus.hpp:210
void HardwareReset(uint32_t lowMs=2, uint32_t bootDelayMs=200) noexcept
Perform hardware reset pulse on the BNO08x.
Definition esp32_bno08x_bus.hpp:437
bool Init() noexcept
Initialize the I2C bus, GPIO, and device handle.
Definition esp32_bno08x_bus.hpp:318
const I2CConfig & getConfig() const noexcept
Get the I2C configuration.
Definition esp32_bno08x_bus.hpp:416
~Esp32Bno08xI2cBus()
Destructor - cleans up I2C resources.
Definition esp32_bno08x_bus.hpp:95
BNO085Interface GetInterfaceType() noexcept
Identify this transport as I2C (required by CommInterface).
Definition esp32_bno08x_bus.hpp:104
Esp32Bno08xI2cBus()
Constructor with default configuration.
Definition esp32_bno08x_bus.hpp:83
void GpioSet(bno08x::CtrlPin pin, bno08x::GpioSignal signal) noexcept
Set a control pin to the specified signal state (required by CommInterface)
Definition esp32_bno08x_bus.hpp:290
uint32_t GetTimeUs() noexcept
Get current time in microseconds (required by CommInterface)
Definition esp32_bno08x_bus.hpp:276
bool isInitialized() const noexcept
Check if the bus is initialized.
Definition esp32_bno08x_bus.hpp:424
int Read(uint8_t *data, uint32_t length) noexcept
Read raw data from the BNO08x sensor (required by CommInterface)
Definition esp32_bno08x_bus.hpp:172
bool Open() noexcept
Open the I2C bus and initialize communication (required by CommInterface)
Definition esp32_bno08x_bus.hpp:117
void Deinit() noexcept
Deinitialize the I2C bus and release all resources.
Definition esp32_bno08x_bus.hpp:382
Esp32Bno08xI2cBus(const I2CConfig &config)
Constructor with custom I2C configuration.
Definition esp32_bno08x_bus.hpp:89
bool DataAvailable() noexcept
Check if new data is available (required by CommInterface)
Definition esp32_bno08x_bus.hpp:256
int Write(const uint8_t *data, uint32_t length) noexcept
Write raw data to the BNO08x sensor (required by CommInterface)
Definition esp32_bno08x_bus.hpp:138
void Close() noexcept
Close the I2C bus and release resources (required by CommInterface)
Definition esp32_bno08x_bus.hpp:124
CRTP base class for BNO08x communication interfaces.
Definition bno08x_comm_interface.hpp:92
std::unique_ptr< Esp32Bno08xI2cBus > CreateEsp32Bno08xI2cBus(const Esp32Bno08xI2cBus::I2CConfig &config=Esp32Bno08xI2cBus::I2CConfig{})
Factory function to create an ESP32 BNO08x I2C bus instance.
Definition esp32_bno08x_bus.hpp:517
CtrlPin
Identifies the hardware control pins of the BNO08x.
Definition bno08x_comm_interface.hpp:58
@ PS0
Protocol select bit 0 (active-high on the physical pin)
@ BOOTN
Bootloader entry (active-low on the physical pin)
@ RSTN
Hardware reset (active-low on the physical pin)
@ PS1
Protocol select bit 1 (active-high on the physical pin)
@ WAKE
Wake from suspend, SPI mode only (active-low on the physical pin)
GpioSignal
Abstract signal level for control pins.
Definition bno08x_comm_interface.hpp:74
@ ACTIVE
Pin function is asserted.
@ INACTIVE
Pin function is deasserted.
I2C bus and device configuration structure.
Definition esp32_bno08x_bus.hpp:68
gpio_num_t sda_pin
SDA pin (default GPIO4, same as pcal95555/pca9685)
Definition esp32_bno08x_bus.hpp:70
uint32_t frequency
I2C frequency in Hz (default 400kHz)
Definition esp32_bno08x_bus.hpp:72
uint8_t device_address
7-bit I2C device address (default 0x4B, SA0=HIGH; 0x4A if SA0=LOW)
Definition esp32_bno08x_bus.hpp:73
bool pullup_enable
Enable internal pullups.
Definition esp32_bno08x_bus.hpp:75
gpio_num_t scl_pin
SCL pin (default GPIO5, same as pcal95555/pca9685)
Definition esp32_bno08x_bus.hpp:71
gpio_num_t int_pin
Interrupt pin (default GPIO17, GPIO_NUM_NC if not used)
Definition esp32_bno08x_bus.hpp:76
i2c_port_t port
I2C port number.
Definition esp32_bno08x_bus.hpp:69
gpio_num_t rst_pin
Reset pin (default GPIO16, GPIO_NUM_NC if not used)
Definition esp32_bno08x_bus.hpp:77