Skip to content

bmi270: add driver for BMI270 6-axis IMU - #874

Open
t-morisawa wants to merge 3 commits into
tinygo-org:devfrom
t-morisawa:feature/bmi270
Open

bmi270: add driver for BMI270 6-axis IMU#874
t-morisawa wants to merge 3 commits into
tinygo-org:devfrom
t-morisawa:feature/bmi270

Conversation

@t-morisawa

@t-morisawa t-morisawa commented Jun 11, 2026

Copy link
Copy Markdown

Summary

Add I2C driver for the Bosch BMI270 6-axis inertial measurement unit.

Features

  • Configurable accelerometer range (±2g/4g/8g/16g)
  • Configurable gyroscope range (±125/250/500/1000/2000 dps)
  • ReadAcceleration returns values in µg
  • ReadRotation returns values in µdps
  • Uses go:embed for firmware config data (same pattern as bma42x)
  • Follows existing driver conventions (reg_ prefix, uint8 address, etc.)

Files

  • bmi270/bmi270.go - driver implementation
  • bmi270/registers.go - register definitions
  • bmi270/bmi270-config.bin - BMI270 firmware config data
  • examples/bmi270/main.go - example usage

Testing

test M5Stack Core 2 v1.3

acc(mg): 8 -506 799  gyr(dps): -277 39 -25
acc(mg): -119 -864 353  gyr(dps): -231 68 151
acc(mg): -271 -925 304  gyr(dps): -45 42 105
acc(mg): -424 -830 498  gyr(dps): 160 18 113
acc(mg): -363 -723 883  gyr(dps): 198 -75 -28

the test program is below:

https://github.com/t-morisawa/m5stack-tinygo/blob/668ff91/tinygo/bmi270-monitor/main.go

Closes #872

Add I2C driver for the Bosch BMI270 inertial measurement unit,
supporting configurable accelerometer (±2g/4g/8g/16g) and gyroscope
(±125/250/500/1000/2000 dps) ranges.

Includes:
- Register definitions (registers.go)
- Driver implementation with go:embed for config firmware (bmi270.go)
- BMI270 config binary data (bmi270-config.bin)
- Example usage (examples/bmi270/main.go)
@t-morisawa
t-morisawa marked this pull request as ready for review June 11, 2026 12:58

@deadprogram deadprogram left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this driver. The structure follows the repo conventions and the register map agrees with the datasheet (CHIP_ID 0x24, INIT_ADDR nibble/byte split). I checked all the scale factors and they are correct:

  • accel: 2G 61, 4G 122, 8G 244, 16G 488 microG/LSB
  • gyro: 2000 60976, 1000 30488, 500 15244, 250 7622, 125 3811 micro-dps/LSB

The worst case product 32767 * 60976 = 1.998e9 stays inside int32, so there is no overflow.

I put some comments in the code. The most important one is the 8 KB RAM copy of the config blob.

Some smaller items:

  • The ODR and the bandwidth are constant (ACC_CONF and GYR_CONF = 0xA8, 100 Hz). This is satisfactory for a first version, but a Config field could be useful later.
  • The example mixes println and fmt.Printf. fmt adds much flash usage on small targets.
  • The PR text says that you did the test on an M5Stack Core 1.3, but the smoketest builds for m5stack-core2. Please make sure that the pins in the example are correct for the target that the CI builds.

Comment thread bmi270/bmi270.go
"tinygo.org/x/drivers"
)

//go:embed bmi270-config.bin

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment that gives the source of this binary and its license status. The bma42x driver does this for its config blobs (see bma42x/bma42x.go lines 29-37). This blob is a Bosch binary and it has no attribution now.

Comment thread bmi270/bmi270.go Outdated
}
time.Sleep(1 * time.Millisecond)

configBytes := []byte(bmi270ConfigData)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes an 8 KB copy of the firmware in RAM. The bma42x driver does special work to prevent this (unsafeStringToSlice, bma42x/bma42x.go lines 158-162).

Here the correction is easier, because you copy the chunk into wbuf. The copy built-in accepts a string source:

