M5Unit-IMU 0.0.2 git rev:e5b00aa
Loading...
Searching...
No Matches
unit_bmm150_data.hpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD
3 *
4 * SPDX-License-Identifier: MIT
5 */
10#ifndef M5_UNIT_IMU_UNIT_UNIT_BMM150_DATA_HPP
11#define M5_UNIT_IMU_UNIT_UNIT_BMM150_DATA_HPP
12
13#include <array>
14#include <cstdint>
15
16namespace m5 {
17namespace unit {
18namespace bmm150 {
19
25enum class DataRate : uint8_t {
26 Rate10Hz = 0x00,
27 Rate2Hz = 0x01,
28 Rate6Hz = 0x02,
29 Rate8Hz = 0x03,
30 Rate15Hz = 0x04,
31 Rate20Hz = 0x05,
32 Rate25Hz = 0x06,
33 Rate30Hz = 0x07,
34};
35
41enum class Preset : uint8_t {
42 LowPower,
43 Regular,
46};
47
49constexpr uint8_t preset_rep_xy(const Preset p)
50{
51 return (p == Preset::LowPower) ? 0x01
52 : (p == Preset::Regular) ? 0x04
53 : (p == Preset::EnhancedRegular) ? 0x07
54 : 0x17;
55}
56
58constexpr uint8_t preset_rep_z(const Preset p)
59{
60 return (p == Preset::LowPower) ? 0x02
61 : (p == Preset::Regular) ? 0x0E
62 : (p == Preset::EnhancedRegular) ? 0x1A
63 : 0x52;
64}
65
67constexpr uint16_t repetition_xy(const uint8_t rep_xy)
68{
69 return static_cast<uint16_t>(1 + 2 * rep_xy);
70}
71
73constexpr uint16_t repetition_z(const uint8_t rep_z)
74{
75 return static_cast<uint16_t>(1 + rep_z);
76}
77
85constexpr uint32_t measurement_time_us(const uint8_t rep_xy, const uint8_t rep_z)
86{
87 return 145U * repetition_xy(rep_xy) + 500U * repetition_z(rep_z) + 980U;
88}
89
91constexpr uint32_t rate_interval_us(const DataRate rate)
92{
93 return (rate == DataRate::Rate10Hz) ? 100000U
94 : (rate == DataRate::Rate2Hz) ? 500000U
95 : (rate == DataRate::Rate6Hz) ? 166667U
96 : (rate == DataRate::Rate8Hz) ? 125000U
97 : (rate == DataRate::Rate15Hz) ? 66667U
98 : (rate == DataRate::Rate20Hz) ? 50000U
99 : (rate == DataRate::Rate25Hz) ? 40000U
100 : 33333U; // Rate30Hz
101}
102
105constexpr bool repetition_fits(const DataRate rate, const uint8_t rep_xy, const uint8_t rep_z)
106{
107 return measurement_time_us(rep_xy, rep_z) <= rate_interval_us(rate);
108}
109
111constexpr int16_t OVERFLOW_OUTPUT{-32768};
112
113namespace internal {
114constexpr int16_t XY_OVERFLOW_RAW{-4096};
115constexpr int16_t Z_OVERFLOW_RAW{-16384};
116constexpr int32_t Z_POSITIVE_SATURATION{32767};
117constexpr int32_t Z_NEGATIVE_SATURATION{-32767};
118} // namespace internal
119
125struct trim_t {
126 int8_t dig_x1{0};
127 int8_t dig_y1{0};
128 int8_t dig_x2{0};
129 int8_t dig_y2{0};
130 uint16_t dig_z1{0};
131 int16_t dig_z2{0};
132 int16_t dig_z3{0};
133 int16_t dig_z4{0};
134 uint8_t dig_xy1{0};
135 int8_t dig_xy2{0};
136 uint16_t dig_xyz1{0};
137};
138
143struct Data {
144 std::array<uint8_t, 8> raw{};
146
150 inline int16_t x_raw() const
151 {
152 const int16_t v = static_cast<int16_t>((raw[1] << 8) | raw[0]);
153 return static_cast<int16_t>(v >> 3);
154 }
156 inline int16_t y_raw() const
157 {
158 const int16_t v = static_cast<int16_t>((raw[3] << 8) | raw[2]);
159 return static_cast<int16_t>(v >> 3);
160 }
162 inline int16_t z_raw() const
163 {
164 const int16_t v = static_cast<int16_t>((raw[5] << 8) | raw[4]);
165 return static_cast<int16_t>(v >> 1);
166 }
168 inline uint16_t rhall() const
169 {
170 const uint16_t v = static_cast<uint16_t>((raw[7] << 8) | raw[6]);
171 return static_cast<uint16_t>(v >> 2);
172 }
174 inline bool drdy() const
175 {
176 return (raw[6] & 0x01) != 0;
177 }
179
183 inline int16_t comp_x() const
184 {
185 const int16_t data_x = x_raw();
186 if (data_x == internal::XY_OVERFLOW_RAW) {
187 return OVERFLOW_OUTPUT;
188 }
189 uint16_t base = rhall();
190 if (base == 0) {
191 base = trim.dig_xyz1;
192 }
193 if (base == 0) {
194 return OVERFLOW_OUTPUT;
195 }
196
197 const int32_t xyz1_scaled = static_cast<int32_t>(trim.dig_xyz1) * 16384;
198 const uint16_t normalized = static_cast<uint16_t>(xyz1_scaled / base) - static_cast<uint16_t>(0x4000);
199 const int16_t centered = static_cast<int16_t>(normalized);
200 const int32_t squared = static_cast<int32_t>(centered) * static_cast<int32_t>(centered);
201 const int32_t cross_term = static_cast<int32_t>(trim.dig_xy2) * (squared / 128);
202 const int32_t xy1_scaled = static_cast<int32_t>(static_cast<int16_t>(trim.dig_xy1) * 128);
203 const int32_t linear_term = static_cast<int32_t>(centered) * xy1_scaled;
204 const int32_t combined = ((cross_term + linear_term) / 512) + static_cast<int32_t>(0x100000);
205 const int32_t gain = static_cast<int32_t>(static_cast<int16_t>(trim.dig_x2) + static_cast<int16_t>(0xA0));
206 const int32_t scale = (combined * gain) / 4096;
207 const int32_t applied = static_cast<int32_t>(data_x) * scale;
208
209 int16_t result = static_cast<int16_t>(applied / 8192);
210 result = static_cast<int16_t>((result + static_cast<int16_t>(trim.dig_x1) * 8) / 16);
211 return result;
212 }
214 inline int16_t comp_y() const
215 {
216 const int16_t data_y = y_raw();
217 if (data_y == internal::XY_OVERFLOW_RAW) {
218 return OVERFLOW_OUTPUT;
219 }
220 uint16_t base = rhall();
221 if (base == 0) {
222 base = trim.dig_xyz1;
223 }
224 if (base == 0) {
225 return OVERFLOW_OUTPUT;
226 }
227
228 const int32_t normalized_full = (static_cast<int32_t>(trim.dig_xyz1) * 16384) / base;
229 const uint16_t normalized = static_cast<uint16_t>(normalized_full) - static_cast<uint16_t>(0x4000);
230 const int16_t centered = static_cast<int16_t>(normalized);
231 const int32_t squared = static_cast<int32_t>(centered) * static_cast<int32_t>(centered);
232 const int32_t cross_term = static_cast<int32_t>(trim.dig_xy2) * (squared / 128);
233 const int32_t xy1_scaled = static_cast<int32_t>(static_cast<int16_t>(trim.dig_xy1) * 128);
234 const int32_t combined_num = cross_term + static_cast<int32_t>(centered) * xy1_scaled;
235 const int32_t combined = combined_num / 512;
236 const int32_t gain = static_cast<int32_t>(static_cast<int16_t>(trim.dig_y2) + static_cast<int16_t>(0xA0));
237 const int32_t scale = ((combined + static_cast<int32_t>(0x100000)) * gain) / 4096;
238 const int32_t applied = static_cast<int32_t>(data_y) * scale;
239
240 int16_t result = static_cast<int16_t>(applied / 8192);
241 result = static_cast<int16_t>((result + static_cast<int16_t>(trim.dig_y1) * 8) / 16);
242 return result;
243 }
245 inline int16_t comp_z() const
246 {
247 const int16_t data_z = z_raw();
248 if (data_z == internal::Z_OVERFLOW_RAW) {
249 return OVERFLOW_OUTPUT;
250 }
251 const uint16_t rh = rhall();
252 if (trim.dig_z2 == 0 || trim.dig_z1 == 0 || rh == 0 || trim.dig_xyz1 == 0) {
253 return OVERFLOW_OUTPUT;
254 }
255
256 const int16_t hall_offset =
257 static_cast<int16_t>(static_cast<int16_t>(rh) - static_cast<int16_t>(trim.dig_xyz1));
258 const int32_t z3_term = (static_cast<int32_t>(trim.dig_z3) * static_cast<int32_t>(hall_offset)) / 4;
259 const int32_t z_delta = static_cast<int32_t>(data_z - trim.dig_z4) * 32768;
260 const int32_t z1_raw = static_cast<int32_t>(trim.dig_z1) * (static_cast<int16_t>(rh) * 2);
261 const int16_t z1_rounded = static_cast<int16_t>((z1_raw + 32768) / 65536);
262
263 int32_t result = (z_delta - z3_term) / (trim.dig_z2 + z1_rounded);
264
265 if (result > internal::Z_POSITIVE_SATURATION) {
266 result = internal::Z_POSITIVE_SATURATION;
267 } else if (result < internal::Z_NEGATIVE_SATURATION) {
268 result = internal::Z_NEGATIVE_SATURATION;
269 }
270 result /= 16;
271
272 return static_cast<int16_t>(result);
273 }
275
279 inline int32_t adj_x() const
280 {
281 return scale_16(comp_x());
282 }
284 inline int32_t adj_y() const
285 {
286 return scale_16(comp_y());
287 }
289 inline int32_t adj_z() const
290 {
291 return scale_16(comp_z());
292 }
294
295private:
297 static inline int32_t scale_16(const int16_t compensated)
298 {
299 return (compensated == OVERFLOW_OUTPUT) ? compensated : static_cast<int32_t>(compensated) * 16;
300 }
301};
302
303} // namespace bmm150
304} // namespace unit
305} // namespace m5
306#endif
Top level namespace of M5Stack.
Definition ahrs_controller.cpp:26
Unit-related namespace.
One measurement (8 bytes burst from REG_DATA_X_LSB, register 0x42)
Definition unit_bmm150_data.hpp:143
std::array< uint8_t, 8 > raw
[0..1] X, [2..3] Y, [4..5] Z, [6..7] RHALL (bit0 of [6] = DRDY)
Definition unit_bmm150_data.hpp:144
int32_t adj_z() const
comp_z() rescaled to 16 LSB/uT (OVERFLOW_OUTPUT preserved as the -32768 sentinel)
Definition unit_bmm150_data.hpp:289
uint16_t rhall() const
Raw hall resistance (14bit unsigned, register bits[15:2])
Definition unit_bmm150_data.hpp:168
int16_t comp_y() const
Compensated magnetometer Y (OVERFLOW_OUTPUT on overflow)
Definition unit_bmm150_data.hpp:214
int32_t adj_x() const
comp_x() rescaled to 16 LSB/uT (OVERFLOW_OUTPUT preserved as the -32768 sentinel)
Definition unit_bmm150_data.hpp:279
int16_t y_raw() const
Raw magnetometer Y (13bit signed, register bits[15:3])
Definition unit_bmm150_data.hpp:156
trim_t trim
Trim values used by the compensation formulas.
Definition unit_bmm150_data.hpp:145
int16_t comp_x() const
Compensated magnetometer X (OVERFLOW_OUTPUT on overflow)
Definition unit_bmm150_data.hpp:183
bool drdy() const
Data ready flag (bit0 of register 0x48)
Definition unit_bmm150_data.hpp:174
int16_t x_raw() const
Raw magnetometer X (13bit signed, register bits[15:3])
Definition unit_bmm150_data.hpp:150
int16_t comp_z() const
Compensated magnetometer Z (OVERFLOW_OUTPUT on overflow), saturated to +-32767 before scaling.
Definition unit_bmm150_data.hpp:245
int16_t z_raw() const
Raw magnetometer Z (15bit signed, register bits[15:1])
Definition unit_bmm150_data.hpp:162
int32_t adj_y() const
comp_y() rescaled to 16 LSB/uT (OVERFLOW_OUTPUT preserved as the -32768 sentinel)
Definition unit_bmm150_data.hpp:284
Factory trim (calibration) values read from registers 0x5D-0x71, consumed by the compensation formula...
Definition unit_bmm150_data.hpp:125
int16_t dig_z2
0x68/0x69
Definition unit_bmm150_data.hpp:131
int8_t dig_x1
0x5D
Definition unit_bmm150_data.hpp:126
int16_t dig_z4
0x62/0x63
Definition unit_bmm150_data.hpp:133
uint16_t dig_z1
0x6A/0x6B
Definition unit_bmm150_data.hpp:130
uint16_t dig_xyz1
0x6C/0x6D (14bit)
Definition unit_bmm150_data.hpp:136
int8_t dig_y2
0x65
Definition unit_bmm150_data.hpp:129
uint8_t dig_xy1
0x71
Definition unit_bmm150_data.hpp:134
int8_t dig_xy2
0x70
Definition unit_bmm150_data.hpp:135
int8_t dig_y1
0x5E
Definition unit_bmm150_data.hpp:127
int8_t dig_x2
0x64
Definition unit_bmm150_data.hpp:128
int16_t dig_z3
0x6E/0x6F
Definition unit_bmm150_data.hpp:132
DataRate
Output data rate (REG_OP_MODE register bits 5:3, value order is NOT monotonic in Hz)
Definition unit_bmm150_data.hpp:25
@ Rate10Hz
10Hz (power-on default)
constexpr uint32_t rate_interval_us(const DataRate rate)
Output period (us) of the given data rate.
Definition unit_bmm150_data.hpp:91
constexpr uint8_t preset_rep_xy(const Preset p)
REG_REP_XY register value (0x51) for the given preset.
Definition unit_bmm150_data.hpp:49
Preset
Preset accuracy/power modes, controlling the REG_REP_XY/REG_REP_Z repetition counts (see preset_rep_x...
Definition unit_bmm150_data.hpp:41
@ LowPower
Lowest power, lowest accuracy.
@ HighAccuracy
Highest accuracy, highest power.
@ EnhancedRegular
Enhanced accuracy over Regular.
@ Regular
Balanced accuracy/power (recommended default)
constexpr uint8_t preset_rep_z(const Preset p)
REG_REP_Z register value (0x52) for the given preset.
Definition unit_bmm150_data.hpp:58
constexpr int16_t OVERFLOW_OUTPUT
Sentinel returned by comp_x()/comp_y()/comp_z() on overflow or invalid input.
Definition unit_bmm150_data.hpp:111
constexpr uint16_t repetition_z(const uint8_t rep_z)
Repetitions actually performed on Z for a REG_REP_Z register value (nZ = 1 + REPZ)
Definition unit_bmm150_data.hpp:73
constexpr bool repetition_fits(const DataRate rate, const uint8_t rep_xy, const uint8_t rep_z)
Can a measurement with these repetitions complete within one period of this rate?
Definition unit_bmm150_data.hpp:105
constexpr uint32_t measurement_time_us(const uint8_t rep_xy, const uint8_t rep_z)
Active measurement time (us) for the given repetition register values.
Definition unit_bmm150_data.hpp:85
constexpr uint16_t repetition_xy(const uint8_t rep_xy)
Repetitions actually performed on X/Y for a REG_REP_XY register value (nXY = 1 + 2*REPXY)
Definition unit_bmm150_data.hpp:67