02-18-2021 01:00 AM
Hi I am currently working on a project which requires interfacing BMG250 with ESP32. I am currently using ESP-IDF. I am stuck at the initialization of the bmg250. I browsed the API for BMI160 and I notice major differences. It seems like there are missing parts on the API provided at https://github.com/BoschSensortec/BMG250-API.
I have tried accessing the BMG250 using the i2c_tools example for ESP-IDF API Reference. I was able to detect the I2C address (0x68), read the default of values of some registers as well as write on some registers. Hence, I already ruled out the hardware side (connections from esp32 to bmg250 module) from the probable causes of may failed bmg250 initialization. See figure below.
Here's my code for your review.
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/i2c.h"
#include "sdkconfig.h"
#include "bmg250.h"
#include "bmg250_defs.h"
//static const char *TAG = "gyro";
#define _I2C_NUMBER(num) I2C_NUM_##num
#define I2C_NUMBER(num) _I2C_NUMBER(num)
#define I2C_MASTER_SCL_IO 19 /*!< gpio number for I2C master clock */
#define I2C_MASTER_SDA_IO 18 /*!< gpio number for I2C master data */
#define I2C_MASTER_NUM 0 /*!< I2C port number for master dev */
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master doesn't need buffer */
#define ESP_SLAVE_ADDR 0x68 /*!< ESP32 slave address, you can set any 7bit value */
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
#define ACK_CHECK_EN 0x1 /*!< I2C master will check ack from slave*/
#define ACK_CHECK_DIS 0x0 /*!< I2C master will not check ack from slave */
#define ACK_VAL 0x0 /*!< I2C ack value */
#define NACK_VAL 0x1 /*!< I2C nack value */
esp_err_t i2c_master_read_slave_reg(uint8_t i2c_addr, uint8_t i2c_reg, uint8_t* data_rd, size_t size)
{
if (size == 0) {
return ESP_OK;
}
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( i2c_addr << 1 ), ACK_CHECK_EN);
i2c_master_write_byte(cmd, i2c_reg, ACK_CHECK_EN);
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( i2c_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
if (size > 1) {
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
}
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
int8_t i2c_reg_read(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data, uint16_t length)
{
i2c_master_read_slave_reg(i2c_addr, reg_addr, reg_data, length);
/* Implement the I2C read routine according to the target machine. */
return -1;
}
esp_err_t i2c_master_write_slave_reg(uint8_t i2c_addr, uint8_t i2c_reg, uint8_t* data_wr, uint16_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, ( i2c_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
i2c_master_write_byte(cmd, i2c_reg, ACK_CHECK_EN);
i2c_master_write(cmd, data_wr, size, ACK_CHECK_EN);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
int8_t i2c_reg_write(uint8_t i2c_addr, uint8_t reg_addr, uint8_t *reg_data, uint16_t length)
{
i2c_master_write_slave_reg(i2c_addr, reg_addr, reg_data, length);
/* Implement the I2C write routine according to the target machine. */
return -1;
}
void i2c_master_init(void)
{
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_MASTER_SDA_IO,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_io_num = I2C_MASTER_SCL_IO,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_MASTER_FREQ_HZ
};
if(i2c_param_config(I2C_MASTER_NUM, &conf) != ESP_OK)
{
printf("\nError configuring I2C\n");
}
else
{
printf("\nSuccessful configuring I2C\n");
}
if(i2c_driver_install(I2C_MASTER_NUM, // i2c port 1
I2C_MODE_MASTER, // master mode
0, // does not need rx buffer
0, // does not need tx buffer
0) != ESP_OK)
{
printf("\nError installing I2C driver!\n");
}
else
{
printf("\nSuccessful installing I2C driver\n");
}
}
void print_rslt(const char api_name[], int8_t rslt)
{
if (rslt != BMG250_OK)
{
printf("%s\t", api_name);
if (rslt == BMG250_E_NULL_PTR)
{
printf("Error [%d] : Null pointer error\r\n", rslt);
}
else if (rslt == BMG250_E_COM_FAIL)
{
printf("Error [%d] : Bus communication failed\r\n", rslt);
}
else if (rslt == BMG250_E_INVALID_TEMPERATURE)
{
printf("Error [%d] : Invalid Temperature\r\n", rslt);
}
else if (rslt == BMG250_E_DEV_NOT_FOUND)
{
printf("Error [%d] : Device not found\r\n", rslt);
}
else
{
/* For more error codes refer "*_defs.h" */
printf("Error [%d] : Unknown error code\r\n", rslt);
}
}
}
void delay_ms(uint32_t period_ms)
{
//vTaskDelay(period_ms / portTICK_RATE_MS);
}
void i2c_gyro_task(void* arg)
{
struct bmg250_dev gyro;
struct bmg250_cfg gyro_cfg;
struct bmg250_sensor_data gyro_data;
//gyro.chip_id = BMG250_CHIP_ID;
gyro.delay_ms = delay_ms;
gyro.dev_id = BMG250_I2C_ADDR;
gyro.intf = BMG250_I2C_INTF;
gyro.read = i2c_reg_read;
gyro.write = i2c_reg_write;
gyro.power_mode = BMG250_GYRO_NORMAL_MODE;
int8_t rslt = BMG250_OK;
rslt = bmg250_init(&gyro);
print_rslt(" bmg250_init status", rslt);
rslt = bmg250_get_sensor_settings(&gyro_cfg, &gyro);
print_rslt(" bmg250_get_sensor_settings status ", rslt);
gyro_cfg.odr = BMG250_ODR_100HZ;
gyro_cfg.range = BMG250_RANGE_1000_DPS;
gyro_cfg.bw = BMG250_BW_NORMAL_MODE;
rslt = bmg250_set_sensor_settings(&gyro_cfg, &gyro);
print_rslt(" bmg250_set_sensor_settings status ", rslt);
while (1)
{
rslt = bmg250_get_sensor_data(BMG250_DATA_TIME_SEL, &gyro_data, &gyro);
printf("Gyro data X: %d \t Y: %d Z: %d \t Sensor-time : %zu\n",
gyro_data.x,
gyro_data.y,
gyro_data.z,
gyro_data.sensortime);
gyro.delay_ms(10);
}
}
void app_main(void)
{
i2c_master_init();
xTaskCreate(i2c_gyro_task, "i2c_gyro_task_0", 1024 * 2, (void* ) 0, 10, NULL);
========================================================================================================
Here's the sample output from the serial monitor of the esp32
I (0) cpu_start: App cpu up.
I (245) heap_init: Initializing. RAM available for dynamic allocation:
I (252) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (258) heap_init: At 3FFB28F8 len 0002D708 (181 KiB): DRAM
I (264) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (271) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (277) heap_init: At 4008B234 len 00014DCC (83 KiB): IRAM
I (283) cpu_start: Pro cpu start user code
I (302) spi_flash: detected chip: generic
I (302) spi_flash: flash io: dio
W (302) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (313) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
Successful configuring I2C
Successful installing I2C driver
bmg250_init status Error [-3] : Device not found
bmg250_get_sensor_settings status Error [-2] : Bus communication failed
bmg250_set_sensor_settings status Error [-2] : Bus communication failed
Gyro data X: 80 Y: 16379 Z: 0 Sensor-time : 0
Gyro data X: 80 Y: 16379 Z: 0 Sensor-time : 0
Gyro data X: 80 Y: 16379 Z: 0 Sensor-time : 0
Can you please provide insights or point out problems with my code. Thank you very much
02-18-2021 04:08 AM
Hi,
From the log, I can only find the bmg250_init error.
So please go to this function and print more info. If chip_id is not 0xD5, please using logic analyzer to get the SCK and SDI wave to find the reason.
int8_t bmg250_init(struct bmg250_dev *dev)
{
int8_t rslt;
uint8_t data;
uint8_t chip_id;
/* Null-pointer check */
rslt = null_ptr_check(dev);
if ((rslt == BMG250_OK) && (dev->intf == BMG250_SPI_INTF))
{
/* Dummy read of 0x7F register to enable SPI Interface
* if SPI is used
*/
rslt = bmg250_get_regs(BMG250_SPI_COMM_TEST_ADDR, &data, 1, dev);
}
if (rslt == BMG250_OK)
{
/* Read chip_id */
rslt = bmg250_get_regs(BMG250_CHIP_ID_ADDR, &chip_id, 1, dev);
// print rslt, and chip_id value, here
if ((rslt == BMG250_OK) && (chip_id == BMG250_CHIP_ID))
{
/* Updating chip_id in device structure */
dev->chip_id = chip_id;
}
else
{
rslt = BMG250_E_DEV_NOT_FOUND;
}
}
return rslt;
}
Best regards.