2023-05-08 3:23 AM - last edited on 2025-07-24 3:29 AM by Andrew Neil
I have verified in my code that writing and reading with I2C works as expected, and registers are configured seemingly correctly. I believe there must be a problem with how I write the configuration file to the BMI270, but I am at a loss as to what error exists in my code.
Here I present the initialization function and starting function for the BMI270:
--------------------------------------------
uint8_t BMI270_init(void)
{
uint8_t address;
uint8_t init_addr0 = 0x5B;
uint8_t init_addr1 = 0x5C;
uint16_t init_val = 0;
uint8_t value, val_lsb, val_msb;
uint8_t buffer[2] = {0};
uint8_t err = 0;
//disable PWR_CONF.adv_power_save (addr=0x7C,val=0x00)
address = 0x7C;
value = 0x00;
//Read address before
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
//Print result
UART_print_char("test pwc 1: ", 12);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
HAL_Delay(1);
//Read address after
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
//Print result
UART_print_char("test pwc 2: ", 12);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
//wait for 450 us
HAL_Delay(1);
//set INIT_CTRL to zero (addr=0x59,val=0x00)
address = 0x59;
value = 0x00;
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
//Read address after
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
//Print result
UART_print_char("test set 1: ", 12);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
//write bmi270_config_file (addr=0x5E,val=bmi270_config_file)
address = 0x5E;
//Continuously write parts of the configuration file <--- error??
for(uint8_t i = 0; i<32 ; i++)
{
err = I2C_write(&address, &bmi270_config_file[i*255], 255);
if (err != HAL_OK)
{return err;}
init_val=128;
val_msb = (uint8_t)(init_val >> 8);
val_lsb = (uint8_t)init_val;
//Update init_addr0 and init_addr1 (increment with bytes/2)
err = I2C_write(&init_addr0, &val_lsb, 1);
if (err != HAL_OK)
{return err;}
err = I2C_write(&init_addr1, &val_msb, 1);
if (err != HAL_OK)
{return err;}
address+= 256;
}
//set INIT_CTRL to one (addr=0x59,val=0x01)
address = 0x59;
value = 0x01;
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
//Read address after
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
//Print result
UART_print_char("test set 2: ", 12);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
return 0;
}
//end BMI270_initialize
uint8_t BMI270_start(void)
{
uint8_t address;
uint8_t value;
uint8_t err = 0;
uint8_t buffer[2] = {0};
//Write to PWR_CTRL (addr=0x7D,val=0x0E) (enable acc. & gyr.)
address = 0x7D;
value = 0x0E;
//Read address before
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
//Print result
UART_print_char("test pwr 1: ", 12);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
//Write value to register
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
//Read address after
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
//Print result
UART_print_char("test pwr 2: ", 12);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
//Write to ACC_CONF (addr=0x40,val=0xA8)
address = 0x40;
value = 0xA3;
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
UART_print_char("test acc: ", 10);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
//Write to GYR_CONF (addr=0x42,val=0xA9)
address = 0x42;
value = 0xA9;
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
err = I2C_read(&address, buffer, 1);
if (err != HAL_OK)
{return err;}
UART_print_char("test gyr: ", 10);
UART_print(buffer, 2);
UART_print_char("\r\n", 2);
//Write to PWR_CONF (addr=0x7C,val=0x02) (disable adv_power_save)
address = 0x7C;
value = 0x02;
err = I2C_write(&address, &value, 1);
if (err != HAL_OK)
{return err;}
return 0;
}
//end BMI270_start
--------------------------------------------
If the initialization was successful, the INTERNAL_STATUS register should contain the value 0x01, but in my case keeps containing the value 0x02 (init. error). The strangest thing is that at one point this code did work (internal_status = 0x01, gyroscope and accelerometer outputted values), however I can no longer replicate this response.
I included a zip folder containing two screenshots of both the error response and the working response in my serial monitor.
I have been breaking my head over the initialization proces for a while now, and I have a feeling there's just something I am overlooking. Help would be immensely appreciated. I would be eager to provide any further information if desired.
Kind regards,
Daan
Edited to apply source code formatting - please see How to insert source code for future reference.
2023-07-01 12:38 AM
Hi Dvan.11,
I am facing the same problem. Have you managed to solve the issue? If yes, could you please share the solution.
2023-08-01 3:25 PM
Please use the code pasting tool so these posts are readable.
On the BMI-160 you have to write a handful of registers and START the device. Would suggest finding other working examples, say from Arduino drivers, or a though reading of the salient manuals for the BOSCH device.
If you can read/write the registers on the device you should be able to port examples from other platforms.
2025-03-24 11:33 AM
Hi Dvan .11, I hope you are having a good day. I am interfacing a BMI270 with an stm32f103c8t6, better known as the Bluepill. I am facing the same error as you and I cannot seem to figure out where I am going wrong in the initialization. If your issue has been resolved, could you please help me figure out where I am going wrong, ill attach my code sample below.
Even im receiving the value "0x02" from register "0x21", it stands for Initialization error and I have no clue where i have made an error.
I have not included the config file in the below code as it would be a waste of space.
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2025 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
uint8_t BMI_config[] = {}; //The config file is too huge to be posted and quite unnecessary
HAL_StatusTypeDef status;
uint8_t buffer[12];
uint8_t check_id;
uint16_t final_address;
uint8_t chip_address;
int error = 0;
int init_complete = 0;
int init_condition = 0;
int address;
int i;
uint16_t config_file_size;
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
uint8_t internal_status = 0;
/* USER CODE BEGIN PFP */
#define BMI270_I2C_ADDR (0x68 << 1) // BMI270 I2C address (adjust if using different I2C variant)
#define BMI270_CONFIG_LOAD_ADDR 0x5E // Config upload address
extern I2C_HandleTypeDef hi2c1; // Ensure you are using the correct I2C handle
/**
* @brief Burst writes the BMI270 firmware/configuration file
* @PAram data: Pointer to the firmware binary
* @PAram length: Length of the binary
* @return HAL Status
*/
HAL_StatusTypeDef BMI270_BurstWrite(uint8_t *data, uint16_t length) {
uint16_t chunkSize = 32; // Recommended max burst size (BMI270 supports up to 32 bytes at a time)
uint16_t bytesWritten = 0;
while (bytesWritten < length) {
uint16_t bytesToWrite = (length - bytesWritten) > chunkSize ? chunkSize : (length - bytesWritten);
status = HAL_I2C_Mem_Write(&hi2c1, BMI270_I2C_ADDR, BMI270_CONFIG_LOAD_ADDR,
I2C_MEMADD_SIZE_8BIT, &data[bytesWritten], bytesToWrite, HAL_MAX_DELAY);
if (status != HAL_OK) {
return status; // Return error if write fails
}
bytesWritten += bytesToWrite;
HAL_Delay(2); // Small delay to avoid overwhelming the sensor
}
return HAL_OK;
}
uint16_t ret_address(){
for(int i = 0; i < 128; i++){
if(HAL_I2C_IsDeviceReady(&hi2c1, i << 1, 1, 100) == HAL_OK){
address = i;
break;
}
}
//status = HAL_I2C_IsDeviceReady(&hi2c1, address << 1, 1, 100);
HAL_I2C_Mem_Read(&hi2c1, address << 1, 0x00, 1, &check_id, 1, 100);
return address;
}
uint8_t ret_chip(){
uint8_t chip_address;
HAL_I2C_Mem_Read(&hi2c1, 0x68 << 1, 0x00, 1, &chip_address, 1, 100);
return chip_address;
}
int init_BMI(){
uint8_t data = 0x00;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x7c, 1, &data, 1, 100);
HAL_Delay(2000);
uint8_t reset_cmd = 0xb6;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x7E, 1, &reset_cmd, 1, 100);
HAL_Delay(2);
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x59, 1, &data, 1, 100);
config_file_size = sizeof(BMI_config);
for(int j = 0; j < config_file_size; j++){
status = HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x5e, 1, &BMI_config[j], 1, 100);
}
//status = BMI270_BurstWrite(BMI_config, config_file_size);
//status = HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x5e, 1, BMI_config, config_file_size, 100);
data = 0x01;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x59, 1, &data, 1, 100);
if(status == HAL_OK){
return 1;
}
else{
return 0;
}
}
int init_check() {
HAL_Delay(300); // Wait before checking initialization status
HAL_I2C_Mem_Read(&hi2c1, address << 1, 0x00, 1, &check_id, 1, 100);
// Read status register (0x21)
status = HAL_I2C_Mem_Read(&hi2c1, final_address << 1, 0x21, 1, &internal_status, 1, 100);
// Check if the read was successful
if (status != HAL_OK) {
return -1; // Indicate failure
}
// Return LSB of the status register
return (internal_status & 0x01);
}
void normal_config(){
uint8_t data;
data = 0x0e;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x7d, 1, &data, 1, 100);
data = 0xa8;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x40, 1, &data, 1, 100);
data = 0xa9;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x42, 1, &data, 1, 100);
data = 0x02;
HAL_I2C_Mem_Write(&hi2c1, final_address << 1, 0x76, 1, &data, 1, 100);
HAL_I2C_Mem_Read(&hi2c1, final_address << 1, 0x0c, 1, buffer, 12, 100);
}
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
/* USER CODE BEGIN 2 */
final_address = ret_address();
chip_address = ret_chip();
if(chip_address == 0x24){
error = 0;
}
else{
error = 1;
}
init_complete = init_BMI();
init_condition = init_check();
//normal_config();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//HAL_I2C_Mem_Read(&hi2c1, 104 << 1, 0x12, 1, buffer, 6, 100);
}
/* USER CODE END 3 */
}
2025-07-23 3:23 PM
Same for me, wrote config file, even verified it back but keep on init error. No idea how I could debug it? Is there any info I could read from the device to see the possible problems ? BR, Bastel
2025-07-23 5:30 PM
Write some code to dump out all the registers.
Show us the current content. The default is for all the sensors to be Off. Confirm content of register per defaults.
Start with PWR_CTRL (0x7D), Set Bit 3 to Enable the temperature sensor.Write the register and read in back, confirm that's working.
Read regsiters 0x22 and 0x23, combine the high/low portions, and decode into the temperature in degrees C. Do this in a loop. Confirm it reads room temperature. Put your finger on the device to warm it up. See the temperature rise.
Then enable the other sensors in PWR_CTRL, and check they start reading. Check the scale and configuration settings.
https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi270-ds000.pdf
2025-07-23 10:10 PM
Thanks Tesla for your Fast and Long reply. I dant get over Step two of the init phase. I wrote the configuration file and read it back without errors. However, the internal status stays at 0x02.
is there any way to debug this?
2025-07-24 3:23 AM
To be more concrete, this is my code [2] and [3] and the resulting output [1]. Config file upload seamed to work (no error messages and verification successfull) but the device is still in initialization mode (Register 0x21 @0x02). Any thought how to debug?
BR, Bastel
[1] debug output
# write 8192 bytes configuration file
# verify config file read
# 0: 0xc8 == 0xc8
# 1: 0x2e == 0x2e
# 2: 0x00 == 0x00
# 3: 0x2e == 0x2e
# 4: 0x80 == 0x80
# ...
# done with 0 errors
# chip id 0x00: 0x24
# init status 0x21: 0x02
# init error 0x5f: 0x11
# power conf 0x7c: 0x00
[2] init function
#define config_file bmi270_config_file
// disable power down
BMI270_write_reg(BMI270_PWR_CONF,0x00); // disable all power saving measures
HAL_Delay(1);
// write config file
BMI270_write_reg(BMI270_INIT_CTRL,0x00); // enter config upload
HAL_Delay(1);
print_debug("write %d bytes configuration file\n",n_bmi270_config_file);
BMI270_burst_write_data(BMI270_INIT_DATA,(uint8_t*) config_file, n_bmi270_config_file);
BMI270_write_reg(BMI270_INIT_CTRL,0x01);
HAL_Delay(20);
// read back config file
BMI270_write_reg(BMI270_INIT_CTRL,0x00);
HAL_Delay(1);
BMI270_burst_read_data(BMI270_INIT_DATA,(uint8_t*) bmi270_config_file_verify, n_bmi270_config_file);
BMI270_write_reg(BMI270_INIT_CTRL,0x01);
HAL_Delay(20);
// check read back
print_debug("verify config file read\n");
uint16_t errors = 0;
for(uint16_t i = 0; i<n_bmi270_config_file; i++) {
if (i<5) print_debug(" %4d: 0x%02x == 0x%02x \n",i, config_file[i],bmi270_config_file_verify[i]);
else if (i==5) print_debug(" ...\n");
if (bmi270_config_file[i] != bmi270_config_file_verify[i]) {
print_debug(" %4d: 0x%02x == 0x%02x \n",i, config_file[i],bmi270_config_file_verify[i]);
errors++;
}
}
print_debug("done with %d errors\n",errors);
uint8_t stat;
print_debug("chip id 0x%02x: 0x%02x\n",BMI270_CHIP_ID,BMI270_read_reg(BMI270_CHIP_ID));
print_debug("init status 0x%02x: 0x%02x\n",BMI270_INTERNAL_STATUS,BMI270_read_reg(BMI270_INTERNAL_STATUS));
print_debug("init error 0x%02x: 0x%02x\n",BMI270_INTERNAL_ERROR,BMI270_read_reg(BMI270_INTERNAL_ERROR));
print_debug("power conf 0x%02x: 0x%02x\n",BMI270_PWR_CONF, BMI270_read_reg(BMI270_PWR_CONF));
[3] I2C write / read functions
void BMI270_write_reg(uint8_t reg, uint8_t data) {
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Write(&hi2c1, smi270_addr << 1, reg,1, &data, 1, i2c_timeout);
if (status != HAL_OK) { print_error("BMI270 write reg 0x%02x to 0x%02x failed (status:0x%02x)\n",reg, data, status); }
//else { print_debug("BMI270 write reg 0x%02x to 0x%02x success (status:0x%02x)\n",reg, data,status); }
}
void BMI270_burst_write_data(uint8_t reg,uint8_t* data, uint16_t size) {
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Write(&hi2c1, smi270_addr << 1, reg,1, data, size, i2c_timeout);
if (status != HAL_OK) { print_error("BMI270 write reg 0x%02x with %d bytes failed (status:0x%02x)\n",reg, size, status); }
//else { print_debug("BMI270 write reg 0x%02x to 0x%02x success (status:0x%02x)\n",reg, data,status); }
}
uint8_t BMI270_read_reg(uint8_t reg) {
HAL_StatusTypeDef status;
uint8_t data = 0x00;
status = HAL_I2C_Mem_Read(&hi2c1, smi270_addr << 1, reg,1, &data, 1, i2c_timeout);
if (status != HAL_OK) { print_error("BMI270 read reg 0x%02x failed (0x%02x)\n",reg, status); }
//else { print_debug("BMI270 read ref 0x%02x = 0x%02x (status:0x%02x)\n",reg, data,status); }
return data;
}
void BMI270_burst_read_data(uint8_t reg,uint8_t* data,uint16_t size) {
HAL_StatusTypeDef status;
status = HAL_I2C_Mem_Read(&hi2c1, smi270_addr << 1, reg,1, data, size, i2c_timeout);
if (status != HAL_OK) { print_error("BMI270 read reg 0x%02x for %d bytes failed (0x%02x)\n",reg,size, status); }
//else { print_debug("BMI270 read ref 0x%02x = 0x%02x (status:0x%02x)\n",reg, data,status); }
}
2025-07-24 5:49 AM - edited 2025-07-24 5:50 AM
It isn't clear whether HAL_I2C_Mem_Write does what the BMI270 documentation calls "burst write".
HAL_I2C_Mem_Write and HAL_I2C_Mem_Read increment the target address for every byte. Is this OK? Should all data go to the same device address?
2025-07-24 1:03 PM
Thanks Pavel, good point, I thought also about this but since read back worked well I assumed it should work. I also just checked the HAL_I2C_Mem_Write implementation which sends only one time the I2C and Memory address and then just writes the bytes (Aas I would expect becouse in general the slave would do an increment address on read/write).
BR, Bastel
...
/* Send Slave Address and Memory Address */
if (I2C_RequestMemoryWrite(hi2c, DevAddress, MemAddress, MemAddSize, Timeout, tickstart) != HAL_OK)
{
return HAL_ERROR;
}
while (hi2c->XferSize > 0U)
....