Skip to content

Commit 66a5dfa

Browse files
Charly-sketchnedseb
authored andcommitted
lis2mdl: fix device + first number
Still doesnt point to north but can see rotation
1 parent c14be37 commit 66a5dfa

2 files changed

Lines changed: 87 additions & 32 deletions

File tree

lib/lis2mdl/exemple/magnet.py

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,62 @@
11
from time import sleep_ms
22
from machine import I2C
33
from lis2mdl.device import LIS2MDL
4+
import math
45

5-
# Initialize the LIS2MDL magnetometer
66
i2c = I2C(1)
7-
magnetometer = LIS2MDL(i2c)
7+
mag = LIS2MDL(i2c)
88

9-
print("Starting magnetometer readings...")
9+
print("Quick calibration: rotate the board FLAT over 360°...")
10+
xmin = ymin = 1e9
11+
xmax = ymax = -1e9
1012

13+
# capture ~3 seconds of data for min/max
14+
for _ in range(150):
15+
x, y, z = mag.read_magnet()
16+
xmin = min(xmin, x); xmax = max(xmax, x)
17+
ymin = min(ymin, y); ymax = max(ymax, y)
18+
sleep_ms(20)
19+
20+
# offsets (hard-iron) and scales (simple 2D soft-iron)
21+
x_off = (xmax + xmin) / 2.0
22+
y_off = (ymax + ymin) / 2.0
23+
x_scale = (xmax - xmin) / 2.0
24+
y_scale = (ymax - ymin) / 2.0
25+
# normalize the scale to have a circle (not essential but better)
26+
scale = (x_scale + y_scale) / 2.0
27+
28+
print("Offsets:", x_off, y_off, " Scales:", x_scale, y_scale)
29+
30+
print("\nContinuous reading (compass):")
1131
while True:
12-
# Read magnetic field data
13-
magnet = magnetometer.read_magnet()
14-
print(f"Magnetic field (X, Y, Z): {magnet}")
32+
x, y, z = mag.read_magnet()
33+
34+
# recentering + normalization
35+
x_c = (x - x_off) / scale
36+
y_c = (y - y_off) / scale
37+
38+
# heading (adjust the sign according to your reference if needed)
39+
angle = math.degrees(math.atan2(y_c, x_c))
40+
if angle < 0:
41+
angle += 360
42+
43+
direction = ""
44+
if angle >= 337.5 or angle < 22.5:
45+
direction = "N"
46+
elif angle >= 22.5 and angle < 67.5:
47+
direction = "NE"
48+
elif angle >= 67.5 and angle < 112.5:
49+
direction = "E"
50+
elif angle >= 112.5 and angle < 157.5:
51+
direction = "SE"
52+
elif angle >= 157.5 and angle < 202.5:
53+
direction = "S"
54+
elif angle >= 202.5 and angle < 247.5:
55+
direction = "SW"
56+
elif angle >= 247.5 and angle < 292.5:
57+
direction = "W"
58+
elif angle >= 292.5 and angle < 337.5:
59+
direction = "NW"
1560

16-
# Wait for 1 second
17-
sleep_ms(1000)
61+
print("{} | {:.2f},{:.2f},{:.2f} | angle={:.2f}°".format(direction, x, y, z, angle))
62+
sleep_ms(100)

lib/lis2mdl/lis2mdl/device.py

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
1+
# device.py
12
from machine import I2C
23
from lis2mdl.const import *
34

45
class LIS2MDL(object):
5-
def __init__(self, i2c, address=LIS2MDL_I2C_ADDR):
6+
def __init__(self, i2c, address=LIS2MDL_I2C_ADDR, odr_hz=10, temp_comp=True, low_power=False, drdy_pin=False):
67
self.i2c = i2c
78
self.address = address
8-
99
self.writebuffer = bytearray(1)
1010
self.readbuffer = bytearray(1)
1111

12-
# Initialize the device
13-
self.reset()
14-
self.configure()
15-
16-
def reset(self):
17-
# Reset the device using CFG_REG_A
18-
self.setReg(0x10, LIS2MDL_CFG_REG_A)
19-
20-
def configure(self):
21-
# Configure the device (example: enable continuous mode)
12+
# Soft reset property
13+
self.setReg(0x20, LIS2MDL_CFG_REG_A) # SOFT_RST=1 (not 0x10)
14+
# small delay (if needed on the MicroPython side)
15+
try:
16+
import time; time.sleep_ms(10)
17+
except:
18+
pass
19+
20+
# CFG_REG_A: COMP_TEMP, LP, ODR, MD=00 (continuous)
21+
odr_bits = {10:0b00, 20:0b01, 50:0b10, 100:0b11}.get(odr_hz, 0b00)
22+
comp = 1 if temp_comp else 0
23+
lp = 1 if low_power else 0
24+
cfg_a = (comp<<7) | (lp<<4) | (odr_bits<<2) | 0b00
25+
self.setReg(cfg_a, LIS2MDL_CFG_REG_A) # <- essential to exit IDLE
26+
27+
# CFG_REG_B: default 0x00 (LPF/off_canc off); you can enable LPF if desired
2228
self.setReg(0x00, LIS2MDL_CFG_REG_B)
23-
self.setReg(0x01, LIS2MDL_CFG_REG_C)
2429

30+
# CFG_REG_C: BDU=1 (+ DRDY_on_PIN if requested)
31+
cfg_c = 0x10 | (0x01 if drdy_pin else 0x00)
32+
self.setReg(cfg_c, LIS2MDL_CFG_REG_C)
33+
34+
# --- identical low-level ---
2535
def setReg(self, data, reg):
2636
self.writebuffer[0] = data
2737
self.i2c.writeto_mem(self.address, reg, self.writebuffer)
@@ -30,22 +40,22 @@ def getReg(self, reg):
3040
self.i2c.readfrom_mem_into(self.address, reg, self.readbuffer)
3141
return self.readbuffer[0]
3242

33-
def get2Reg(self, reg):
34-
lowerByte = self.getReg(reg)
35-
higherByte = self.getReg(reg + 1)
36-
return (higherByte << 8) + lowerByte
43+
# signed helper
44+
@staticmethod
45+
def _to_int16(v):
46+
return v - 0x10000 if v & 0x8000 else v
3747

48+
# burst read + signed
3849
def read_magnet(self):
39-
# Read magnetic field data for X, Y, Z axes
40-
x = self.get2Reg(LIS2MDL_OUTX_L_REG)
41-
y = self.get2Reg(LIS2MDL_OUTY_L_REG)
42-
z = self.get2Reg(LIS2MDL_OUTZ_L_REG)
50+
# auto-increment: reg | 0x80 (cf. datasheet I2C op)
51+
buf = self.i2c.readfrom_mem(self.address, LIS2MDL_OUTX_L_REG | 0x80, 6)
52+
x = self._to_int16((buf[1] << 8) | buf[0])
53+
y = self._to_int16((buf[3] << 8) | buf[2])
54+
z = self._to_int16((buf[5] << 8) | buf[4])
4355
return (x, y, z)
4456

4557
def whoAmI(self):
46-
# Read the WHO_AM_I register
4758
return self.getReg(LIS2MDL_WHO_AM_I)
4859

4960
def status(self):
50-
# Read the STATUS register
51-
return self.getReg(LIS2MDL_STATUS_REG)
61+
return self.getReg(LIS2MDL_STATUS_REG)

0 commit comments

Comments
 (0)