FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
hmc5883l.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
22#ifndef HMC5883L_H
23#define HMC5883L_H
24
25#include <math.h>
26#include "common_magneto.h"
27#include "../bits.h"
28#include "../functors.h"
29#include "../i2c_device.h"
30#include "../i2c_device_utilities.h"
31#include "../utilities.h"
32
33namespace devices::magneto
34{
39 inline float magnetic_heading(int16_t x, int16_t y)
40 {
41 float theta = atan2(y, x);
42 return theta;
43 }
44
49 enum class SamplesAveraged : uint8_t
50 {
51 ONE_SAMPLE = 0 << 5,
52 TWO_SAMPLES = 1 << 5,
53 FOUR_SAMPLES = 2 << 5,
54 EIGHT_SAMPLES = 3 << 5
55 };
56
61 enum class DataOutput : uint8_t
62 {
63 RATE_0_75HZ = 0 << 2,
64 RATE_1_5HZ = 1 << 2,
65 RATE_3HZ = 2 << 2,
66 RATE_7_5HZ = 3 << 2,
67 RATE_15HZ = 4 << 2,
68 RATE_30HZ = 5 << 2,
69 RATE_75HZ = 6 << 2
70 };
71
75 enum class MeasurementMode : uint8_t
76 {
77 NORMAL = 0,
78 POSITIVE_BIAS = 1,
79 NEGATIVE_BIAS = 2
80 };
81
85 enum class OperatingMode : uint8_t
86 {
87 CONTINUOUS = 0,
88 SINGLE = 1,
89 IDLE = 2
90 };
91
95 enum class Gain : uint8_t
96 {
97 GAIN_0_88GA = 0 << 5,
98 GAIN_1_3GA = 1 << 5,
99 GAIN_1_9GA = 2 << 5,
100 GAIN_2_5GA = 3 << 5,
101 GAIN_4_0GA = 4 << 5,
102 GAIN_4_7GA = 5 << 5,
103 GAIN_5_6GA = 6 << 5,
104 GAIN_8_1GA = 7 << 5
105 };
106
110 class Status
111 {
112 public:
113 Status() = default;
114
122 bool ready() const
123 {
124 return data_ & READY;
125 }
126
133 bool lock() const
134 {
135 return data_ & LOCK;
136 }
137
138 private:
139 static constexpr uint8_t READY = bits::BV8(0);
140 static constexpr uint8_t LOCK = bits::BV8(1);
141
142 uint8_t data_ = 0;
143 };
144
215 template<typename MANAGER>
216 class HMC5883L : public i2c::I2CDevice<MANAGER>
217 {
218 private:
220 template<typename OUT, typename IN> using FUTURE = typename PARENT::template FUTURE<OUT, IN>;
221
222 // Forward declarations needed by compiler
223 template<uint8_t REGISTER, typename T = uint8_t, typename FUNCTOR = functor::Identity<T>>
225 template<uint8_t REGISTER, typename T = uint8_t, typename FUNCTOR = functor::Identity<T>>
227 template<typename T, uint8_t... REGISTERS>
229
230 static constexpr const uint8_t DEVICE_ADDRESS = 0x1E << 1;
231
232 static constexpr const uint8_t CONFIG_REG_A = 0;
233 static constexpr const uint8_t CONFIG_REG_B = 1;
234 static constexpr const uint8_t MODE_REG = 2;
235 static constexpr const uint8_t OUTPUT_REG_1 = 3;
236 static constexpr const uint8_t STATUS_REG = 9;
237 static constexpr const uint8_t IDENT_REG_A = 10;
238 static constexpr const uint8_t IDENT_REG_B = 11;
239 static constexpr const uint8_t IDENT_REG_C = 12;
240
241 // Transformer functor for Sensor3D inverted fields
242 class Sensor3DSwitcher
243 {
244 public:
245 using ARG_TYPE = Sensor3D;
246 using RES_TYPE = Sensor3D;
247 Sensor3D operator()(const Sensor3D& value) const
248 {
249 Sensor3D result = value;
250 // HMC5883L registers are in order X,Z,Y while Sensor3D is X,Y,Z
251 int16_t temp = result.y;
252 result.y = result.z;
253 result.z = temp;
254 return result;
255 }
256 };
257
258 using Sensor3DTransformer =
260
261 public:
267 explicit HMC5883L(MANAGER& manager) : PARENT{manager, DEVICE_ADDRESS, i2c::I2C_FAST, false} {}
268
269 // Asynchronous API
270 //==================
286 class BeginFuture : public TWriteMultiRegisterFuture<uint8_t, CONFIG_REG_A, CONFIG_REG_B, MODE_REG>
287 {
289 public:
291 explicit BeginFuture( OperatingMode mode = OperatingMode::SINGLE,
292 Gain gain = Gain::GAIN_1_3GA,
293 DataOutput rate = DataOutput::RATE_15HZ,
294 SamplesAveraged samples = SamplesAveraged::ONE_SAMPLE,
295 MeasurementMode measurement = MeasurementMode::NORMAL)
296 : PARENT{ bits::OR8(uint8_t(measurement), uint8_t(rate), uint8_t(samples)),
297 uint8_t(gain), uint8_t(mode)} {}
298
299 Gain gain() const
300 {
301 return static_cast<Gain>(this->get_input().value(1));
302 }
304 };
305
326 {
327 gain_ = GAIN(future.gain());
328 return this->async_multi_write(future);
329 }
330
339 using EndFuture =
340 TWriteRegisterFuture<MODE_REG, uint8_t, functor::Constant<uint8_t, uint8_t(OperatingMode::IDLE)>>;
341
362 {
363 return this->async_write(future);
364 }
365
375
394 {
395 return this->async_read(future);
396 }
397
409
431 {
432 return this->async_read(future);
433 }
434
435 // Synchronous API
436 //=================
453 bool begin(OperatingMode mode = OperatingMode::SINGLE, Gain gain = Gain::GAIN_1_3GA,
454 DataOutput rate = DataOutput::RATE_15HZ, SamplesAveraged samples = SamplesAveraged::ONE_SAMPLE,
455 MeasurementMode measurement = MeasurementMode::NORMAL)
456 {
457 BeginFuture future{mode, gain, rate, samples, measurement};
458 if (begin(future) != 0) return false;
459 return (future.await() == future::FutureStatus::READY);
460 }
461
473 bool end() INLINE
474 {
475 return this->template sync_write<EndFuture>();
476 }
477
486 {
488 if (this->template sync_read<StatusFuture>(status))
489 return status;
490 else
491 return Status{};
492 }
493
509 {
510 return this->template sync_read<MagneticFieldsFuture>(fields);
511 }
512
524 {
525 convert_field_to_mGa(fields.x);
526 convert_field_to_mGa(fields.y);
527 convert_field_to_mGa(fields.z);
528 }
529
530 private:
531 void convert_field_to_mGa(int16_t& value)
532 {
533 value = value * 1000L / gain_;
534 }
535
536 static constexpr uint16_t GAIN(Gain gain)
537 {
538 if (gain == Gain::GAIN_0_88GA) return 1370;
539 if (gain == Gain::GAIN_1_3GA) return 1090;
540 if (gain == Gain::GAIN_1_9GA) return 820;
541 if (gain == Gain::GAIN_2_5GA) return 660;
542 if (gain == Gain::GAIN_4_0GA) return 440;
543 if (gain == Gain::GAIN_4_7GA) return 390;
544 if (gain == Gain::GAIN_5_6GA) return 330;
545 return 230;
546 }
547
548 uint16_t gain_;
549 };
550}
551
552#endif /* HMC5883L_H */
Create a future to be used by asynchronous method begin(BeginFuture&).
Definition: hmc5883l.h:287
I2C device driver for the HMC5883L compass chip.
Definition: hmc5883l.h:217
bool begin(OperatingMode mode=OperatingMode::SINGLE, Gain gain=Gain::GAIN_1_3GA, DataOutput rate=DataOutput::RATE_15HZ, SamplesAveraged samples=SamplesAveraged::ONE_SAMPLE, MeasurementMode measurement=MeasurementMode::NORMAL)
Start operation of this compass chip.
Definition: hmc5883l.h:453
Status status() INLINE
Get the curent chip status.
Definition: hmc5883l.h:485
int status(StatusFuture &future) INLINE
Get the curent chip status.
Definition: hmc5883l.h:393
bool end() INLINE
Stop operation of this compass chip.
Definition: hmc5883l.h:473
void convert_fields_to_mGA(Sensor3D &fields)
Convert raw fields measured obtained with magnetic_fields() to actual physical values,...
Definition: hmc5883l.h:523
int magnetic_fields(MagneticFieldsFuture &future)
Read the magnetic fields (as raw values) on 3 axes (datasheet p15-16).
Definition: hmc5883l.h:430
int begin(BeginFuture &future)
Start operation of this compass chip.
Definition: hmc5883l.h:325
bool magnetic_fields(Sensor3D &fields)
Read the magnetic fields (as raw values) on 3 axes (datasheet p15-16).
Definition: hmc5883l.h:508
HMC5883L(MANAGER &manager)
Create a new device driver for a HMC5883L chip.
Definition: hmc5883l.h:267
int end(EndFuture &future) INLINE
Stop operation of this compass chip.
Definition: hmc5883l.h:361
The chip status, as defined in datasheet p16.
Definition: hmc5883l.h:111
bool lock() const
Check datasheet p16 for further explanations.
Definition: hmc5883l.h:133
bool ready() const
Readiness of device.
Definition: hmc5883l.h:122
Composition functor: applies 2 functors one after each other.
Definition: functors.h:147
Constant functor: always returns a constant value.
Definition: functors.h:110
Base class for all I2C devices.
Definition: i2c_device.h:84
int async_write(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing only one write...
Definition: i2c_device.h:357
int async_multi_write(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing several regist...
Definition: i2c_device.h:379
MANAGER MANAGER
the type of I2C Manager that can handle this device.
Definition: i2c_device.h:87
int async_read(F &future, bool stop=true)
Helper method that asynchronously launches I2C commands for a simple Future performing one write foll...
Definition: i2c_device.h:309
Generic Future that can be used to read an I2C device register.
Generic Future that can be used to write to several I2C device registers.
Generic Future that can be used to write to an I2C device register.
Common types used by 3D sensors (e.g.
#define INLINE
Specific GCC attribute to force the compiler to always inline code of a given function.
Definition: defines.h:57
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
static constexpr uint8_t OR8(uint8_t val1, uint8_t val2)
Create a uint8_t bitwise OR boolean operation between uint8_t operands.
Definition: bits.h:281
Defines API for magnetic sensors for direction, speed and acceleration properties.
float magnetic_heading(int16_t x, int16_t y)
Calculate the magnetic heading (heading measured clockwise from magnetic north) from X and Y magnetic...
Definition: hmc5883l.h:39
MeasurementMode
The measurement mode as defined in datasheet p12, table6.
Definition: hmc5883l.h:76
Gain
The gain to set for the chip, as defined in datasheet p13, table9.
Definition: hmc5883l.h:96
SamplesAveraged
The number of samples to average every time a measurement is required from the HMC5883L chip (datashe...
Definition: hmc5883l.h:50
OperatingMode
The operating mode of the chip as defined in datasheet p10, p14 table 12.
Definition: hmc5883l.h:86
DataOutput
The output rate when used in continuous mode (datasheet p12).
Definition: hmc5883l.h:62
Contains the API around Future implementation.
Definition: future.h:312
@ READY
The status of a Future once its output value has been fully set by a provider.
Define API to define and manage I2C devices.
Definition: i2c.h:51
Structure to store 3 axis data for one sensor (gyroscope or accelerometer).
int16_t y
Sensor value on Y axis.
int16_t z
Sensor value on Z axis.
int16_t x
Sensor value on X axis.