Skip to content

Commit f845452

Browse files
authored
En bmi sensor (#4)
* sensors: Adding bmi support. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Add BMI270 sensor. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Add BMI270 sensor. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Fixed copilot review comments. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Adding bmi support. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Add BMI270 sensor. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Add BMI270 sensor. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Fixed copilot review comments. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> * sensors: Resolve conflicts and remove unintended import. Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]> --------- Signed-off-by: Rajasekhar Nikhita (DES DOS SWEE ESW EPE) <[email protected]>
1 parent 8a6a913 commit f845452

File tree

4 files changed

+721
-0
lines changed

4 files changed

+721
-0
lines changed

README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,20 @@ config = {
8787
"buffer_size": 512,
8888
}
8989
```
90+
2. For BMI270 sensor with interrupt, we configure it as:
91+
92+
```python
93+
int_pin = Pin("P1_5", mode=Pin.IN, pull = Pin.PULL_DOWN)
94+
int_pin.irq(handler=cback, trigger=Pin.IRQ_FALLING)
95+
96+
config = {
97+
"bus": i2c,
98+
"accel_range": b.ACCEL_RANGE_2G,
99+
"gyro_range": b.GYRO_RANGE_250,
100+
"interrupt_config": int_pin
101+
}
102+
```
103+
If interrupt functionality is not desired, pass None.
90104

91105
## FAQs
92106

@@ -104,6 +118,20 @@ Q: I am experiencing __duplicate timestamps__ when importing data to Studio.
104118

105119
A: Duplicate timestamps may occur when importing data to Studio if the sensor is changed without adjusting the delay value accordingly. To resolve this issue, ensure that the delay value in `data_acquisition.py` script is adjusted in accordance with your implementation to synchronize the server and client. This adjustment will prevent duplicate timestamps and ensure accurate data importation.
106120

121+
2. For BMI270 sensor with interrupt, we configure it as:
122+
123+
```python
124+
int_pin = Pin("P1_5", mode=Pin.IN, pull = Pin.PULL_DOWN)
125+
int_pin.irq(handler=cback, trigger=Pin.IRQ_FALLING)
126+
127+
config = {
128+
"bus": i2c,
129+
"accel_range": b.ACCEL_RANGE_2G,
130+
"gyro_range": b.GYRO_RANGE_250,
131+
"interrupt_config": int_pin
132+
}
133+
```
134+
If interrupt functionality is not desired, pass None.
107135

108136
## Contributing Guide
109137
Please do not hesitate to share your sensor integration with the community! Open a [Pull Request](https://github.com/Infineon/deepcraft-micropython-data-acquisition/pulls) with your `sensors/sensor_name.py` and an example configuration in the `README.md`. 🙌

sensors/bmi270.py

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# The `BMI270` class is a sensor interface for the BMI270 sensor that provides methods for
2+
# initialization, setting ranges, reading acceleration and gyroscope data, and configuring interrupts.
3+
from sensors.bmi270_config_file import bmi270_config_file
4+
from sensors.sensor_interface import SensorInterface
5+
from sensors import bmi270_i2c_helper as b
6+
import time
7+
from micropython import const
8+
from machine import I2C
9+
import array
10+
import micropython
11+
import sys
12+
13+
# Acceleration Range
14+
ACCEL_RANGE_2G = const(0b00)
15+
ACCEL_RANGE_4G = const(0b01)
16+
ACCEL_RANGE_8G = const(0b10)
17+
ACCEL_RANGE_16G = const(0b11)
18+
acceleration_range_values = (
19+
ACCEL_RANGE_2G,
20+
ACCEL_RANGE_4G,
21+
ACCEL_RANGE_8G,
22+
ACCEL_RANGE_16G,
23+
)
24+
25+
# Gyro range
26+
GYRO_RANGE_2000 = const(0b000)
27+
GYRO_RANGE_1000 = const(0b001)
28+
GYRO_RANGE_500 = const(0b010)
29+
GYRO_RANGE_250 = const(0b011)
30+
GYRO_RANGE_125 = const(0b100)
31+
gyro_range_values = (
32+
GYRO_RANGE_2000,
33+
GYRO_RANGE_1000,
34+
GYRO_RANGE_500,
35+
GYRO_RANGE_250,
36+
GYRO_RANGE_125,
37+
)
38+
39+
# BMI270 Reg Stack
40+
_BMI270_REG_CHIP_ID = const(0x00)
41+
_BMI270_REG_ERR_REG = const(0x02)
42+
_BMI270_REG_STATUS = const(0x03)
43+
_BMI270_REG_DATA_0 = const(0x04)
44+
_BMI270_REG_DATA_1 = const(0x05)
45+
_BMI270_REG_DATA_2 = const(0x06)
46+
_BMI270_REG_DATA_3 = const(0x07)
47+
_BMI270_REG_DATA_4 = const(0x08)
48+
_BMI270_REG_DATA_5 = const(0x09)
49+
_BMI270_REG_DATA_6 = const(0x0A)
50+
_BMI270_REG_DATA_7 = const(0x0B)
51+
_BMI270_REG_DATA_8_ACC_X_LSB = const(0x0C)
52+
_BMI270_REG_DATA_9_ACC_X_MSB = const(0x0D)
53+
_BMI270_REG_DATA_10_ACC_Y_LSB = const(0x0E)
54+
_BMI270_REG_DATA_11_ACC_Y_MSB = const(0x0F)
55+
_BMI270_REG_DATA_12_ACC_Z_LSB = const(0x10)
56+
_BMI270_REG_DATA_13_ACC_Z_MSB = const(0x11)
57+
_BMI270_REG_DATA_14_GYR_X_LSB = const(0x12)
58+
_BMI270_REG_DATA_15_GYR_X_MSB = const(0x13)
59+
_BMI270_REG_DATA_16_GYR_Y_LSB = const(0x14)
60+
_BMI270_REG_DATA_17_GYR_Y_MSB = const(0x15)
61+
_BMI270_REG_DATA_18_GYR_Z_LSB = const(0x16)
62+
_BMI270_REG_DATA_19_GYR_Z_MSB = const(0x17)
63+
_BMI270_REG_INTERNAL_STATUS = const(0x21)
64+
_BMI270_REG_ACC_CONF = const(0x40)
65+
_BMI270_REG_ACC_RANGE = const(0x41)
66+
_BMI270_REG_GYRO_CONF = const(0x42)
67+
_BMI270_REG_GYRO_RANGE = const(0x43)
68+
_BMI270_REG_INT1_IO_CTRL = const(0x53)
69+
_BMI270_REG_INT2_IO_CTRL = const(0x54)
70+
_BMI270_REG_INT_LATCH = const(0x55)
71+
_BMI270_REG_INT1_MAP_FEAT = const(0x56)
72+
_BMI270_REG_INT2_MAP_FEAT = const(0x57)
73+
_BMI270_REG_INT_MAP_DATA = const(0x58)
74+
_BMI270_REG_INIT_CTRL = const(0x59)
75+
_BMI270_REG_INIT_ADDR0 = const(0x5B)
76+
_BMI270_REG_INIT_ADDR1 = const(0x5C)
77+
_BMI270_REG_INIT_DATA = const(0x5E)
78+
_BMI270_REG_PWR_CONF = const(0x7C)
79+
_BMI270_REG_PWR_CTRL = const(0x7D)
80+
_BMI270_REG_CMD = const(0x7E)
81+
82+
ACCEL_SCALE = (2, 4, 8, 16)
83+
GYRO_SCALE = (2000, 1000, 500, 250, 125)
84+
85+
class BMI270(SensorInterface):
86+
def __init__(self, config=None):
87+
super().__init__(config)
88+
89+
if config is None or "bus" not in config:
90+
raise ValueError("An I2C bus should be initialized by user")
91+
92+
self._bus = config["bus"]
93+
self._address = config.get("address", 0x68)
94+
self._acceleration_range = config.get("acceleration_range", ACCEL_RANGE_2G)
95+
self._gyro_range = config.get("gyro_range", GYRO_RANGE_250)
96+
self._accel_scale = config.get("accel_scale", 4)
97+
self._gyro_scale = config.get("gyro_scale", 2000)
98+
self.reg = b.Register(self._address, self._bus) # Create an object of Register class to allow reg read and write
99+
self._int_config = config.get("interrupt_config", None)
100+
self.scratch = memoryview(array.array("h", [0, 0, 0])) #For direct accel and gyro API call
101+
102+
def get_device_id(self):
103+
"""Get device id of BMI270 sensor.
104+
"""
105+
return self.reg._read_reg(_BMI270_REG_CHIP_ID, 1)
106+
107+
def get_internal_status(self):
108+
"""Get the status of the sensor.
109+
"""
110+
return self.reg._read_reg(_BMI270_REG_INTERNAL_STATUS, 1)
111+
112+
def set_normal_power_mode(self):
113+
"""Sets the sensor to operate in normal power mode.
114+
"""
115+
self.reg._write_reg(_BMI270_REG_PWR_CTRL, 0x0E)
116+
time.sleep(0.1)
117+
self.reg._write_reg(_BMI270_REG_ACC_CONF, 0xA8)
118+
time.sleep(0.1)
119+
self.reg._write_reg(_BMI270_REG_GYRO_CONF, 0xA9)
120+
time.sleep(0.1)
121+
self.reg._write_reg(_BMI270_REG_PWR_CONF, 0x02)
122+
time.sleep(0.1)
123+
124+
def set_accel_range(self, accel_scale):
125+
"""Set the range for acceleration. Possible values are : 2, 4, 8, 16.
126+
"""
127+
self.accel_scale = 32768/accel_scale
128+
self.reg._write_reg(_BMI270_REG_ACC_RANGE, ACCEL_SCALE.index(accel_scale))
129+
130+
def set_gyro_range(self, gyro_scale):
131+
"""Set the range for gyro. Possible values are: 2000, 1000, 500, 250, 125.
132+
"""
133+
self.gyro_scale = 32768/gyro_scale
134+
self.reg._write_reg(_BMI270_REG_GYRO_RANGE, GYRO_SCALE.index(gyro_scale))
135+
136+
def load_config_file(self) -> None:
137+
"""Load the configuration file mandatory for BMI270 sensor to initialize.
138+
"""
139+
if self.get_internal_status() == 0x01:
140+
print(hex(self._address), " --> Initialization already done")
141+
else:
142+
from sensors.bmi270_config_file import bmi270_config_file
143+
144+
print(hex(self._address), " --> Initializing...")
145+
self.reg._write_reg(_BMI270_REG_PWR_CONF, 0x00)
146+
time.sleep_us(450)
147+
self.reg._write_reg(_BMI270_REG_INIT_CTRL, 0x00)
148+
for i in range(256):
149+
self.reg._write_reg(_BMI270_REG_INIT_ADDR0, 0x00)
150+
self.reg._write_reg(_BMI270_REG_INIT_ADDR1, i)
151+
time.sleep(0.03)
152+
self._bus.writeto_mem(
153+
self._address,
154+
0x5E,
155+
bytes(bmi270_config_file[i * 32 : (i + 1) * 32]),
156+
)
157+
time.sleep(0.000020)
158+
self.reg._write_reg(_BMI270_REG_INIT_CTRL, 0x01)
159+
time.sleep(0.02)
160+
print(
161+
hex(self._address),
162+
" --> Initialization status: "
163+
+ "{:08b}".format(self.get_internal_status())
164+
+ "\t(00000001 --> OK)",
165+
)
166+
167+
def init(self):
168+
""" Initializes the sensor by loading configuration file, setting power mode and acceleration and gyro ranges.
169+
"""
170+
self.load_config_file()
171+
self.set_normal_power_mode()
172+
self.set_accel_range(self._accel_scale)
173+
self.set_gyro_range(self._gyro_scale)
174+
175+
@micropython.native
176+
def acceleration(self):
177+
"""Public API to get directly acceleration values in m/s^2.
178+
"""
179+
f = self.accel_scale
180+
self.reg._read_reg_into(_BMI270_REG_DATA_8_ACC_X_LSB, self.scratch)
181+
return (self.scratch[0] / f, self.scratch[1] / f, self.scratch[2] / f)
182+
183+
@micropython.native
184+
def gyro(self):
185+
"""Public API to get directly gyro values in degrees/sec.
186+
"""
187+
f = self.gyro_scale
188+
self.reg._read_reg_into(_BMI270_REG_DATA_14_GYR_X_LSB, self.scratch)
189+
return (self.scratch[0] / f, self.scratch[1] / f, self.scratch[2] / f)
190+
191+
192+
def configure_data_ready_interrupt(self):
193+
"""Configure data ready interrupt for INT1 channel.
194+
"""
195+
if self._int_config is not None:
196+
self.reg._write_reg(_BMI270_REG_INT_MAP_DATA, 0x04)
197+
self.reg._write_reg(_BMI270_REG_INT1_IO_CTRL, 0x08)
198+
self.reg._write_reg(_BMI270_REG_INT_LATCH, 0x00)
199+
else:
200+
raise ValueError("Interrupt on pin must be configured")
201+
202+
def get_buffer(self):
203+
""" Creates buffers to hold acceleration and gyroscope values and returns.
204+
"""
205+
scratch_accel = memoryview(array.array("h", [0, 0, 0]))
206+
scratch_gyro = memoryview(array.array("h", [0, 0, 0]))
207+
return scratch_accel, scratch_gyro
208+
209+
@micropython.native
210+
def read_samples(self, scratch_accel, scratch_gyro):
211+
""" Fills scratch_accel and scratch_gyro buffers with acceleration and gyro values and returns normalized values.
212+
"""
213+
f1 = self.accel_scale
214+
f2 = self.gyro_scale
215+
self.reg._read_reg_into(_BMI270_REG_DATA_8_ACC_X_LSB, scratch_accel)
216+
self.reg._read_reg_into(_BMI270_REG_DATA_14_GYR_X_LSB, scratch_gyro)
217+
return (scratch_accel[0] / f1, scratch_accel[1] / f1, scratch_accel[2] / f1, scratch_gyro[0] / f2, scratch_gyro[1] / f2, scratch_gyro[2] / f2)
218+
219+
def get_format(self):
220+
""" Returns format and endianess to hold data in buffer.
221+
"""
222+
return '<', 'h'
223+
224+
def deinit(self):
225+
""" Deinitializes sensor module.
226+
"""
227+
self._bus.deinit()
228+
self._int_config.deinit()
229+

0 commit comments

Comments
 (0)