kopia lustrzana https://github.com/micropython/micropython-lib
bmm150: Add new magnetometer driver.
For the BOSCH BMM150 magnetometer.pull/593/head
rodzic
92854c1754
commit
e3371bef6c
|
@ -0,0 +1,187 @@
|
|||
"""
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Arduino SA
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Basic example usage:
|
||||
|
||||
import time
|
||||
from bmm150 import BMM150
|
||||
from machine import Pin, SPI, I2C
|
||||
|
||||
# Init in I2C mode.
|
||||
imu = BMM150(I2C(1, scl=Pin(15), sda=Pin(14)))
|
||||
|
||||
# Or init in SPI mode.
|
||||
# TODO: Not supported yet.
|
||||
# imu = BMM150(SPI(5), cs=Pin(10))
|
||||
|
||||
while (True):
|
||||
print('magnetometer: x:{:>8.3f} y:{:>8.3f} z:{:>8.3f}'.format(*imu.magnet()))
|
||||
time.sleep_ms(100)
|
||||
"""
|
||||
|
||||
import array
|
||||
import time
|
||||
from micropython import const
|
||||
|
||||
_DEFAULT_ADDR = const(0x10)
|
||||
_CHIP_ID = const(0x40)
|
||||
_DATA = const(0x42)
|
||||
_POWER = const(0x4B)
|
||||
_OPMODE = const(0x4C)
|
||||
_INT_STATUS = const(0x4A)
|
||||
_TRIM_X1 = const(0x5D)
|
||||
_TRIM_Y1 = const(0x5E)
|
||||
_TRIM_Z4_LSB = const(0x62)
|
||||
_TRIM_Z2_LSB = const(0x68)
|
||||
_XYAXES_FLIP = const(-4096)
|
||||
_ZHAXES_FLIP = const(-16384)
|
||||
_ODR = const((10, 2, 6, 8, 15, 20, 25, 30))
|
||||
|
||||
|
||||
class BMM150:
|
||||
def __init__(
|
||||
self,
|
||||
bus,
|
||||
cs=None,
|
||||
address=_DEFAULT_ADDR,
|
||||
magnet_odr=30,
|
||||
):
|
||||
"""Initalizes the Magnetometer.
|
||||
bus: IMU bus
|
||||
address: I2C address (in I2C mode).
|
||||
cs: SPI CS pin (in SPI mode).
|
||||
magnet_odr: (2, 6, 8, 10, 15, 20, 25, 30)
|
||||
"""
|
||||
self.bus = bus
|
||||
self.cs = cs
|
||||
self.address = address
|
||||
self._use_i2c = hasattr(self.bus, "readfrom_mem")
|
||||
|
||||
# Sanity checks
|
||||
if not self._use_i2c:
|
||||
raise ValueError("SPI mode is not supported")
|
||||
if not magnet_odr in _ODR:
|
||||
raise ValueError("Invalid sampling rate: %d" % magnet_odr)
|
||||
|
||||
# Perform soft reset, and power on.
|
||||
self._write_reg(_POWER, 0x83)
|
||||
time.sleep_ms(10)
|
||||
|
||||
if self._read_reg(_CHIP_ID) != 0x32:
|
||||
raise OSError("No BMM150 device was found at address 0x%x" % (self.address))
|
||||
|
||||
# Configure the device.
|
||||
# ODR | OP: Normal mode
|
||||
self._write_reg(_OPMODE, _ODR.index(magnet_odr) << 3)
|
||||
|
||||
# Read trim registers.
|
||||
trim_x1y1 = self._read_reg(_TRIM_X1, 2)
|
||||
trim_xyz_data = self._read_reg(_TRIM_Z4_LSB, 4)
|
||||
trim_xy1xy2 = self._read_reg(_TRIM_Z2_LSB, 10)
|
||||
|
||||
self.trim_x1 = trim_x1y1[0]
|
||||
self.trim_y1 = trim_x1y1[1]
|
||||
self.trim_x2 = trim_xyz_data[2]
|
||||
self.trim_y2 = trim_xyz_data[3]
|
||||
self.trim_z1 = (trim_xy1xy2[3] << 8) | trim_xy1xy2[2]
|
||||
self.trim_z2 = (trim_xy1xy2[1] << 8) | trim_xy1xy2[0]
|
||||
self.trim_z3 = (trim_xy1xy2[7] << 8) | trim_xy1xy2[6]
|
||||
self.trim_z4 = (trim_xyz_data[1] << 8) | trim_xyz_data[0]
|
||||
self.trim_xy1 = trim_xy1xy2[9]
|
||||
self.trim_xy2 = trim_xy1xy2[8]
|
||||
self.trim_xyz1 = ((trim_xy1xy2[5] & 0x7F) << 8) | trim_xy1xy2[4]
|
||||
|
||||
# Allocate scratch buffer.
|
||||
self.scratch = memoryview(array.array("h", [0, 0, 0, 0]))
|
||||
|
||||
def _read_reg(self, reg, size=1):
|
||||
buf = self.bus.readfrom_mem(self.address, reg, size)
|
||||
if size == 1:
|
||||
return int(buf[0])
|
||||
return buf
|
||||
|
||||
def _read_reg_into(self, reg, buf):
|
||||
self.bus.readfrom_mem_into(self.address, reg, buf)
|
||||
|
||||
def _write_reg(self, reg, val):
|
||||
self.bus.writeto_mem(self.address, reg, bytes([val]))
|
||||
|
||||
def _compensate_x(self, raw, hall):
|
||||
"""Compensation equation ported from C driver"""
|
||||
x = 0
|
||||
if raw != _XYAXES_FLIP:
|
||||
x0 = self.trim_xyz1 * 16384 / hall
|
||||
x = x0 - 16384
|
||||
x1 = (self.trim_xy2) * (x**2 / 268435456)
|
||||
x2 = x1 + x * (self.trim_xy1) / 16384
|
||||
x3 = (self.trim_x2) + 160
|
||||
x4 = raw * ((x2 + 256) * x3)
|
||||
x = ((x4 / 8192) + (self.trim_x1 * 8)) / 16
|
||||
return x
|
||||
|
||||
def _compensate_y(self, raw, hall):
|
||||
"""Compensation equation ported from C driver"""
|
||||
y = 0
|
||||
if raw != _XYAXES_FLIP:
|
||||
y0 = self.trim_xyz1 * 16384 / hall
|
||||
y = y0 - 16384
|
||||
y1 = self.trim_xy2 * (y**2 / 268435456)
|
||||
y2 = y1 + y * self.trim_xy1 / 16384
|
||||
y3 = self.trim_y2 + 160
|
||||
y4 = raw * ((y2 + 256) * y3)
|
||||
y = ((y4 / 8192) + (self.trim_y1 * 8)) / 16
|
||||
return y
|
||||
|
||||
def _compensate_z(self, raw, hall):
|
||||
"""Compensation equation ported from C driver"""
|
||||
z = 0
|
||||
if raw != _ZHAXES_FLIP:
|
||||
z0 = raw - self.trim_z4
|
||||
z1 = hall - self.trim_xyz1
|
||||
z2 = self.trim_z3 * z1
|
||||
z3 = (self.trim_z1 * hall) / 32768
|
||||
z4 = self.trim_z2 + z3
|
||||
z5 = (z0 * 131072) - z2
|
||||
z = (z5 / (z4 * 4)) / 16
|
||||
return z
|
||||
|
||||
def reset(self):
|
||||
self._write_reg(_CMD, 0xB6)
|
||||
|
||||
def magnet_raw(self):
|
||||
for i in range(0, 10):
|
||||
self._read_reg_into(_DATA, self.scratch)
|
||||
if self.scratch[3] & 0x1:
|
||||
return (
|
||||
self.scratch[0] >> 3,
|
||||
self.scratch[1] >> 3,
|
||||
self.scratch[2] >> 1,
|
||||
self.scratch[3] >> 2,
|
||||
)
|
||||
time.sleep_ms(30)
|
||||
raise OSError("Data not ready")
|
||||
|
||||
def magnet(self):
|
||||
"""Returns magnetometer vector."""
|
||||
x, y, z, h = self.magnet_raw()
|
||||
return (self._compensate_x(x, h), self._compensate_y(y, h), self._compensate_z(z, h))
|
|
@ -0,0 +1,2 @@
|
|||
metadata(description="BOSCH BMM150 magnetometer driver.", version="1.0.0")
|
||||
module("bmm150.py", opt=3)
|
Ładowanie…
Reference in New Issue