Open Model Railroad Network (OpenMRN)
Loading...
Searching...
No Matches
TMAG5273.hxx
Go to the documentation of this file.
1
34#ifndef _FREERTOS_DRIVERS_COMMON_TMAG5273_HXX_
35#define _FREERTOS_DRIVERS_COMMON_TMAG5273_HXX_
36
37#include <fcntl.h>
38#include <unistd.h>
39#include <stropts.h>
40#include <endian.h>
41
42#include "i2c-dev.h"
43#include "i2c.h"
44#include "utils/Atomic.hxx"
45#include "utils/logging.h"
46#include "utils/macros.h"
47
49class TMAG5273 : private Atomic
50{
51public:
53 enum I2CAddress : uint8_t
54 {
55 ADDR_A = 0x35,
56 ADDR_B = 0x22,
57 ADDR_C = 0x78,
58 ADDR_D = 0x44,
59 };
60
62 enum class DeviceID : uint8_t
63 {
64 UNKNOWN = 0x00,
65 MT_40_AND_80 = 0x01,
66 MT_133_AND_266 = 0x02,
67 ERROR = 0xFF,
68 };
69
71 enum class ChannelEnable : uint8_t
72 {
73 ALL_OFF = 0x00,
74 X_ENABLE = 0x10,
75 Y_ENABLE = 0x20,
76 XY_ENABLE = 0x30,
77 Z_ENABLE = 0x40,
78 XZ_ENABLE = 0x50,
79 YZ_ENABLE = 0x60,
80 XYZ_ENABLE = 0x70,
81 XYX_ENABLE = 0x80,
82 YXY_ENABLE = 0x90,
83 YZY_ENABLE = 0xA0,
84 XZX_ENABLE = 0xB0,
85 };
86
88 enum class SleepTime : uint8_t
89 {
90 SLEEP_1_MSEC = 0x00,
91 SLEEP_5_MSEC = 0x01,
92 SLEEP_10_MSEC = 0x02,
93 SLEEP_15_MSEC = 0x03,
94 SLEEP_20_MSEC = 0x04,
95 SLEEP_30_MSEC = 0x05,
96 SLEEP_50_MSEC = 0x06,
97 SLEEP_100_MSEC = 0x07,
98 SLEEP_500_MSEC = 0x08,
99 SLEEP_1000_MSEC = 0x09,
100 SLEEP_2000_MSEC = 0x0A,
101 SLEEP_5000_MSEC = 0x0B,
102 SLEEP_20000_MSEC = 0x0C,
103 };
104
106 enum class DeviceStatus : uint8_t
107 {
111 OSC_ERROR_MASK = 0x08,
115 OTP_CRC_ERROR_MASK = 0x02,
117 VCC_UV_ERROR_MASK = 0x01,
118 };
119
121 enum class InterruptConfig : uint8_t
122 {
126 THRESHOLD_ENABLE = 0x40,
128 STATE_MASK = 0x20,
130 MODE_NONE = (0 << 2),
132 MODE_INT_N = (1 << 2),
136 MODE_SCL = (3 << 2),
138 MODE_SCL_EXCEPT_I2C_BUSY = (4 << 2),
140 MASK_INT_N_MASK = 0x01,
141 };
142
144 enum class ConversionStatus : uint8_t
145 {
147 SET_COUNT_MASK = 0xE0,
149 SET_COUNT_SHIFT = 5,
151 POR_MASK = 0x10,
153 DIAG_STATUS_MASK = 0x02,
155 RESULT_STATUS_MASK = 0x01,
156 };
157
159 enum class ConversionAverage : uint8_t
160 {
161 AVG_1 = (0 << 2),
162 AVG_2 = (1 << 2),
163 AVG_4 = (2 << 2),
164 AVG_8 = (3 << 2),
165 AVG_16 = (4 << 2),
166 AVG_32 = (5 << 2),
167 };
168
170 enum class AngleEnable : uint8_t
171 {
172 OFF = (0 << 2),
173 XY_ENABLE = (1 << 2),
174 YZ_ENABLE = (2 << 2),
175 XZ_ENABLE = (3 << 2),
176 };
177
179 enum class OperatingMode : uint8_t
180 {
181 STANDBY = 0x00,
182 SLEEP = 0x01,
183 CONTINUOUS = 0x02,
184 WAKE_UP_AND_SLEEP = 0x03,
185 };
186
190 TMAG5273(uint8_t address = ADDR_A)
191 : i2cAddress_(address)
192 { }
193
198 TMAG5273(const char *i2c_path, uint8_t address = ADDR_A)
199 : i2cAddress_(address)
200 {
201 init(i2c_path);
202 }
203
206 {
207 if (fd_ >= 0)
208 {
209 ::close(fd_);
210 }
211 }
212
213 void init(const char *i2c_path)
214 {
215 int fd = ::open(i2c_path, O_RDWR);
216 HASSERT(fd >= 0);
217 init(fd);
218 }
219
222 void init(int i2c_fd)
223 {
224 fd_ = i2c_fd;
225 }
226
227 friend class MagSensorTest;
228 friend class Input;
229
234 {
235 uint8_t rc[3];
236 // We start with a dummy read to ensure I2C is in a known state.
237 register_read(TMAG5273::DEVICE_ID, rc, 3);
238 if (register_read(TMAG5273::DEVICE_ID, rc, 3) < 0)
239 {
240 // Error reading from i2c.
241 LOG(VERBOSE, "error read");
242 return DeviceID::ERROR;
243 }
244 // mask off the reserved bits of the device ID.
245 rc[0] &= DEVICE_ID_VERSION_MASK;
246 if ((rc[0] != static_cast<uint8_t>(DeviceID::MT_40_AND_80) &&
247 rc[0] != static_cast<uint8_t>(DeviceID::MT_133_AND_266)) ||
248 rc[1] != 0x49 || rc[2] != 0x54)
249 {
250 LOG(VERBOSE, "read %x %x %x", rc[0], rc[1], rc[2]);
251 return DeviceID::UNKNOWN;
252 }
253 return static_cast<DeviceID>(rc[0]);
254 }
255
259 {
260 uint8_t result;
261 register_read(DEVICE_STATUS, &result, 1);
262 return static_cast<DeviceStatus>(result);
263 }
264
268 {
269 register_write(DEVICE_STATUS, static_cast<uint8_t>(status));
270 }
271
275 {
277 SENSOR_CONFIG_1, SCONF1_MAG_CH_MASK, static_cast<uint8_t>(enable));
278 }
279
283 {
285 static_cast<uint8_t>(t));
286 }
287
291 {
292 register_write(INT_CONFIG_1, static_cast<uint8_t>(config));
293 }
294
298 {
300 static_cast<uint8_t>(mode));
301 }
302
306 {
307 uint8_t result;
308 register_read(CONV_STATUS, &result, 1);
309 return result;
310 }
311
314 {
316 CONV_STATUS, static_cast<uint8_t>(ConversionStatus::POR_MASK));
317 }
318
322 {
324 DEVICE_CONFIG_1, DCONF1_AVG_MASK, static_cast<uint8_t>(avg));
325 }
326
330 {
332 SENSOR_CONFIG_2, SCONF2_ANGLE_EN_MASK, static_cast<uint8_t>(angle));
333 }
334
340 void set_angle_gain(uint8_t gain, bool second)
341 {
342 register_write(MAG_GAIN_CONFIG, gain);
344 second ? SCONF2_MAG_GAIN_CH_ADJ2 : SCONF2_MAG_GAIN_CH_ADJ1);
345 }
346
353 void set_offset_1(int8_t offset)
354 {
355 register_write(MAG_OFFSET_CONFIG_1, offset);
356 }
357
363 void set_offset_2(int8_t offset)
364 {
365 register_write(MAG_OFFSET_CONFIG_2, offset);
366 }
367
372 {
373 return static_cast<DeviceID>(
375 }
376
379 void read_conversion_results(int16_t xyz[3])
380 {
381 register_read(X_MSB_RESULT, (uint8_t*)xyz, 6);
382 xyz[0] = be16toh(xyz[0]);
383 xyz[1] = be16toh(xyz[1]);
384 xyz[2] = be16toh(xyz[2]);
385 }
386
390 {
391 int16_t angle;
392 register_read(ANGLE_RESULT_MSB, (uint8_t*)&angle, sizeof(int16_t));
393 return be16toh(angle);
394 }
395
396private:
399 {
402
405
406 SCONF1_MAG_CH_MASK = 0b11110000,
408
411 SCONF2_MAG_GAIN_CH_ADJ1 = 0,
412 SCONF2_MAG_GAIN_CH_ADJ2 = SCONF2_MAG_GAIN_CH_MASK,
413
416
419 };
420
423 {
424 DEVICE_CONFIG_1 = 0x0, // Configure Device Operation Modes
425 DEVICE_CONFIG_2 = 0x1, // Configure Device Operation Modes
426 SENSOR_CONFIG_1 = 0x2, // Sensor Device Operation Modes
427 SENSOR_CONFIG_2 = 0x3, // Sensor Device Operation Modes
428 X_THR_CONFIG = 0x4, // X Threshold Configuration
429 Y_THR_CONFIG = 0x5, // Y Threshold Configuration
430 Z_THR_CONFIG = 0x6, // Z Threshold Configuration
431 T_CONFIG = 0x7, // Temp Sensor Configuration
432 INT_CONFIG_1 = 0x8, // Configure Device Operation Modes
433 MAG_GAIN_CONFIG = 0x9, // Configure Device Operation Modes
434 MAG_OFFSET_CONFIG_1 = 0xA, // Configure Device Operation Modes
435 MAG_OFFSET_CONFIG_2 = 0xB, // Configure Device Operation Modes
436 I2C_ADDRESS = 0xC, // I2C Address Register
437 DEVICE_ID = 0xD, // ID for the device die
438 MANUFACTURER_ID_LSB = 0xE, // Manufacturer ID lower byte
439 MANUFACTURER_ID_MSB = 0xF, // Manufacturer ID upper byte
440 T_MSB_RESULT = 0x10, // Conversion Result Register
441 T_LSB_RESULT = 0x11, // Conversion Result Register
442 X_MSB_RESULT = 0x12, // Conversion Result Register
443 X_LSB_RESULT = 0x13, // Conversion Result Register
444 Y_MSB_RESULT = 0x14, // Conversion Result Register
445 Y_LSB_RESULT = 0x15, // Conversion Result Register
446 Z_MSB_RESULT = 0x16, // Conversion Result Register
447 Z_LSB_RESULT = 0x17, // Conversion Result Register
448 CONV_STATUS = 0x18, // Conversion Status Register
449 ANGLE_RESULT_MSB = 0x19, // Conversion Result Register
450 ANGLE_RESULT_LSB = 0x1A, // Conversion Result Register
451 MAGNITUDE_RESULT = 0x1B, // Conversion Result Register
452 DEVICE_STATUS = 0x1C, // Device_Diag Status Register
453 };
454
461 int register_read(uint8_t reg, uint8_t *data, uint16_t len)
462 {
463 struct i2c_msg msgs[] = {
464 {.addr = i2cAddress_, .flags = 0, .len = 1, .buf = &reg},
465 {.addr = i2cAddress_, .flags = I2C_M_RD, .len = len, .buf = data}};
466
467 struct i2c_rdwr_ioctl_data ioctl_data = {
468 .msgs = msgs, .nmsgs = ARRAYSIZE(msgs)};
469
470 return ::ioctl(fd_, I2C_RDWR, &ioctl_data);
471 }
472
478 void register_write(uint8_t reg, const uint8_t *data, uint16_t len)
479 {
480 HASSERT(len <= 2);
481 uint8_t dat[3];
482 dat[0] = reg;
483 dat[1] = data[0];
484 if (len > 1)
485 {
486 dat[2] = data[1];
487 }
488 struct i2c_msg msgs[] = {{.addr = i2cAddress_,
489 .flags = 0,
490 .len = (uint16_t)(len + 1),
491 .buf = dat}};
492
493 struct i2c_rdwr_ioctl_data ioctl_data = {
494 .msgs = msgs, .nmsgs = ARRAYSIZE(msgs)};
495
496 ::ioctl(fd_, I2C_RDWR, &ioctl_data);
497 }
498
503 void register_write(uint8_t reg, uint8_t value)
504 {
505 register_write(reg, &value, 1);
506 }
507
514 uint8_t register_read(uint8_t reg)
515 {
516 uint8_t ret;
517 register_read(reg, &ret, 1);
518 return ret;
519 }
520
528 void register_modify(uint8_t reg, uint8_t mask, uint8_t value)
529 {
530 uint8_t current = register_read(reg);
531 current &= ~mask;
532 current |= (value & mask);
533 register_write(reg, current);
534 }
535
537 int fd_ = -1;
539 const uint8_t i2cAddress_;
540};
541
547{
548 return static_cast<TMAG5273::DeviceStatus>(
549 static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
550}
551
557{
558 return static_cast<TMAG5273::InterruptConfig>(
559 static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
560}
561
562#endif // _FREERTOS_DRIVERS_COMMON_TMAG5273_HXX_
int ioctl(int fd, unsigned long int key,...)
Request and ioctl transaction.
Definition Fileio.cxx:452
TMAG5273::DeviceStatus operator|(const TMAG5273::DeviceStatus &a, const TMAG5273::DeviceStatus &b)
'|' operator for DeviceStatus.
Definition TMAG5273.hxx:545
Lightweight locking class for protecting small critical sections.
Definition Atomic.hxx:130
Implementation of TMAG5273 sensor driver.
Definition TMAG5273.hxx:50
TMAG5273(const char *i2c_path, uint8_t address=ADDR_A)
Constructor.
Definition TMAG5273.hxx:198
ConversionStatus
conversion status.
Definition TMAG5273.hxx:145
@ POR_MASK
Device powered up, 0 = no power on reset, 1 = power on reset.
@ SET_COUNT_MASK
rolling count of conversion data sets mask
@ DIAG_STATUS_MASK
Diagnositic status, 0 = no diag fail, 1 diag fail detected.
@ RESULT_STATUS_MASK
Conversion, 0 = conversion not complete, 1 = conversion complete.
@ SET_COUNT_SHIFT
rolling count of conversion data sets shift
void register_write(uint8_t reg, uint8_t value)
Writes one register.
Definition TMAG5273.hxx:503
void clr_por_conversion_status()
Clear the power on reset bit of the conversion status.
Definition TMAG5273.hxx:313
uint8_t register_read(uint8_t reg)
Reads a single register.
Definition TMAG5273.hxx:514
DeviceStatus get_device_status()
Get the device status.
Definition TMAG5273.hxx:258
ConversionAverage
Conversion oversampling average configuration.
Definition TMAG5273.hxx:160
@ AVG_4
average 4 saples
@ AVG_32
average 32 saples
@ AVG_8
average 8 saples
@ AVG_2
average 2 saples
@ AVG_16
average 16 saples
void read_conversion_results(int16_t xyz[3])
Read the conversion results.
Definition TMAG5273.hxx:379
void register_write(uint8_t reg, const uint8_t *data, uint16_t len)
Writes one or more (sequential) register.
Definition TMAG5273.hxx:478
DeviceID is_present()
Checks whether the magnetic sensor is present.
Definition TMAG5273.hxx:233
void set_sleep_time(SleepTime t)
Set the sleep time between channels in wake and sleep mode.
Definition TMAG5273.hxx:282
ChannelEnable
Channels to enabled.
Definition TMAG5273.hxx:72
@ XYZ_ENABLE
X, Y, and Z channels enabled.
@ YXY_ENABLE
pseudo-simultaneous Y plus X channels enabled
@ X_ENABLE
X channel enabled.
@ XY_ENABLE
X and Y channels enabled.
@ XZ_ENABLE
X and Z channels enabled.
@ YZ_ENABLE
Y and Z channels enabled.
@ Z_ENABLE
Z channel enabled.
@ ALL_OFF
all channels off, default
@ Y_ENABLE
Y channel enabled.
@ XZX_ENABLE
pseudo-simultaneous X plus Z channels enabled
@ YZY_ENABLE
pseudo-simultaneous Y plus Z channels enabled
@ XYX_ENABLE
pseudo-simultaneous X plus Y channels enabled
InterruptConfig
Interrupt configuration.
Definition TMAG5273.hxx:122
@ MASK_INT_N_MASK
mask interrupt pin when INT_N is connected to ground
@ CONVERSION_COMPLETE_ENABLE
interrupt on conversion complete, 0 = disable, 1 = enable
@ MODE_SCL
interrupt mode through SCL
@ MODE_INT_N_EXCEPT_I2C_BUSY
interrupt mode through INT_N, except when I2C is busy
@ MODE_SCL_EXCEPT_I2C_BUSY
interrupt mode through SCL, except when I2C is busy
@ THRESHOLD_ENABLE
interrupt on threshold, 0 = disabled, 1 = enabled
@ MODE_INT_N
interrupt mode through INT_N
@ STATE_MASK
interrupt state, 0 = lached until clear, 1 = pulse for 10 usec
OperatingMode
Operating modes of the device.
Definition TMAG5273.hxx:180
@ WAKE_UP_AND_SLEEP
wake-up and sleep mode
@ CONTINUOUS
continuous measurement mode
@ STANDBY
starts new conversion at trigger event
void set_offset_2(int8_t offset)
Sets offset correction for the second axis.
Definition TMAG5273.hxx:363
void set_angle_gain(uint8_t gain, bool second)
Sets angle gain parameters.
Definition TMAG5273.hxx:340
~TMAG5273()
Destructor.
Definition TMAG5273.hxx:205
I2CAddress
Supported I2C addresses.
Definition TMAG5273.hxx:54
@ ADDR_D
D1 and D2 device address.
Definition TMAG5273.hxx:58
@ ADDR_C
C1 and C2 device address.
Definition TMAG5273.hxx:57
@ ADDR_A
A1 and A2 device address.
Definition TMAG5273.hxx:55
@ ADDR_B
B1 and B2 device address.
Definition TMAG5273.hxx:56
void enable_channels(ChannelEnable enable)
Enable/disable channels.
Definition TMAG5273.hxx:274
void init(int i2c_fd)
Initializes the device.
Definition TMAG5273.hxx:222
TMAG5273(uint8_t address=ADDR_A)
Constructor.
Definition TMAG5273.hxx:190
void set_oversampling(ConversionAverage avg)
Sets the oversampling+averaging mode.
Definition TMAG5273.hxx:321
BitMasks
Useful bit masks.
Definition TMAG5273.hxx:399
@ DCONF2_OPERATING_MODE_MASK
Mask for the operating mode in DEVICE_CONFIG_2 register.
Definition TMAG5273.hxx:404
@ DCONF1_AVG_MASK
Mask for averaging field in DEVICE_CONFIG_1 register.
Definition TMAG5273.hxx:401
@ SCONF2_ANGLE_EN_MASK
Mask for ANGLE_EN bits in the SENSOR_CONFIG_2 register.
Definition TMAG5273.hxx:415
@ DEVICE_ID_RESERVED_MASK
reserved bits.
Definition TMAG5273.hxx:417
@ SCONF2_MAG_GAIN_CH_MASK
Mask for MAG_GAIN_CH bits in the SENSOR_CONFIG_2 register.
Definition TMAG5273.hxx:410
@ SCONF1_SLEEP_TIME_MASK
sleep time mask.
Definition TMAG5273.hxx:407
@ DEVICE_ID_VERSION_MASK
version bits.
Definition TMAG5273.hxx:418
@ SCONF1_MAG_CH_MASK
Channel enable mask.
Definition TMAG5273.hxx:406
Registers
Device register address offsets.
Definition TMAG5273.hxx:423
DeviceID get_device_id()
Definition TMAG5273.hxx:371
void set_offset_1(int8_t offset)
Sets offset correction for the first axis.
Definition TMAG5273.hxx:353
int16_t read_angle_result()
Read the angle result.
Definition TMAG5273.hxx:389
void clr_device_status(DeviceStatus status)
Get the device status.
Definition TMAG5273.hxx:267
AngleEnable
Angle calculation to enable.
Definition TMAG5273.hxx:171
@ OFF
angle not enabled
SleepTime
Sleep time between conversions when operating mode is wake-up and sleep.
Definition TMAG5273.hxx:89
@ SLEEP_1_MSEC
1 millisecond, default
@ SLEEP_500_MSEC
500 milliseconds
@ SLEEP_1000_MSEC
1000 milliseconds
@ SLEEP_2000_MSEC
2000 milliseconds
@ SLEEP_50_MSEC
50 milliseconds
@ SLEEP_5000_MSEC
5000 milliseconds
@ SLEEP_15_MSEC
15 milliseconds
@ SLEEP_5_MSEC
5 milliseconds
@ SLEEP_100_MSEC
100 milliseconds
@ SLEEP_30_MSEC
30 milliseconds
@ SLEEP_10_MSEC
10 milliseconds
@ SLEEP_20_MSEC
20 milliseconds
@ SLEEP_20000_MSEC
20000 milliseconds
int fd_
I2C device.
Definition TMAG5273.hxx:537
DeviceID
Device Identifier.
Definition TMAG5273.hxx:63
@ MT_40_AND_80
40-mT and 80-mT range supported
@ UNKNOWN
ID unknown or device not detected.
@ MT_133_AND_266
133-mT and 266-mT range supported
@ ERROR
some kind of error occured
int register_read(uint8_t reg, uint8_t *data, uint16_t len)
Reads one or more (sequential) registers.
Definition TMAG5273.hxx:461
void register_modify(uint8_t reg, uint8_t mask, uint8_t value)
Modifies a register value in place.
Definition TMAG5273.hxx:528
uint8_t get_conversion_status()
Get the conversion status.
Definition TMAG5273.hxx:305
const uint8_t i2cAddress_
7-bit address, right aligned.
Definition TMAG5273.hxx:539
void set_angle_en(AngleEnable angle)
Sets whether angle measurement should be enabled.
Definition TMAG5273.hxx:329
void set_interrupt_config(InterruptConfig config)
Set the interrupt config.
Definition TMAG5273.hxx:290
void set_operating_mode(OperatingMode mode)
Set the operating mode.
Definition TMAG5273.hxx:297
DeviceStatus
Device status bit masks.
Definition TMAG5273.hxx:107
@ INT_N_PIN_ERROR_MASK
INT_N pin error, 0 = no error, 1 = error, write 1 to clear.
@ OTP_CRC_ERROR_MASK
OTP CRC error, 0 = no error, 1 = error, write 1 to clear.
@ VCC_UV_ERROR_MASK
VCC < 2.3V, 0 = no VCC UV, 1 = VCC UV, write 1 to clear.
@ INT_N_PIN_RESET_LEVEL_MASK
value of the INT_N pin read at reset, 0 = low, 1 = high
@ OSC_ERROR_MASK
Oscillator error, 0 = no error, 1 = error, write 1 to clear.
#define LOG(level, message...)
Conditionally write a message to the logging output.
Definition logging.h:99
static const int VERBOSE
Loglevel that is usually not printed, reporting debugging information.
Definition logging.h:59
#define ARRAYSIZE(a)
Returns the number of elements in a statically defined array (of static size)
Definition macros.h:185
#define HASSERT(x)
Checks that the value of expression x is true, else terminates the current process.
Definition macros.h:138