Sygaldry
Loading...
Searching...
No Matches
sygsp-icm20948_registers.hpp
1/*
2Copyright 2023 Travis J. West, https://traviswest.ca, Input Devices and Music
3Interaction Laboratory (IDMIL), Centre for Interdisciplinary Research in Music
4Media and Technology (CIRMMT), McGill University, Montréal, Canada, and Univ.
5Lille, Inria, CNRS, Centrale Lille, UMR 9189 CRIStAL, F-59000 Lille, France
6
7SPDX-License-Identifier: MIT
8*/
9
10#pragma once
11#include <bit>
12#include "sygah-string_literal.hpp"
13
14namespace sygaldry { namespace sygsp {
15
20
21static constexpr uint8_t AK09916_I2C_ADDRESS = 0b0001100;
22static constexpr uint8_t ICM20948_I2C_ADDRESS_0 = 0b1101000; // 0x68
23static constexpr uint8_t ICM20948_I2C_ADDRESS_1 = 0b1101001; // 0x69
24
25template<typename Serif>
27{
28
34static uint8_t current_bank_;
35
37template<uint8_t bank>
38static void select_bank_()
39{
40 static_assert(0 <= bank && bank <= 3);
41 if (bank != current_bank_)
42 {
43 Serif::write(127, bank << 4);
44 current_bank_ = bank;
45 }
46}
47
57template <string_literal name, uint8_t addr_, uint8_t bank_, uint8_t reset_>
59{
60 static constexpr uint8_t address = addr_;
61 static constexpr uint8_t bank = bank_;
62 static constexpr uint8_t after_reset = reset_;
63 static constexpr const char * register_name() {return name.value;}
64
65 static void select_bank()
66 {
67 select_bank_<bank>();
68 }
69
70 [[nodiscard]] static uint8_t read()
71 {
72 select_bank();
73 //printf("sygsp-icm20948_registers: %s (%x) read\n", register_name(), address);
74 return Serif::read(address);
75 }
76
77 static void write(uint8_t value)
78 {
79 select_bank();
80 //printf("sygsp-icm20948_registers: %s (%x) write %x\n", register_name(), address, value);
81 Serif::write(address, value);
82 }
83};
84
86template<typename RegisterField, uint8_t value>
87static void read_modify_write()
88{
89 //printf("sygsp-icm20948_registers: %s::%s (%x::%x) rmw\n", RegisterField::register_name(), RegisterField::field_name(), RegisterField::address, RegisterField::mask);
90 static_assert(RegisterField::read && RegisterField::write);
91 uint8_t read = RegisterField::read();
92 uint8_t modify = (read & ~RegisterField::mask) | (value & RegisterField::mask);
93 /* write */ RegisterField::write(modify);
94 //printf("sygsp-icm20948_registers: %s::%s %#04x -> %#04x\n", RegisterField::register_name(), RegisterField::field_name(), read, modify);
95}
96
97
109template<string_literal name, typename Register, uint8_t mask_>
111{
112 static constexpr uint8_t mask = mask_;
113 static constexpr const char * field_name() {return name.value;}
114 [[nodiscard]] static uint8_t read_field()
115 {
116 return mask & Register::read();
117 }
118};
119
126template<string_literal name, typename BitField, uint8_t value>
128{
130 static constexpr const char * state_name() {return name.value;}
131 static void set() { read_modify_write<This, value>(); }
132};
133
140template<string_literal name, typename Register, uint8_t mask>
141struct BitTrigger : BitField<name, Register, mask>
142{
144 static void trigger()
145 {
146 static_assert(std::has_single_bit(mask));
147 read_modify_write<This, mask>();
148 }
149};
150
160template<string_literal name, typename Register, uint8_t mask, bool invert = false>
161struct BitSwitch : BitField<name, Register, mask>
162{
164 static void enable()
165 {
166 static_assert(std::has_single_bit(mask));
167 if constexpr (invert)
168 read_modify_write<This, 0>();
169 else
170 read_modify_write<This, mask>();
171 }
172 static void disable()
173 {
174 static_assert(std::has_single_bit(mask));
175 if constexpr (invert)
176 read_modify_write<This, mask>();
177 else
178 read_modify_write<This, 0>();
179 }
180};
181
186template <string_literal name, uint8_t addr_, uint8_t reset_>
188{
189 static constexpr uint8_t address = addr_;
190 static constexpr uint8_t after_reset = reset_;
191 static constexpr const char * register_name() {return name.value;}
192
193 [[nodiscard]] static uint8_t read()
194 {
195 return Serif::read(address);
196 }
197
198 static void write(uint8_t value)
199 {
200 Serif::write(address, value);
201 }
202};
203
204struct WHO_AM_I : Register<"WHO_AM_I", 0x00, 0, 0xEA> {};
205// read only, no bit fields
206
207struct USER_CTRL : Register<"USER_CTRL", 0x03, 0, 0x00>
208{
209 struct DMP_EN : BitSwitch<"DMP_EN", USER_CTRL, 1 << 7> {};
210 struct FIFO_EN : BitSwitch<"FIFO_EN", USER_CTRL, 1 << 6> {};
211 struct I2C_MST_EN : BitSwitch<"I2C_MST_EN", USER_CTRL, 1 << 5> {};
212 struct I2C_IF_DIS : BitTrigger<"I2C_IF_DIS", USER_CTRL, 1 << 4> {};
213 struct DMP_RST : BitTrigger<"DMP_RST", USER_CTRL, 1 << 3> {};
214 struct SRAM_RST : BitTrigger<"SRAM_RST", USER_CTRL, 1 << 2> {};
215 struct I2C_MST_RST : BitTrigger<"I2C_MST_RST", USER_CTRL, 1 << 1> {};
216};
217
218struct PWR_MGMT_1 : Register<"PWR_MGMT_1", 0x06, 0, 0x41>
219{
220 struct DEVICE_RESET : BitTrigger<"DEVICE_RESET", PWR_MGMT_1, 1 << 7> {};
221 struct SLEEP : BitSwitch<"SLEEP", PWR_MGMT_1, 1 << 6> {};
222 struct LP_EN : BitSwitch<"LP_EN", PWR_MGMT_1, 1 << 5> {};
223 struct TEMP_DIS : BitSwitch<"TEMP_DIS", PWR_MGMT_1, 1 << 3> {};
224 struct CLKSEL : BitField<"CLKSEL", PWR_MGMT_1, 0b111>
225 {
226 struct InternalOscillator : BitFieldState<"InternalOscillator", CLKSEL, 0> {};
227 struct AutoSelect : BitFieldState<"AutoSelect", CLKSEL, 1> {};
228 struct Stop : BitFieldState<"Stop", CLKSEL, 7> {};
229 };
230};
231struct LP_CONFIG : Register<"LP_CONFIG", 0x05, 0, 0x40>
232{
233 struct I2C_MST_CYCLE : BitSwitch<"I2C_MST_CYCLE", LP_CONFIG, 1 << 6> {};
234 struct ACCEL_CYCLE : BitSwitch<"ACCEL_CYCLE", LP_CONFIG, 1 << 5> {};
235 struct GYRO_CYCLE : BitSwitch<"GYRO_CYCLE", LP_CONFIG, 1 << 4> {};
236};
237
238struct PWR_MGMT_2 : Register<"PWR_MGMT_2", 0x07, 0, 0x00>
239{
240 struct DISABLE_ACCEL : BitSwitch<"DISABLE_ACCEL", PWR_MGMT_2, 0b111 << 3> {};
241 struct DISABLE_GYRO : BitSwitch<"DISABLE_GYRO", PWR_MGMT_2, 0b111 << 0> {};
242};
243
244struct INT_PIN_CFG : Register<"INT_PIN_CFG", 0x0F, 0, 0x00>
245{
246 struct INT1_ACTL : BitSwitch<"INT1_ACTL", INT_PIN_CFG, 1 << 7> {};
247 struct INT1_OPEN : BitSwitch<"INT1_OPEN", INT_PIN_CFG, 1 << 6> {};
248 struct INT1_Latch__EN : BitSwitch<"INT1_Latch__EN", INT_PIN_CFG, 1 << 5> {};
249 struct INT_ANYRD_2CLEAR : BitSwitch<"INT_ANYRD_2CLEAR", INT_PIN_CFG, 1 << 4> {};
250 struct ACTL_FSYNC : BitSwitch<"ACTL_FSYNC", INT_PIN_CFG, 1 << 3> {};
251 struct FSYNC_INT_MODE_EN : BitSwitch<"FSYNC_INT_MODE_EN", INT_PIN_CFG, 1 << 2> {};
252 struct BYPASS_EN : BitSwitch<"BYPASS_EN", INT_PIN_CFG, 1 << 1> {};
253};
254
255// interrupt status registers
256struct INT_STATUS_1 : Register<"INT_STATUS_1", 0x1A, 0, 0> {};
257struct INT_STATUS_2 : Register<"INT_STATUS_2", 0x1B, 0, 0> {};
258struct INT_STATUS_3 : Register<"INT_STATUS_3", 0x1C, 0, 0> {};
259
260// delay time registers
261struct DELAY_TIME_H : Register<"DELAY_TIME_H", 0x28, 0, 0> {};
262struct DELAY_TIME_L : Register<"DELAY_TIME_L", 0x29, 0, 0> {};
263
264// main IMU sensor data registers
265struct ACCEL_XOUT_H : Register<"ACCEL_XOUT_H", 0x2D, 0, 0> {};
266struct ACCEL_XOUT_L : Register<"ACCEL_XOUT_L", 0x2E, 0, 0> {};
267struct ACCEL_YOUT_H : Register<"ACCEL_YOUT_H", 0x2F, 0, 0> {};
268struct ACCEL_YOUT_L : Register<"ACCEL_YOUT_L", 0x30, 0, 0> {};
269struct ACCEL_ZOUT_H : Register<"ACCEL_ZOUT_H", 0x31, 0, 0> {};
270struct ACCEL_ZOUT_L : Register<"ACCEL_ZOUT_L", 0x32, 0, 0> {};
271struct GYRO_XOUT_H : Register<"GYRO_XOUT_H", 0x33, 0, 0> {};
272struct GYRO_XOUT_L : Register<"GYRO_XOUT_L", 0x34, 0, 0> {};
273struct GYRO_YOUT_H : Register<"GYRO_YOUT_H", 0x35, 0, 0> {};
274struct GYRO_YOUT_L : Register<"GYRO_YOUT_L", 0x36, 0, 0> {};
275struct GYRO_ZOUT_H : Register<"GYRO_ZOUT_H", 0x37, 0, 0> {};
276struct GYRO_ZOUT_L : Register<"GYRO_ZOUT_L", 0x38, 0, 0> {};
277struct TEMP_OUT_H : Register<"TEMP_OUT_H", 0x39, 0, 0> {};
278struct TEMP_OUT_L : Register<"TEMP_OUT_L", 0x3A, 0, 0> {};
279
280// external sensor data registers
281struct EXT_SLV_SENS_DATA_00 : Register<"EXT_SLV_SENS_DATA_00", 0x3B, 0, 0> {};
282struct EXT_SLV_SENS_DATA_01 : Register<"EXT_SLV_SENS_DATA_01", 0x3C, 0, 0> {};
283struct EXT_SLV_SENS_DATA_02 : Register<"EXT_SLV_SENS_DATA_02", 0x3D, 0, 0> {};
284struct EXT_SLV_SENS_DATA_03 : Register<"EXT_SLV_SENS_DATA_03", 0x3E, 0, 0> {};
285struct EXT_SLV_SENS_DATA_04 : Register<"EXT_SLV_SENS_DATA_04", 0x3F, 0, 0> {};
286struct EXT_SLV_SENS_DATA_05 : Register<"EXT_SLV_SENS_DATA_05", 0x40, 0, 0> {};
287struct EXT_SLV_SENS_DATA_06 : Register<"EXT_SLV_SENS_DATA_06", 0x41, 0, 0> {};
288struct EXT_SLV_SENS_DATA_07 : Register<"EXT_SLV_SENS_DATA_07", 0x42, 0, 0> {};
289struct EXT_SLV_SENS_DATA_08 : Register<"EXT_SLV_SENS_DATA_08", 0x43, 0, 0> {};
290struct EXT_SLV_SENS_DATA_09 : Register<"EXT_SLV_SENS_DATA_09", 0x44, 0, 0> {};
291struct EXT_SLV_SENS_DATA_10 : Register<"EXT_SLV_SENS_DATA_10", 0x45, 0, 0> {};
292struct EXT_SLV_SENS_DATA_11 : Register<"EXT_SLV_SENS_DATA_11", 0x46, 0, 0> {};
293struct EXT_SLV_SENS_DATA_12 : Register<"EXT_SLV_SENS_DATA_12", 0x47, 0, 0> {};
294struct EXT_SLV_SENS_DATA_13 : Register<"EXT_SLV_SENS_DATA_13", 0x48, 0, 0> {};
295struct EXT_SLV_SENS_DATA_14 : Register<"EXT_SLV_SENS_DATA_14", 0x49, 0, 0> {};
296struct EXT_SLV_SENS_DATA_15 : Register<"EXT_SLV_SENS_DATA_15", 0x4A, 0, 0> {};
297struct EXT_SLV_SENS_DATA_16 : Register<"EXT_SLV_SENS_DATA_16", 0x4B, 0, 0> {};
298struct EXT_SLV_SENS_DATA_17 : Register<"EXT_SLV_SENS_DATA_17", 0x4C, 0, 0> {};
299struct EXT_SLV_SENS_DATA_18 : Register<"EXT_SLV_SENS_DATA_18", 0x4D, 0, 0> {};
300struct EXT_SLV_SENS_DATA_19 : Register<"EXT_SLV_SENS_DATA_19", 0x4E, 0, 0> {};
301struct EXT_SLV_SENS_DATA_20 : Register<"EXT_SLV_SENS_DATA_20", 0x4F, 0, 0> {};
302struct EXT_SLV_SENS_DATA_21 : Register<"EXT_SLV_SENS_DATA_21", 0x50, 0, 0> {};
303struct EXT_SLV_SENS_DATA_22 : Register<"EXT_SLV_SENS_DATA_22", 0x51, 0, 0> {};
304struct EXT_SLV_SENS_DATA_23 : Register<"EXT_SLV_SENS_DATA_23", 0x52, 0, 0> {};
305
306// gyro configuration registers
307struct GYRO_SMPLRT_DIV : Register<"GYRO_SMPLRT_DIV", 0x00, 2, 0> {};
308
309struct GYRO_CONFIG_1 : Register<"GYRO_CONFIG_1", 0x01, 2, 0x01>
310{
311 struct GYRO_DLPFCFG : BitField<"GYRO_DLPFCFG", GYRO_CONFIG_1, (0b111 << 3)>
312 {
313 struct LPF_196_6Hz : BitFieldState<"LPF_196_6Hz", GYRO_DLPFCFG, 0b000 << 3> {};
314 struct LPF_151_8Hz : BitFieldState<"LPF_151_8Hz", GYRO_DLPFCFG, 0b001 << 3> {};
315 struct LPF_119_5Hz : BitFieldState<"LPF_119_5Hz", GYRO_DLPFCFG, 0b010 << 3> {};
316 struct LPF_51_2Hz : BitFieldState<"LPF_51_2Hz", GYRO_DLPFCFG, 0b011 << 3> {};
317 struct LPF_23_9Hz : BitFieldState<"LPF_23_9Hz", GYRO_DLPFCFG, 0b100 << 3> {};
318 struct LPF_11_6Hz : BitFieldState<"LPF_11_6Hz", GYRO_DLPFCFG, 0b101 << 3> {};
319 struct LPF_5_7Hz : BitFieldState<"LPF_5_7Hz", GYRO_DLPFCFG, 0b110 << 3> {};
320 struct LPF_361_4Hz : BitFieldState<"LPF_361_4Hz", GYRO_DLPFCFG, 0b111 << 3> {};
321 };
322 struct GYRO_FS_SEL : BitField<"GYRO_FS_SEL", GYRO_CONFIG_1, (0b11 << 1)>
323 {
324 struct DPS_250 : BitFieldState<"DPS_250", GYRO_FS_SEL, 0b000> {};
325 struct DPS_500 : BitFieldState<"DPS_500", GYRO_FS_SEL, 0b010> {};
326 struct DPS_1000 : BitFieldState<"DPS_1000", GYRO_FS_SEL, 0b100> {};
327 struct DPS_2000 : BitFieldState<"DPS_2000", GYRO_FS_SEL, 0b110> {};
328 };
329
330 struct GYRO_FCHOICE : BitSwitch<"GYRO_FCHOICE", GYRO_CONFIG_1, 0b1> {};
331};
332
333struct ACCEL_SMPLRT_DIV_1 : Register<"ACCEL_SMPLRT_DIV_1", 0x10, 2, 0> {};
334struct ACCEL_SMPLRT_DIV_2 : Register<"ACCEL_SMPLRT_DIV_2", 0x11, 2, 0> {};
335
336struct ACCEL_CONFIG : Register<"ACCEL_CONFIG", 0x14, 2, 0x01>
337{
338 struct ACCEL_DLPFCFG : BitField<"ACCEL_DLPFCFG", ACCEL_CONFIG, (0b111 << 3)>
339 {
340 struct LPF_246_0Hz : BitFieldState<"LPF_246_0Hz", ACCEL_DLPFCFG, 0b000 << 3> {};
341 struct LPF_111_4Hz : BitFieldState<"LPF_111_4Hz", ACCEL_DLPFCFG, 0b010 << 3> {};
342 struct LPF_50_4Hz : BitFieldState<"LPF_50_4Hz", ACCEL_DLPFCFG, 0b011 << 3> {};
343 struct LPF_23_9Hz : BitFieldState<"LPF_23_9Hz", ACCEL_DLPFCFG, 0b100 << 3> {};
344 struct LPF_11_5Hz : BitFieldState<"LPF_11_5Hz", ACCEL_DLPFCFG, 0b101 << 3> {};
345 struct LPF_5_7Hz : BitFieldState<"LPF_5_7Hz", ACCEL_DLPFCFG, 0b110 << 3> {};
346 struct LPF_473Hz : BitFieldState<"LPF_473Hz", ACCEL_DLPFCFG, 0b111 << 3> {};
347 };
348
349 struct ACCEL_FS_SEL : BitField<"ACCEL_FS_SEL", ACCEL_CONFIG, (0b11 << 1)>
350 {
351 struct G_2 : BitFieldState<"G_2", ACCEL_FS_SEL, 0b00 << 1> {};
352 struct G_4 : BitFieldState<"G_4", ACCEL_FS_SEL, 0b01 << 1> {};
353 struct G_8 : BitFieldState<"G_8", ACCEL_FS_SEL, 0b10 << 1> {};
354 struct G_16 : BitFieldState<"G_16", ACCEL_FS_SEL, 0b11 << 1> {};
355 };
356
357 struct ACCEL_FCHOICE : BitSwitch<"ACCEL_FCHOICE", ACCEL_CONFIG, 0b1>
358 {
359 struct BYPASS_DLPF : BitFieldState<"BYPASS_DLPF", ACCEL_FCHOICE, 0b0> {};
360 struct ENABLE_DLPF : BitFieldState<"ENABLE_DLPF", ACCEL_FCHOICE, 0b1> {};
361 };
362
363};
364
365// Aux I2C registers
366
367// remember: addr bit 7 is read/write (1 - read, 0 - write), 6:0 are I2C address to access
368struct I2C_SLV4_ADDR : Register<"I2C_SLV4_ADDR", 0x13, 3, 0> {};
369struct I2C_SLV4_REG : Register<"I2C_SLV4_REG", 0x14, 3, 0> {};
370struct I2C_SLV4_DO : Register<"I2C_SLV4_DO", 0x16, 3, 0> {};
371struct I2C_SLV4_DI : Register<"I2C_SLV4_DI", 0x16, 3, 0> {};
372struct I2C_SLV4_CTRL : Register<"I2C_SLV4_ADDR", 0x15, 3, 0>
373{
374 struct I2C_SLV4_EN : BitTrigger<"I2C_SLV4_EN", I2C_SLV4_CTRL, 1 << 7> {};
375 struct I2C_SLV4_INT_EN : BitSwitch<"I2C_SLV4_INT_EN", I2C_SLV4_CTRL, 1 << 6> {};
376 struct I2C_SLV4_REG_DIS : BitSwitch<"I2C_SLV4_REG_DIS", I2C_SLV4_CTRL, 1 << 5> {};
377 struct I2C_SLV4_DLY : BitField<"", I2C_SLV4_CTRL, 0b11111> {};
378};
379
380struct I2C_MST_STATUS : Register<"I2C_MST_STATUS", 0x17, 0, 0> {};
381// AK09916 registers
382
383struct WIA1 : AK09916Register<"Company ID", 0x00, 0x48> {};
384struct WIA2 : AK09916Register<"Device ID", 0x01, 0x09> {};
385// reserved 1 0x02
386// reserved 2 0x03
387// sequential reads in one transaction (I2C auto increment) skip to 10
388
389struct ST1 : AK09916Register<"Status 1", 0x10, 0>
390{
391 struct DOR : BitField<"DOR", ST1, 0b10> {};
392 struct DRDY : BitField<"DRDY", ST1, 0b01> {};
393};
394struct HXL : AK09916Register<"HXL", 0x11, 0> {};
395struct HXH : AK09916Register<"HXH", 0x12, 0> {};
396struct HYL : AK09916Register<"HYL", 0x13, 0> {};
397struct HYH : AK09916Register<"HYH", 0x14, 0> {};
398struct HZL : AK09916Register<"HZL", 0x15, 0> {};
399struct HZH : AK09916Register<"HZH", 0x16, 0> {};
400// TMPS "dummy" registers 0x17
401struct ST2 : AK09916Register<"Status 2", 0x18, 0> {}; // must be read to signal end of read transaction!
402// sequential reads in one transaction (I2C auto increment) roll over to 0
403
404struct CNTL2 : AK09916Register<"CNTL2", 0x31, 0>
405{
406 // The datasheet recommends (sec 9.3, pg 10) that to switch modes,
407 // first change to power down, wait at least 100 us, then switch to the desired mode.
408 // It seems from later sections (9.4.3) that this may not be a strict requirement?
409 struct MODE : BitField<"MODE", CNTL2, 0b00011111>
410 {
411 struct PowerDown : BitFieldState<"PowerDown", MODE, 0b00000> {};
412 struct SingleMeasurement : BitFieldState<"SingleMeasurement", MODE, 0b00001> {};
413 // sampling rates given in the AK09916 datasheet
414 struct ContinuousMode10HZ : BitFieldState<"ContinuousMode1", MODE, 0b00010> {};
415 struct ContinuousMode20Hz : BitFieldState<"ContinuousMode2", MODE, 0b00100> {};
416 struct ContinuousMode50Hz : BitFieldState<"ContinuousMode3", MODE, 0b00110> {};
417 struct ContinuousMode100Hz : BitFieldState<"ContinuousMode4", MODE, 0b01000> {};
418 struct SelfTest : BitFieldState<"SelfTest", MODE, 0b10000> {};
419 };
420};
421
422struct CNTL3 : AK09916Register<"CNTL3", 0x32, 0>
423{
424 struct SRST : BitTrigger<"Soft Reset", CNTL3, 1> {};
425};
426
427};
428
429template<typename Serif>
430uint8_t ICM20948Registers<Serif>::current_bank_ = 0xFF;
431
434} }
static uint8_t current_bank_
Definition sygsp-icm20948_registers.hpp:34
Definition sygsp-icm20948_registers.hpp:188
Definition sygsp-icm20948_registers.hpp:128
Definition sygsp-icm20948_registers.hpp:111
Definition sygsp-icm20948_registers.hpp:162
Definition sygsp-icm20948_registers.hpp:142
Definition sygsp-icm20948_registers.hpp:59
Definition sygsp-icm20948_registers.hpp:209
Definition sygsp-icm20948_registers.hpp:208
Definition sygsp-icm20948_registers.hpp:204
Definition sygsp-icm20948_registers.hpp:27
static void select_bank_()
Switch to a particular user bank, unless it is already selected.
Definition sygsp-icm20948_registers.hpp:38
static void read_modify_write()
read the current state of a register, clear the masked bits of a field, set those bits according to t...
Definition sygsp-icm20948_registers.hpp:87