8000 bmm150: Add new magnetometer driver. · micropython/micropython-lib@e3371be · GitHub
[go: up one dir, main page]

Skip to content

Commit e3371be

Browse files
iabdalkaderdpgeorge
authored andcommitted
bmm150: Add new magnetometer driver.
For the BOSCH BMM150 magnetometer.
1 parent 92854c1 commit e3371be

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed
Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
"""
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2023 Arduino SA
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.
23+
24+
Basic example usage:
25+
26+
import time
27+
from bmm150 import BMM150
28+
from machine import Pin, SPI, I2C
29+
30+
# Init in I2C mode.
31+
imu = BMM150(I2C(1, scl=Pin(15), sda=Pin(14)))
32+
33+
# Or init in SPI mode.
34+
# TODO: Not supported yet.
35+
# imu = BMM150(SPI(5), cs=Pin(10))
36+
37+
while (True):
38+
print('magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet()))
39+
time.sleep_ms(100)
40+
"""
41+
42+
import array
43+
import time
44+
from micropython import const
45+
46+
_DEFAULT_ADDR = const(0x10)
47+
_CHIP_ID = const(0x40)
48+
_DATA = const(0x42)
49+
_POWER = const(0x4B)
50+
_OPMODE = const(0x4C)
51+
_INT_STATUS = const(0x4A)
52+
_TRIM_X1 = const(0x5D)
53+
_TRIM_Y1 = const(0x5E)
54+
_TRIM_Z4_LSB = const(0x62)
55+
_TRIM_Z2_LSB = const(0x68)
56+
_XYAXES_FLIP = const(-4096)
57+
_ZHAXES_FLIP = const(-16384)
58+
_ODR = const((10, 2, 6, 8, 15, 20, 25, 30))
59+
60+
61+
class BMM150:
62+
def __init__(
63+
self,
64+
bus,
65+
cs=None,
66+
address=_DEFAULT_ADDR,
67+
magnet_odr=30,
68+
):
69+
"""Initalizes the Magnetometer.
70+
bus: IMU bus
71+
address: I2C address (in I2C mode).
72+
cs: SPI CS pin (in SPI mode).
73+
magnet_odr: (2, 6, 8, 10, 15, 20, 25, 30)
74+
"""
75+
self.bus = bus
76+
self.cs = cs
77+
self.address = address
78+
self._use_i2c = hasattr(self.bus, "readfrom_mem")
79+
80+
# Sanity checks
81+
if not self._use_i2c:
82+
raise ValueError("SPI mode is not supported")
83+
if not magnet_odr in _ODR:
84+
raise ValueError("Invalid sampling rate: %d" % magnet_odr)
85+
86+
# Perform soft reset, and power on.
87+
self._write_reg(_POWER, 0x83)
88+
time.sleep_ms(10)
89+
90+
if self._read_reg(_CHIP_ID) != 0x32:
91+
raise OSError("No BMM150 device was found at address 0x%x" % (self.address))
92+
93+
# Configure the device.
94+
# ODR | OP: Normal mode
95+
self._write_reg(_OPMODE, _ODR.index(magnet_odr) << 3)
96+
97+
# Read trim registers.
98+
trim_x1y1 = self._read_reg(_TRIM_X1, 2)
99+
trim_xyz_data = self._read_reg(_TRIM_Z4_LSB, 4)
100+
trim_xy1xy2 = self._read_reg(_TRIM_Z2_LSB, 10)
101+
102+
self.trim_x1 = trim_x1y1[0]
103+
self.trim_y1 = trim_x1y1[1]
104+
self.trim_x2 = trim_xyz_data[2]
105+
self.trim_y2 = trim_xyz_data[3]
106+
self.trim_z1 = (trim_xy1xy2[3] << 8) | trim_xy1xy2[2]
107+
self.trim_z2 = (trim_xy1xy2[1] << 8) | trim_xy1xy2[0]
108+
self.trim_z3 = (trim_xy1xy2[7] << 8) | trim_xy1xy2[6]
109+
self.trim_z4 = (trim_xyz_data[1] << 8) | trim_xyz_data[0]
110+
self.trim_xy1 = trim_xy1xy2[9]
111+
self.trim_xy2 = trim_xy1xy2[8]
112+
self.trim_xyz1 = ((trim_xy1xy2[5] & 0x7F) << 8) | trim_xy1xy2[4]
113+
114+
# Allocate scratch buffer.
115+
self.scratch = memoryview(array.array("h", [0, 0, 0, 0]))
116+
117+
def _read_reg(self, reg, size=1):
118+
buf = self.bus.readfrom_mem(self.address, reg, size)
119+
if size == 1:
120+
return int(buf[0])
121+
return buf
122+
123+
def _read_reg_into(self, reg, buf):
124+
self.bus.readfrom_mem_into(self.address, reg, buf)
125+
126+
def _write_reg(self, reg, val):
127+
self.bus.writeto_mem(self.address, reg, bytes([val]))
128+
129+
def _compensate_x(self, raw, hall):
130+
"""Compensation equation ported from C driver"""
131+
x = 0
132+
if raw != _XYAXES_FLIP:
133+
x0 = self.trim_xyz1 * 16384 / hall
134+
x = x0 - 16384
135+
x1 = (self.trim_xy2) * (x**2 / 268435456)
136+
x2 = x1 + x * (self.trim_xy1) / 16384
137+
x3 = (self.trim_x2) + 160
138+
x4 = raw * ((x2 + 256) * x3)
139+
x = ((x4 / 8192) + (self.trim_x1 * 8)) / 16
140+
return x
141+
142+
def _compensate_y(self, raw, hall):
143+
"""Compensation equation ported from C driver"""
144+
y = 0
145+
if raw != _XYAXES_FLIP:
146+
y0 = self.trim_xyz1 * 16384 / hall
147+
y = y0 - 16384
148+
y1 = self.trim_xy2 * (y**2 / 268435456)
149+
y2 = y1 + y * self.trim_xy1 / 16384
150+
y3 = self.trim_y2 + 160
151+
y4 = raw * ((y2 + 256) * y3)
152+
y = ((y4 / 8192) + (self.trim_y1 * 8)) / 16
153+
return y
154+
155+
def _compensate_z(self, raw, hall):
156+
"""Compensation equation ported from C driver"""
157+
z = 0
158+
if raw != _ZHAXES_FLIP:
159+
z0 = raw - self.trim_z4
160+
z1 = hall - self.trim_xyz1
161+
z2 = self.trim_z3 * z1
162+
z3 = (self.trim_z1 * hall) / 32768
163+
z4 = self.trim_z2 + z3
164+
z5 = (z0 * 131072) - z2
165+
z = (z5 / (z4 * 4)) / 16
166+
return z
167+
168+
def reset(self):
169+
self._write_reg(_CMD, 0xB6)
170+
171+
def magnet_raw(self):
172+
for i in range(0, 10):
173+
self._read_reg_into(_DATA, self.scratch)
174+
if self.scratch[3] & 0x1:
175+
return (
176+
self.scratch[0] >> 3,
177+
self.scratch[1] >> 3,
178+
self.scratch[2] >> 1,
179+
self.scratch[3] >> 2,
180+
)
181+
time.sleep_ms(30)
182+
raise OSError("Data not ready")
183+
184+
def magnet(self):
185+
"""Returns magnetometer vector."""
186+
x, y, z, h = self.magnet_raw()
187+
return (self._compensate_x(x, h), self._compensate_y(y, h), self._compensate_z(z, h))
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
metadata(description="BOSCH BMM150 magnetometer driver.", version="1.0.0")
2+
module("bmm150.py", opt=3)

0 commit comments

Comments
 (0)
0