for i := 0; i < len(bmi270ConfigData); i += chunkSize {
    ...
    n := copy(d.wbuf[1:], bmi270ConfigData[i:end])

Then you can remove the configBytes variable.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to copy directly from the string using copy(), eliminating the 8 KB RAM copy. Thanks!
f8a25fb#diff-17f100c3d4763c5385c199aedcb9357aa29b378c1d6a6dcb10ccb40742c92d25R105-R122

Comment thread bmi270/bmi270.go Outdated
if err != nil {
return err
}
if status == 0x01 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comparison is too strict. It is not equal to 0x01 if axes_remap_error (bit 5) or odr_50hz_error (bit 6) is set, although the message field (bits [2:0]) shows init_ok. See datasheet section 5.3.2.

Use status&0x07 == 0x01.

Comment thread bmi270/bmi270.go Outdated
}

func (d *Device) Configure(config Config) error {
if config.AccelRange != 0 {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accel2G and Gyro2000DPS are both 0x00, thus config.AccelRange != 0 and config.GyroRange != 0 are always false for the default values and the else branches do the same thing. You can assign the two fields directly.

Comment thread bmi270/bmi270.go Outdated
return err
}

var rangeVal byte

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AccelRange constants are equal to the register values, thus this switch is an identity map. You can write byte(d.accelRange). The same is applicable to the gyro switch below.

Comment thread bmi270/registers.go
reg_GYR_CONF = 0x42
reg_GYR_RANGE = 0x43
reg_INIT_CTRL = 0x59
reg_INIT_ADDR_0 = 0x5B

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reg_INIT_ADDR_1 is not used, because the 2-byte write to INIT_ADDR_0 increments the address automatically. This is satisfactory, but a short comment can help the next reader.

- Add Bosch Sensortec source/license attribution for the embedded
  bmi270-config.bin firmware blob.
- Avoid an 8 KB RAM copy of the config blob by copying chunks
  directly from the embedded string into wbuf.
- Check only the message field of INTERNAL_STATUS (status&0x07 == 0x01)
  per datasheet section 5.3.2, instead of the full register value.
- Drop redundant AccelRange/GyroRange zero checks in Configure,
  since Accel2G and Gyro2000DPS are both 0x00.
- Replace the identity-map switch blocks with direct byte() casts.
- Add a comment on reg_INIT_ADDR_1 noting that writing 2 bytes to
  reg_INIT_ADDR_0 automatically updates it.
- Example: use println with integer mg/mdps values instead of
  fmt.Printf to reduce flash usage on small targets.
@t-morisawa

t-morisawa commented Aug 29, 2026

Copy link
Copy Markdown
Author

Thank you for the feedback! I have updated the PR to address all the review comments and verified that it works as expected on the M5Stack Core2 v1.3.

f8a25fb

acc(mg): -1123 226 286  gyr(dps): 75 -26 71
acc(mg): -908 334 125  gyr(dps): -43 82 -97
acc(mg): -1003 -89 196  gyr(dps): 19 23 -158
acc(mg): -62 -1898 533  gyr(dps): 179 116 -242
acc(mg): -515 -794 358  gyr(dps): -6 117 50
acc(mg): -739 -871 261  gyr(dps): 20 -50 -88
acc(mg): -484 -910 252  gyr(dps): 0 12 -9
acc(mg): -598 -935 133  gyr(dps): -3 -214 -195
acc(mg): -123 -959 434  gyr(dps): -65 -79 -85
acc(mg): -80 -947 -310  gyr(dps): -30 62 11
acc(mg): -299 -1044 150  gyr(dps): 1 246 227
acc(mg): -195 -617 -323  gyr(dps): 20 2 -160

@t-morisawa

Copy link
Copy Markdown
Author

The PR text says that you did the test on an M5Stack Core 1.3, but the smoketest builds for m5stack-core2.

Sorry, the PR text was wrong. I use M5Stack Core2 v1.3, and fixed the text.

@t-morisawa
t-morisawa requested a review from deadprogram August 29, 2026 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Adding BMI270 Support

2 participants