diff --git a/Cargo.toml b/Cargo.toml index 2e3fea2..7328148 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,8 @@ defmt = ["dep:defmt"] [dependencies] bitfield-struct = "0.8.0" defmt = { version = "0.3.8", optional = true } -hardware-registers = "0.1.0" +# hardware-registers = "0.1.0" +hardware-registers = { git = "http://github.com/sunsided/hardware-registers", features = ["i2c", "spi"] } [package.metadata.docs.rs] all-features = true diff --git a/src/accel.rs b/src/accel.rs deleted file mode 100644 index ab94cfb..0000000 --- a/src/accel.rs +++ /dev/null @@ -1,1028 +0,0 @@ -//! Accelerometer registers. - -mod types; - -pub use types::*; - -use bitfield_struct::bitfield; - -/// The I2C bus address. -/// -/// For linear acceleration the default (factory) 7-bit slave address is `0011001b`. -/// -/// The slave address is completed with a Read/Write bit. If the bit is `1` (read), a repeated -/// `START` (`SR`) condition must be issued after the two sub-address bytes; if the bit is `0` (write) -/// the master transmits to the slave with the direction unchanged. -/// -/// When the MSB is set to `1`, multiple bytes can be read. -pub const DEFAULT_DEVICE_ADDRESS: u8 = 0b0011001; - -/// Register addresses specific to the accelerometer sensor. -/// -/// See also [`DEFAULT_DEVICE_ADDRESS`]. -#[allow(dead_code)] -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[derive(Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RegisterAddress { - /// See [`ControlRegister1A`]. - CTRL_REG1_A = 0x20, - /// See [`ControlRegister2A`]. - CTRL_REG2_A = 0x21, - /// See [`ControlRegister3A`]. - CTRL_REG3_A = 0x22, - /// See [`ControlRegister4A`]. - CTRL_REG4_A = 0x23, - /// See [`ControlRegister5A`]. - CTRL_REG5_A = 0x24, - /// See [`ControlRegister6A`]. - CTRL_REG6_A = 0x25, - /// See [`ReferenceRegisterA`]. - REFERENCE_A = 0x26, - /// See [`StatusRegisterA`]. - STATUS_REG_A = 0x27, - /// See [`OutXLowA`]. - OUT_X_L_A = 0x28, - /// See [`OutXHighA`]. - OUT_X_H_A = 0x29, - /// See [`OutYLowA`]. - OUT_Y_L_A = 0x2A, - /// See [`OutYHighA`]. - OUT_Y_H_A = 0x2B, - /// See [`OutZLowA`]. - OUT_Z_L_A = 0x2C, - /// See [`OutZHighA`]. - OUT_Z_H_A = 0x2D, - /// See [`FifoControlRegisterA`]. - FIFO_CTRL_REG_A = 0x2E, - /// See [`FifoSourceRegisterA`]. - FIFO_SRC_REG_A = 0x2F, - /// See [`Int1ConfigurationRegisterA`]. - INT1_CFG_A = 0x30, - /// See [`Int1SourceRegisterA`]. - INT1_SRC_A = 0x31, - /// See [`Int1ThresholdRegisterA`]. - INT1_THS_A = 0x32, - /// See [`Int1DurationRegisterA`]. - INT1_DURATION_A = 0x33, - /// See [`Int1ConfigurationRegisterA`]. - INT2_CFG_A = 0x34, - /// See [`Int2SourceRegisterA`]. - INT2_SRC_A = 0x35, - /// See [`Int2ThresholdRegisterA`]. - INT2_THS_A = 0x36, - /// See [`Int2DurationRegisterA`]. - INT2_DURATION_A = 0x37, - /// See [`ClickConfigurationRegisterA`]. - CLICK_CFG_A = 0x38, - /// See [`ClickSourceRegisterA`]. - CLICK_SRC_A = 0x39, - /// See [`ClickThresholdRegisterA`]. - CLICK_THS_A = 0x3A, - /// See [`ClickTimeLimitRegisterA`]. - TIME_LIMIT_A = 0x3B, - /// See [`ClickTimeLatencyRegisterA`]. - TIME_LATENCY_A = 0x3C, - /// See [`ClickTimeWindowRegisterA`]. - TIME_WINDOW_A = 0x3D, -} - -impl RegisterAddress { - /// Returns the address of a register. - pub const fn addr(&self) -> u8 { - *self as u8 - } -} - -impl From for u8 { - fn from(value: RegisterAddress) -> Self { - value.addr() - } -} - -/// [`CTRL_REG1_A`](RegisterAddress::CTRL_REG1_A) (20h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlRegister1A { - /// Data rate selection. - #[bits(4, access = RW)] - pub output_data_rate: AccelOdr, - - /// Low-power mode enable. - #[bits(1, access = RW)] - pub low_power_enable: bool, - - /// Z-axis enable. - #[bits(1, access = RW, default = true)] - pub z_enable: bool, - - /// Y-axis enable. - #[bits(1, access = RW, default = true)] - pub y_enable: bool, - - /// X-axis enable. - #[bits(1, access = RW, default = true)] - pub x_enable: bool, -} - -writable_register!(ControlRegister1A, RegisterAddress::CTRL_REG1_A); - -/// [`CTRL_REG2_A`](RegisterAddress::CTRL_REG2_A) (21h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlRegister2A { - /// High-pass filter mode selection. - #[bits(2, access = RW)] - pub hpm: HighpassFilterMode, - - /// High-pass filter Cutoff frequency selection - #[bits(2, access = RW)] - pub hpcf: u8, // TODO: Add enum - - /// Filter data selection - #[bits(1, access = RW)] - pub fds: bool, - - /// High-pass filter enabled for click function - #[bits(1, access = RW)] - pub hpclick: bool, - - /// High-pass filter enabled for AOI function on Interrupt 2 - #[bits(1, access = RW)] - pub hpis2: bool, - - /// High-pass filter enabled for AOI function on Interrupt 1 - #[bits(1, access = RW)] - pub hpis1: bool, -} - -writable_register!(ControlRegister2A, RegisterAddress::CTRL_REG2_A); - -/// [`CTRL_REG3_A`](RegisterAddress::CTRL_REG3_A) (22h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlRegister3A { - /// Enable CLICK interrupt on INT1 - #[bits(1, access = RW)] - pub i1click: bool, - - /// Enable AOI1 interrupt on INT1 - #[bits(1, access = RW)] - pub i1aoi1: bool, - - /// Enable AOI2 interrupt on INT1 - #[bits(1, access = RW)] - pub i1aoi2: bool, - - /// Enable the accelerometer data ready (`DRDY1`) interrupt on `INT1`. - /// - /// Enabling this on a vanilla sensor will raise an interrupt on `INT1` whenever the - /// accelerometer reads new data. - #[bits(1, access = RW)] - pub i1drdy1: bool, - - /// Enable the accelerometer data ready (`DRDY2`) interrupt on `INT1`. - #[bits(1, access = RW)] - pub i1drdy2: bool, - - /// Enable FIFO watermark interrupt on INT1 - #[bits(1, access = RW)] - pub i1wtm: bool, - - /// Enable FIFO overrun interrupt on INT1 - #[bits(1, access = RW)] - pub i1overrun: bool, - - #[bits(1)] - __: bool, -} - -writable_register!(ControlRegister3A, RegisterAddress::CTRL_REG3_A); - -/// [`CTRL_REG4_A`](RegisterAddress::CTRL_REG4_A) (23h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlRegister4A { - /// Block data update. - /// - /// The BDU bit is used to inhibit output register updates between the reading of the upper and - /// lower register parts. In default mode (BDU = `0`), the lower and upper register parts are - /// updated continuously. If it is not certain to read faster than output data rate, it is - /// recommended to set BDU bit to `1`. In this way, after the reading of the lower (upper) register - /// part, the content of that output register is not updated until the upper (lower) part is read - /// also. This feature avoids reading LSB and MSB related to different samples. - /// - /// * `false` - continuous update - /// * `true` - output registers not updated until MSB and LSB - // have been read - #[bits(1, access = RW)] - pub block_data_update: bool, - - /// Big/little endian data selection. - /// - /// * `false` - data LSB @ lower address - /// * `true` - data MSB @ lower address - #[bits(1, access = RW)] - pub big_endian: bool, - - /// Full-scale selection - #[bits(2, access = RW)] - pub full_scale: Sensitivity, - - /// High-resolution output mode. - #[bits(1, access = RW)] - pub high_resolution: bool, - - #[bits(2, default = 0b00)] - zeros_12: u8, - - /// SPI serial interface mode. - /// - /// * `false` - 4-wire interface - /// * `true` - 3-wire interface - #[bits(1, access = RW)] - pub spi_serial_3wire: bool, -} - -writable_register!(ControlRegister4A, RegisterAddress::CTRL_REG4_A); - -/// [`CTRL_REG5_A`](RegisterAddress::CTRL_REG5_A) (24h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlRegister5A { - /// Reboot memory content - // have been read - #[bits(1, access = RW)] - pub boot: bool, - - /// Enable FIFO - // have been read - #[bits(1, access = RW)] - pub fifo_enable: bool, - - #[bits(2)] - __: u8, - - /// Latch interrupt request on INT1_SRC register, with INT1_SRC register cleared - /// by reading INT1_SRC itself. - // have been read - #[bits(1, access = RW)] - pub lir_int1: bool, - - /// 4D enable: 4D detection is enabled on INT1 when 6D bit on INT1_CFG is set to 1. - // have been read - #[bits(1, access = RW)] - pub d4d_int1: bool, - - /// Latch interrupt request on INT2_SRC register, with INT2_SRC register cleared - /// by reading INT2_SRC itself. - // have been read - #[bits(1, access = RW)] - pub lir_int2: bool, - - /// 4D enable: 4D detection is enabled on INT2 when 6D bit on INT2_CFG is set to 1. - // have been read - #[bits(1, access = RW)] - pub d4d_int2: bool, -} - -writable_register!(ControlRegister5A, RegisterAddress::CTRL_REG5_A); - -/// [`CTRL_REG6_A`](RegisterAddress::CTRL_REG6_A) (25h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ControlRegister6A { - /// CLICK interrupt enable on PAD2. - // have been read - #[bits(1, access = RW)] - pub i2click_en: bool, - - /// Interrupt 1 on PAD2 - // have been read - #[bits(1, access = RW)] - pub i2int1: bool, - - /// Interrupt 2 on PAD2 - // have been read - #[bits(1, access = RW)] - pub i2int2: bool, - - /// Reboot memory content on PAD2 - // have been read - #[bits(1, access = RW)] - pub boot_i1: bool, - - /// Active functions status on PAD2 - // have been read - #[bits(1, access = RW)] - pub p2_active: bool, - - #[bits(1)] - __: u8, - - /// Interrupt active low - /// - /// * `false` - Interrupt is active high - /// * `true` - Interrupt is active low - // have been read - #[bits(1, access = RW)] - pub active_low: bool, - - #[bits(1)] - __: u8, -} - -writable_register!(ControlRegister6A, RegisterAddress::CTRL_REG6_A); - -/// This register sets the acceleration value taken as a reference for the high-pass filter output. -/// (See Doc ID 16941 Rev 1. for the LSM303DLH, non -C version) -/// -/// [`REFERENCE_A`](RegisterAddress::REFERENCE_A) (26h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ReferenceRegisterA { - /// Reference value for interrupt generation. - #[bits(8, access = RO)] - pub reference: u8, -} - -writable_register!(ReferenceRegisterA, RegisterAddress::REFERENCE_A); - -/// [`STATUS_REG_A`](RegisterAddress::STATUS_REG_A) (27h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct StatusRegisterA { - /// X-, Y-, and Z-axis data overrun. - /// * `false` - no overrun has occurred - /// * `true` - a new set of data has overwritten the previous data - #[bits(1, access = RO)] - pub zyx_overrun: bool, - - /// Z-axis data overrun. - /// * `false` - no overrun has occurred - /// * `true` - new data for the Z-axis has overwritten the previous data - #[bits(1, access = RO)] - pub z_overrun: bool, - - /// Y-axis data overrun. - /// * `false` - no overrun has occurred - /// * `true` - new data for the Y-axis has overwritten the previous data - #[bits(1, access = RO)] - pub y_overrun: bool, - - /// X-axis data overrun. - /// * `false` - no overrun has occurred - /// * `true` - new data for the X-axis has overwritten the previous data - #[bits(1, access = RO)] - pub x_overrun: bool, - - /// X-, Y-, and Z-axis new data available. - /// * `false` - a new set of data is not yet available - /// * `true` - a new set of data is available - #[bits(1, access = RO)] - pub xyz_data_available: bool, - - /// Z-axis new data available. - /// * `false` - new data for the Z-axis is not yet available - /// * `true` - new data for the Z-axis is available - #[bits(1, access = RO)] - pub z_data_available: bool, - - /// Y-axis new data available. - /// * `false` - new data for the Y-axis is not yet available - /// * `true` - new data for the Y-axis is available - #[bits(1, access = RO)] - pub y_data_available: bool, - - /// X-axis new data available. - /// * `false` - new data for the X-axis is not yet available - /// * `true` - new data for the X-axis is available - #[bits(1, access = RO)] - pub x_data_available: bool, -} - -readable_register!(StatusRegisterA, RegisterAddress::STATUS_REG_A); - -/// [`OUT_X_L_A`](RegisterAddress::OUT_X_L_A) (28h) -/// -/// Low byte of the 16-bit acceleration value. See [`OutXHighA`] for the high byte. -/// -/// ## Little Endian Data Order -/// -/// Note that the registers are provided in little endian order, i.e. the low byte -/// has the lower register address and will be read first. -/// While the temperature readings follow the same principle, the magnetometer readings -/// have a different order. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutXLowA { - /// Low byte of the X-axis value. - /// - /// Together with [`OutXHighA`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutXLowA, RegisterAddress::OUT_X_L_A); - -/// [`OUT_X_H_A`](RegisterAddress::OUT_X_H_A) (29h) -/// -/// High byte of the 16-bit acceleration value. See [`OutXLowA`] for the low byte. -/// -/// ## Little Endian Data Order -/// -/// Note that the registers are provided in little endian order, i.e. the low byte -/// has the lower register address and will be read first. -/// While the temperature readings follow the same principle, the magnetometer readings -/// have a different order. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutXHighA { - /// High byte of the X-axis value. - /// - /// Together with [`OutXLowA`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutXHighA, RegisterAddress::OUT_X_H_A); - -/// [`OUT_Y_L_A`](RegisterAddress::OUT_Y_L_A) (2Ah) -/// -/// Low byte of the 16-bit acceleration value. See [`OutYHighA`] for the high byte. -/// -/// ## Little Endian Data Order -/// -/// Note that the registers are provided in little endian order, i.e. the low byte -/// has the lower register address and will be read first. -/// While the temperature readings follow the same principle, the magnetometer readings -/// have a different order. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutYLowA { - /// Low byte of the Y-axis acceleration value. - /// - /// Together with [`OutYHighA`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutYLowA, RegisterAddress::OUT_Y_L_A); - -/// [`OUT_Y_H_A`](RegisterAddress::OUT_Y_H_A) (2Bh) -/// -/// High byte of the 16-bit acceleration value. See [`OutYLowA`] for the low byte. -/// -/// ## Little Endian Data Order -/// -/// Note that the registers are provided in little endian order, i.e. the low byte -/// has the lower register address and will be read first. -/// While the temperature readings follow the same principle, the magnetometer readings -/// have a different order. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutYHighA { - /// High byte of the Y-axis acceleration value. - /// - /// Together with [`OutYLowA`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutYHighA, RegisterAddress::OUT_Y_H_A); - -/// [`OUT_Z_L_A`](RegisterAddress::OUT_Z_L_A) (2Ch) -/// -/// Low byte of the 16-bit acceleration value. See [`OutZHighA`] for the high byte. -/// -/// ## Little Endian Data Order -/// -/// Note that the registers are provided in little endian order, i.e. the low byte -/// has the lower register address and will be read first. -/// While the temperature readings follow the same principle, the magnetometer readings -/// have a different order. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutZLowA { - /// Low byte of the Z-axis acceleration value. - /// - /// Together with [`OutZHighA`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutZLowA, RegisterAddress::OUT_Z_L_A); - -/// [`OUT_Z_H_A`](RegisterAddress::OUT_Z_H_A) (2Dh) -/// -/// High byte of the 16-bit acceleration value. See [`OutZLowA`] for the low byte. -/// -/// ## Little Endian Data Order -/// -/// Note that the registers are provided in little endian order, i.e. the low byte -/// has the lower register address and will be read first. -/// While the temperature readings follow the same principle, the magnetometer readings -/// have a different order. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutZHighA { - /// High byte of the Z-axis acceleration value. - /// - /// Together with [`OutZLowA`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutZHighA, RegisterAddress::OUT_Z_H_A); - -/// [`FIFO_CTRL_REG_A`](RegisterAddress::FIFO_CTRL_REG_A) (2Eh) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct FifoControlRegisterA { - /// FIFO mode selection - #[bits(2, access = RW, default = FifoMode::Bypass)] - pub fifo_mode: FifoMode, - - /// Trigger selection - /// - /// * `false` - Trigger event linked to trigger signal on INT1 - /// * `true` - Trigger event linked to trigger signal on INT1 - #[bits(1, access = RW)] - pub trigger_on_int2: bool, - - /// The `fth` field. - #[bits(5, access = RW)] - pub fth: u8, -} - -writable_register!(FifoControlRegisterA, RegisterAddress::FIFO_CTRL_REG_A); - -/// [`FIFO_CTRL_REG_A`](RegisterAddress::FIFO_SRC_REG_A) (2Fh) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct FifoSourceRegisterA { - #[bits(1, access = RO)] - pub wtm: bool, - - #[bits(1, access = RO)] - pub ovrn_fifo: bool, - - #[bits(1, access = RO)] - pub empty: bool, - - #[bits(5, access = RO)] - pub fss: u8, -} - -readable_register!(FifoSourceRegisterA, RegisterAddress::FIFO_SRC_REG_A); - -/// [`INT1_CFG_A`](RegisterAddress::INT1_CFG_A) (2Fh) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int1ConfigurationRegisterA { - /// AND/OR combination of interrupt events. - #[bits(1, access = RW)] - pub aoi: bool, - - /// 6-direction detection function enabled. - #[bits(1, access = RW)] - pub six_d: bool, - - /// Enable interrupt generation on Z high event or on direction recognition. - #[bits(1, access = RW)] - pub zhie_zupe: bool, - - /// Enable interrupt generation on Z low event or on direction recognition. - #[bits(1, access = RW)] - pub zlie_zdowne: bool, - - /// Enable interrupt generation on Y high event or on direction recognition. - #[bits(1, access = RW)] - pub yhie_yupe: bool, - - /// Enable interrupt generation on Y low event or on direction recognition. - #[bits(1, access = RW)] - pub ylie_ydowne: bool, - - /// Enable interrupt generation on X high event or on direction recognition. - #[bits(1, access = RW)] - pub xhie_xupe: bool, - - /// Enable interrupt generation on X low event or on direction recognition. - #[bits(1, access = RW)] - pub xlie_xdowne: bool, -} - -writable_register!(Int1ConfigurationRegisterA, RegisterAddress::INT1_CFG_A); - -/// [`INT1_SRC_A`](RegisterAddress::INT1_SRC_A) (31h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int1SourceRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// Interrupt active. - #[bits(1, access = RO)] - pub ia: bool, - - /// Z high. - #[bits(1, access = RO)] - pub z_high: bool, - - /// Z low. - #[bits(1, access = RO)] - pub z_low: bool, - - /// Y high. - #[bits(1, access = RO)] - pub y_high: bool, - - /// Y low. - #[bits(1, access = RO)] - pub y_low: bool, - - /// X high. - #[bits(1, access = RO)] - pub x_high: bool, - - /// X low. - #[bits(1, access = RO)] - pub x_low: bool, -} - -readable_register!(Int1SourceRegisterA, RegisterAddress::INT1_SRC_A); - -/// [`INT1_SRC_A`](RegisterAddress::INT1_THS_A) (32h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int1ThresholdRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// Interrupt 1 threshold. - #[bits(7, access = RW, default = 0)] - pub threshold: u8, -} - -writable_register!(Int1ThresholdRegisterA, RegisterAddress::INT1_THS_A); - -/// [`INT1_DURATION_A`](RegisterAddress::INT1_DURATION_A) (33h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int1DurationRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// The minimum duration of the Interrupt 1 event to be recognized. Duration - /// steps and maximum values depend on the ODR chosen. - #[bits(7, access = RW, default = 0)] - pub duration: u8, -} - -writable_register!(Int1DurationRegisterA, RegisterAddress::INT1_DURATION_A); - -/// [`INT2_CFG_A`](RegisterAddress::INT2_CFG_A) (34h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int2ConfigurationRegisterA { - /// AND/OR combination of interrupt events. - #[bits(1, access = RW, default = false)] - pub aoi: bool, - - /// 6-direction detection function enabled - #[bits(1, access = RW, default = false)] - pub six_d: bool, - - /// Enable interrupt generation on Z high event - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW, default = false)] - pub zhie: bool, - - /// Enable interrupt generation on Z low event - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value lower than preset threshold - #[bits(1, access = RW, default = false)] - pub zlie: bool, - - /// Enable interrupt generation on Y high event - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW, default = false)] - pub yhie: bool, - - /// Enable interrupt generation on Y low event - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value lower than preset threshold - #[bits(1, access = RW, default = false)] - pub ylie: bool, - - /// Enable interrupt generation on X high event - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW, default = false)] - pub xhie: bool, - - /// Enable interrupt generation on X low event - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value lower than preset threshold - #[bits(1, access = RW, default = false)] - pub xlie: bool, -} - -writable_register!(Int2ConfigurationRegisterA, RegisterAddress::INT2_CFG_A); - -/// [`INT2_SRC_A`](RegisterAddress::INT2_SRC_A) (35h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int2SourceRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// Interrupt active. - #[bits(1, access = RO)] - pub ia: bool, - - /// Z high. - #[bits(1, access = RO)] - pub z_high: bool, - - /// Z low. - #[bits(1, access = RO)] - pub z_low: bool, - - /// Y high. - #[bits(1, access = RO)] - pub y_high: bool, - - /// Y low. - #[bits(1, access = RO)] - pub y_low: bool, - - /// X high. - #[bits(1, access = RO)] - pub x_high: bool, - - /// X low. - #[bits(1, access = RO)] - pub x_low: bool, -} - -readable_register!(Int2SourceRegisterA, RegisterAddress::INT2_SRC_A); - -/// [`INT2_SRC_A`](RegisterAddress::INT2_THS_A) (36h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int2ThresholdRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// Interrupt 2 threshold. - #[bits(7, access = RW, default = 0)] - pub threshold: u8, -} - -writable_register!(Int2ThresholdRegisterA, RegisterAddress::INT2_THS_A); - -/// [`INT2_DURATION_A`](RegisterAddress::INT2_DURATION_A) (37h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Int2DurationRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// The minimum duration of the Interrupt 1 event to be recognized. Duration - /// steps and maximum values depend on the ODR chosen. - #[bits(7, access = RW, default = 0)] - pub duration: u8, -} - -writable_register!(Int2DurationRegisterA, RegisterAddress::INT2_DURATION_A); - -/// [`CLICK_CFG_A`](RegisterAddress::CLICK_CFG_A) (38h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClickConfigurationRegisterA { - #[bits(2)] - __: u8, - - /// Enable interrupt double-click in Z-axis. - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW)] - pub zd: bool, - - /// Enable interrupt single-click in Z-axis. - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW)] - pub zs: bool, - - /// Enable interrupt double-click in Y-axis. - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW)] - pub yd: bool, - - /// Enable interrupt single-click in Y-axis. - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW)] - pub ys: bool, - - /// Enable interrupt double-click in X-axis. - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW)] - pub xd: bool, - - /// Enable interrupt single-click in X-axis. - /// - /// * `false` - disable interrupt request - /// * `true` - enable interrupt request on measured accel. value higher than preset threshold - #[bits(1, access = RW)] - pub xs: bool, -} - -writable_register!(ClickConfigurationRegisterA, RegisterAddress::CLICK_CFG_A); - -/// [`CLICK_SRC_A`](RegisterAddress::CLICK_SRC_A) (39h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClickSourceRegisterA { - #[bits(1)] - __: bool, - - /// Interrupt active. - #[bits(1, access = RO)] - pub ia: bool, - - /// Double-click enable. - /// - /// * `false` - double-click detection disable - /// * `true` - double-click detection enable - #[bits(1, access = RO)] - pub dclick: bool, - - /// Single-click enable. - /// - /// * `false` - single-click detection disable - /// * `true` - signle-click detection enable - #[bits(1, access = RO)] - pub sclick: bool, - - /// Click sign. - #[bits(1, access = RO)] - pub sign_negative: bool, - - /// Z-click detection - /// - /// * `false` - no interrupt - /// * `true` - Z high event has occurred - #[bits(1, access = RO)] - pub z: bool, - - /// Y-click detection - /// - /// * `false` - no interrupt - /// * `true` - Y high event has occurred - #[bits(1, access = RO)] - pub y: bool, - - /// X-click detection - /// - /// * `false` - no interrupt - /// * `true` - X high event has occurred - #[bits(1, access = RO)] - pub x: bool, -} - -readable_register!(ClickSourceRegisterA, RegisterAddress::CLICK_SRC_A); - -/// [`CLICK_THS_A`](RegisterAddress::CLICK_THS_A) (3Ah) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClickThresholdRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// Click threshold. - /// - /// 1 LSB = full-scale / 128. - /// Ths6 through Ths0 define the threshold which is used by the system to start the - /// click-detection procedure. The threshold value is expressed over 7 bits - /// as an unsigned number. - #[bits(7, access = RW, default = 0)] - pub threshold: u8, -} - -writable_register!(ClickThresholdRegisterA, RegisterAddress::CLICK_THS_A); - -/// [`TIME_LIMIT_A`](RegisterAddress::TIME_LIMIT_A) (3Bh) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClickTimeLimitRegisterA { - #[bits(1, default = false)] - zero: bool, - - /// Click time limit. - /// - /// 1 LSB = 1/ODR. TLI6 through TLI0 define the maximum time interval that can elapse - /// between the start of the click-detection procedure (the acceleration on the selected channel - /// exceeds the programmed threshold) and when the acceleration falls below the threshold. - #[bits(7, access = RW, default = 0)] - pub time_limit: u8, -} - -writable_register!(ClickTimeLimitRegisterA, RegisterAddress::TIME_LIMIT_A); - -/// [`TIME_LATENCY_A`](RegisterAddress::TIME_LATENCY_A) (3Ch) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClickTimeLatencyRegisterA { - /// Double-click time latency. - /// - /// 1 LSB = 1/ODR. TLA7 through TLA0 define the time interval that starts after the first click - /// detection where the click-detection procedure is disabled, in cases where the device is - /// configured for double-click detection. - #[bits(8, access = RW, default = 0)] - pub time_latency: u8, -} - -writable_register!(ClickTimeLatencyRegisterA, RegisterAddress::TIME_LATENCY_A); - -/// [`TIME_WINDOW_A`](RegisterAddress::TIME_WINDOW_A) (3Dh) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ClickTimeWindowRegisterA { - /// Double-click time window. - /// - /// 1 LSB = 1/ODR. TW7 through TW0 define the maximum interval of time that can elapse - /// after the end of the latency interval in which the click detection procedure can start, in cases - /// where the device is configured for double-click detection. - #[bits(8, access = RW, default = 0)] - pub time_window: u8, -} - -writable_register!(ClickTimeWindowRegisterA, RegisterAddress::TIME_WINDOW_A); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - #[allow(clippy::unusual_byte_groupings)] - fn status_register_1a() { - let reg = ControlRegister1A::new() - .with_output_data_rate(AccelOdr::Hz400) - .with_low_power_enable(false) - .with_x_enable(true) - .with_y_enable(true) - .with_z_enable(true); - - assert_eq!(reg.into_bits(), 0b0111_0_111); - } -} diff --git a/src/accel/types.rs b/src/accel/types.rs deleted file mode 100644 index 29e477c..0000000 --- a/src/accel/types.rs +++ /dev/null @@ -1,152 +0,0 @@ -//! Types used in the accelerometer registers. - -/// Accelerometer Output Data Rate -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum AccelOdr { - /// Power-down mode (`0b0000`) - Disabled = 0b0000, - /// 1 Hz (`0b0001`) - Hz1 = 0b0001, - /// 10 Hz (`0b0010`) - Hz10 = 0b0010, - /// 25 Hz (`0b0011`) - Hz25 = 0b0011, - /// 50 Hz (`0b0100`) - Hz50 = 0b0100, - /// 100 Hz (`0b0101`) - Hz100 = 0b0101, - /// 200 Hz (`0b0110`) - Hz200 = 0b0110, - /// 400 Hz (`0b0111`) - Hz400 = 0b0111, - /// 1.620 kHz when in Low-Power mode (`0b1000`) - LpHz1620 = 0b1000, - /// 5.376 kHz when in normal mode, 1.344 kHz when in normal mode (`0b1001`) - LpHz1620NormalHz5376 = 0b1001, -} - -impl AccelOdr { - /// Converts the value into an `u8`. - pub const fn into_bits(self) -> u8 { - self as u8 - } - - pub(crate) const fn from_bits(value: u8) -> Self { - match value { - 0b0000 => AccelOdr::Disabled, - 0b0001 => AccelOdr::Hz1, - 0b0010 => AccelOdr::Hz10, - 0b0011 => AccelOdr::Hz25, - 0b0100 => AccelOdr::Hz50, - 0b0101 => AccelOdr::Hz100, - 0b0110 => AccelOdr::Hz200, - 0b0111 => AccelOdr::Hz400, - 0b1000 => AccelOdr::LpHz1620, - 0b1001 => AccelOdr::LpHz1620NormalHz5376, - _ => unreachable!(), - } - } -} - -/// Acceleration sensitivity (full scale selection). -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum Sensitivity { - /// Range: [-2g, +2g]. Sensitivity ~ 1 g / (1 << 14) LSB (`0b00`) - G1 = 0b00, - /// Range: [-4g, +4g]. Sensitivity ~ 2 g / (1 << 14) LSB (`0b01`) - G2 = 0b01, - /// Range: [-8g, +8g]. Sensitivity ~ 4 g / (1 << 14) LSB (`0b10`) - G4 = 0b10, - /// Range: [-16g, +16g]. Sensitivity ~ 12 g / (1 << 14) LSB (`0b11`) - G12 = 0b11, -} - -impl Sensitivity { - /// Converts the value into an `u8`. - pub const fn into_bits(self) -> u8 { - self as u8 - } - - pub(crate) const fn from_bits(value: u8) -> Self { - match value { - 0b00 => Sensitivity::G1, - 0b01 => Sensitivity::G2, - 0b10 => Sensitivity::G4, - 0b11 => Sensitivity::G12, - _ => unreachable!(), - } - } -} - -/// FIFO mode configuration. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum FifoMode { - /// Bypass mode (`0b00`) - /// - /// Bypass the FIFO and store data directly in the output registers. - Bypass = 0b00, - /// FIFO mode (`0b01`) - #[allow(clippy::upper_case_acronyms)] - FIFO = 0b01, - /// Stream mode (`0b10`) - Stream = 0b10, - /// Trigger mode (`0b11`) - Trigger = 0b11, -} - -impl FifoMode { - /// Converts the value into an `u8`. - pub const fn into_bits(self) -> u8 { - self as u8 - } - - pub(crate) const fn from_bits(value: u8) -> Self { - match value { - 0b00 => FifoMode::Bypass, - 0b01 => FifoMode::FIFO, - 0b10 => FifoMode::Stream, - 0b11 => FifoMode::Trigger, - _ => unreachable!(), - } - } -} - -/// High-Pass Filter Mode -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum HighpassFilterMode { - /// Normal mode (`0b00`) - /// - /// Reset reading `HP_RESET_FILTER`. - NormalWithReset = 0b00, - /// Reference signal for filtering (`0b01`) - ReferenceSignal = 0b01, - /// Normal mode (`0b10`) - Normal = 0b10, - /// Autoreset on interrupt event (`0b11`) - AutoresetOnInterrupt = 0b11, -} - -impl HighpassFilterMode { - /// Converts the value into an `u8`. - pub const fn into_bits(self) -> u8 { - self as u8 - } - - pub(crate) const fn from_bits(value: u8) -> Self { - match value { - 0b00 => HighpassFilterMode::NormalWithReset, - 0b01 => HighpassFilterMode::ReferenceSignal, - 0b10 => HighpassFilterMode::Normal, - 0b11 => HighpassFilterMode::AutoresetOnInterrupt, - _ => unreachable!(), - } - } -} diff --git a/src/gyro.rs b/src/gyro.rs new file mode 100644 index 0000000..25985bd --- /dev/null +++ b/src/gyro.rs @@ -0,0 +1,709 @@ +//! Gyroscope registers. + +use crate::types::{Bandwidth, FifoMode, HighpassFilterMode, OutputDataRate, Sensitivity}; +use bitfield_struct::bitfield; + +/// The I²C bus address. +/// +/// The Slave ADdress (SAD) associated with the L3GD20 is `110101xb`. The SDO pin can be +/// used to modify the less significant bit of the device address. If the SDO pin is connected to +/// voltage supply, LSb is `1` (address `1101011b`). Otherwise, if the SDO pin is connected to +/// ground, the LSb value is `0` (address `1101010b`). This solution allows to connect and +/// address two different gyroscopes to the same I²C bus. +pub const DEFAULT_DEVICE_ADDRESS: u8 = 0b0110_1010; + +/// Register addresses specific to the Gyroscope sensor. +/// +/// See also [`DEFAULT_DEVICE_ADDRESS`]. +#[allow(dead_code)] +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[derive(Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum RegisterAddress { + /// See [`WhoAmI`]. Read-only. + WHO_AM_I = 0x0F, + /// See [`ControlRegister1`]. Read-write. + CTRL_REG1 = 0x20, + /// See [`ControlRegister2`]. Read-write. + CTRL_REG2 = 0x21, + /// See [`ControlRegister3`]. Read-write. + CTRL_REG3 = 0x22, + /// See [`ControlRegister4`]. Read-write. + CTRL_REG4 = 0x23, + /// See [`ControlRegister5`]. Read-write. + CTRL_REG5 = 0x24, + /// See [`ReferenceRegister`]. Read-write. + REFERENCE = 0x25, + /// See [`TemperatureRegister`]. Read-only. + OUT_TEMP = 0x26, + /// See [`StatusRegister`]. Read-only. + STATUS_REG = 0x27, + /// See [`OutXLow`]. Read-only. + OUT_X_L = 0x28, + /// See [`OutXHigh`]. Read-only. + OUT_X_H = 0x29, + /// See [`OutYLow`]. Read-only. + OUT_Y_L = 0x2A, + /// See [`OutYHigh`]. Read-only. + OUT_Y_H = 0x2B, + /// See [`OutZLow`]. Read-only. + OUT_Z_L = 0x2C, + /// See [`OutZHigh`]. Read-only. + OUT_Z_H = 0x2D, + /// See [`FifoControlRegister`]. Read-write. + FIFO_CTRL_REG = 0x2E, + /// See [`FifoSourceRegister`]. Read-only. + FIFO_SRC_REG = 0x2F, + /// See [`Int1ConfigurationRegister`]. Read-write. + INT1_CFG = 0x30, + /// See [`Int1SourceRegisterA`]. Read-only. + INT1_SRC = 0x31, + /// See [`Int1ThresholdRegisterXL`]. Read-write. + INT1_TSH_XH = 0x32, + /// See [`missing`]. Read-write. + INT1_TSH_XL = 0x33, + /// See [`Int1ThresholdRegisterYH`]. Read-write. + INT1_TSH_YH = 0x34, + /// See [`Int1ThresholdRegisterYL`]. Read-write. + INT1_TSH_YL = 0x35, + /// See [`Int1ThresholdRegisterZH`]. Read-write. + INT1_TSH_ZH = 0x36, + /// See [`Int1ThresholdRegisterZL`]. Read-write. + INT1_TSH_ZL = 0x37, + /// See [`missing`]. Read-write. + INT1_DURATION = 0x38, +} + +impl RegisterAddress { + /// Returns the address of a register. + pub const fn addr(&self) -> u8 { + *self as u8 + } +} + +impl From for u8 { + fn from(value: RegisterAddress) -> Self { + value.addr() + } +} + +/// [`WHO_AM_I`](RegisterAddress::WHO_AM_I) (0Fh) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct WhoAmI { + /// The identification value. Always `0b11010100` + #[bits(8, access = RO)] + pub ident: u8, +} + +writable_register!(WhoAmI, RegisterAddress::WHO_AM_I); + +/// [`CTRL_REG1`](RegisterAddress::CTRL_REG1) (20h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControlRegister1 { + /// Data rate selection. + #[bits(2, access = RW)] + pub output_data_rate: OutputDataRate, + + /// Bandwidth selection. + #[bits(2, access = RW)] + pub bandwidth: Bandwidth, + + /// "Power-down mode" + /// + /// * `false` to enter power-down mode + /// * `true` to enter normal or sleep mode + /// + /// To enter sleep mode, disable the [`ControlRegister1::z_enable`], [`ControlRegister1::x_enable`] + /// and [`ControlRegister1::y_enable`] flags. + #[bits(1, access = RW)] + pub power_up: bool, + + /// Z-axis enable. + #[bits(1, access = RW, default = true)] + pub z_enable: bool, + + /// X-axis enable. + #[bits(1, access = RW, default = true)] + pub x_enable: bool, + + /// Y-axis enable. + #[bits(1, access = RW, default = true)] + pub y_enable: bool, +} + +writable_register!(ControlRegister1, RegisterAddress::CTRL_REG1); + +/// [`CTRL_REG2`](RegisterAddress::CTRL_REG2) (21h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControlRegister2 { + #[bits(2)] + __: u8, + + /// High-pass filter mode selection. + #[bits(2, access = RW)] + pub hpm: HighpassFilterMode, + + /// High-pass filter Cutoff frequency selection + #[bits(4, access = RW)] + pub hpcf: u8, // TODO: Add enum +} + +writable_register!(ControlRegister2, RegisterAddress::CTRL_REG2); + +/// [`CTRL_REG3`](RegisterAddress::CTRL_REG3) (22h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControlRegister3 { + /// Interrupt enable on INT1 pin. + #[bits(1, access = RW)] + pub i1int1: bool, + + /// Boot status available on INT1. + #[bits(1, access = RW)] + pub i1boot: bool, + + /// Interrupt active configuration on INT1. + /// * `false` - INT1 is active high (default) + /// * `true` - INT1 is active low + #[bits(1, access = RW)] + pub int1_low: bool, + + /// Push-pull / Open drain selector. + /// + /// * `false` - Push-pull (default) + /// * `true` - Open drain + #[bits(1, access = RW)] + pub open_drain: bool, + + /// Date-ready on DRDY/INT2. + #[bits(1, access = RW)] + pub i2drdy: bool, + + /// FIFO watermark interrupt on DRDY/INT2. + #[bits(1, access = RW)] + pub i2wtm: bool, + + /// FIFO overrun interrupt on DRDY/INT2. + #[bits(1, access = RW)] + pub i2orun: bool, + + /// FIFO empty interrupt on DRDY/INT2. + #[bits(1, access = RW)] + pub i2empty: bool, +} + +writable_register!(ControlRegister3, RegisterAddress::CTRL_REG3); + +/// [`CTRL_REG4`](RegisterAddress::CTRL_REG4) (23h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControlRegister4 { + /// Block data update. + /// + /// * `false` - continuous update + /// * `true` - output registers not updated until MSb and LSb read + #[bits(1, access = RW)] + pub block_data_update: bool, + + /// Big/little endian data selection. + /// + /// * `false` - data LSB @ lower address + /// * `true` - data MSB @ lower address + #[bits(1, access = RW)] + pub big_endian: bool, + + /// Full-scale selection + #[bits(2, access = RW)] + pub full_scale: Sensitivity, + + #[bits(3, default = 0b000)] + zeros_12: u8, + + /// SPI serial interface mode. + /// + /// * `false` - 4-wire interface (true) + /// * `true` - 3-wire interface + #[bits(1, access = RW)] + pub spi_serial_3wire: bool, +} + +writable_register!(ControlRegister4, RegisterAddress::CTRL_REG4); + +/// [`CTRL_REG5`](RegisterAddress::CTRL_REG5) (24h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ControlRegister5 { + /// Reboot memory content + // have been read + #[bits(1, access = RW)] + pub boot: bool, + + /// Enable FIFO + // have been read + #[bits(1, access = RW)] + pub fifo_enable: bool, + + #[bits(1)] + __: bool, + + /// High-pass filter enable. + // have been read + #[bits(1, access = RW)] + pub hpen: bool, + + /// INT1 selection configuration. See datasheet. + // have been read + #[bits(2, access = RW)] + pub int1_sel: u8, // TODO: Make enum + + /// Out selection configuration. See datasheet. + // have been read + #[bits(2, access = RW)] + pub out_sel: u8, // TODO: Make enum +} + +writable_register!(ControlRegister5, RegisterAddress::CTRL_REG5); + +/// ## Reference / Data capture register. +/// +/// Reference value for interrupt generation. +/// +/// [`REFERENCE`](RegisterAddress::REFERENCE) (25h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ReferenceRegister { + /// Reference value for interrupt generation. + #[bits(8, access = RW)] + pub reference: u8, +} + +writable_register!(ReferenceRegister, RegisterAddress::REFERENCE); + +/// [`OUT_TEMP`](RegisterAddress::OUT_TEMP) (26h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct TemperatureRegister { + /// Temperature data (1LSB/deg - 8-bit resolution). The value is expressed as two's complement. + #[bits(8, access = RO)] + pub temp: u8, +} + +readable_register!(TemperatureRegister, RegisterAddress::OUT_TEMP); + +/// [`STATUS_REG`](RegisterAddress::STATUS_REG) (27h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct StatusRegister { + /// X, Y, Z-axis data overrun. + #[bits(1, access = RO)] + pub zyx_overrun: bool, + + /// Z-axis data overrun. + #[bits(1, access = RO)] + pub z_overrun: bool, + + /// Y-axis data overrun. + #[bits(1, access = RO)] + pub y_overrun: bool, + + /// X-axis data overrun. + #[bits(1, access = RO)] + pub x_overrun: bool, + + /// X, Y, Z-axis data available. + #[bits(1, access = RO)] + pub zyx_da: bool, + + /// Z-axis data available. + #[bits(1, access = RO)] + pub z_da: bool, + + /// Y-axis data available. + #[bits(1, access = RO)] + pub y_da: bool, + + /// X-axis data available. + #[bits(1, access = RO)] + pub x_da: bool, +} + +readable_register!(StatusRegister, RegisterAddress::STATUS_REG); + +/// [`OUT_X_L`](RegisterAddress::OUT_X_L) (28h) +/// +/// Low byte of the 16-bit angular rate value. See [`OutXHigh`] for the high byte. +/// +/// ## Little Endian Data Order +/// +/// Note that the registers are provided in little endian order, i.e. the low byte +/// has the lower register address and will be read first. +/// While the temperature readings follow the same principle, the magnetometer readings +/// have a different order. +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutXLow { + /// Low byte of the X-axis value. + /// + /// Together with [`OutXHigh`] this forms a reading expressed in two's complement. + #[bits(8, access = RO)] + pub bits: u8, +} + +readable_register!(OutXLow, RegisterAddress::OUT_X_L); + +/// [`OUT_X_H`](RegisterAddress::OUT_X_H) (29h) +/// +/// High byte of the 16-bit angular rate value. See [`OutXLow`] for the low byte. +/// +/// ## Little Endian Data Order +/// +/// Note that the registers are provided in little endian order, i.e. the low byte +/// has the lower register address and will be read first. +/// While the temperature readings follow the same principle, the magnetometer readings +/// have a different order. +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutXHigh { + /// High byte of the X-axis value. + /// + /// Together with [`OutXLowA`] this forms a reading expressed in two's complement. + #[bits(8, access = RO)] + pub bits: u8, +} + +readable_register!(OutXHigh, RegisterAddress::OUT_X_H); + +/// [`OUT_Y_L`](RegisterAddress::OUT_Y_L) (2Ah) +/// +/// Low byte of the 16-bit angular rate value. See [`OutYHigh`] for the high byte. +/// +/// ## Little Endian Data Order +/// +/// Note that the registers are provided in little endian order, i.e. the low byte +/// has the lower register address and will be read first. +/// While the temperature readings follow the same principle, the magnetometer readings +/// have a different order. +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutYLow { + /// Low byte of the Y-axis angular rate value. + /// + /// Together with [`OutYHigh`] this forms a reading expressed in two's complement. + #[bits(8, access = RO)] + pub bits: u8, +} + +readable_register!(OutYLow, RegisterAddress::OUT_Y_L); + +/// [`OUT_Y_H`](RegisterAddress::OUT_Y_H) (2Bh) +/// +/// High byte of the 16-bit angular rate value. See [`OutYLow`] for the low byte. +/// +/// ## Little Endian Data Order +/// +/// Note that the registers are provided in little endian order, i.e. the low byte +/// has the lower register address and will be read first. +/// While the temperature readings follow the same principle, the magnetometer readings +/// have a different order. +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutYHigh { + /// High byte of the Y-axis angular rate value. + /// + /// Together with [`OutYLow`] this forms a reading expressed in two's complement. + #[bits(8, access = RO)] + pub bits: u8, +} + +readable_register!(OutYHigh, RegisterAddress::OUT_Y_H); + +/// [`OUT_Z_L`](RegisterAddress::OUT_Z_L) (2Ch) +/// +/// Low byte of the 16-bit angular rate value. See [`OutZHighA`] for the high byte. +/// +/// ## Little Endian Data Order +/// +/// Note that the registers are provided in little endian order, i.e. the low byte +/// has the lower register address and will be read first. +/// While the temperature readings follow the same principle, the magnetometer readings +/// have a different order. +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutZLow { + /// Low byte of the Z-axis angular rate value. + /// + /// Together with [`OutZHigh`] this forms a reading expressed in two's complement. + #[bits(8, access = RO)] + pub bits: u8, +} + +readable_register!(OutZLow, RegisterAddress::OUT_Z_L); + +/// [`OUT_Z_H`](RegisterAddress::OUT_Z_H) (2Dh) +/// +/// High byte of the 16-bit angular rate value. See [`OutZLow`] for the low byte. +/// +/// ## Little Endian Data Order +/// +/// Note that the registers are provided in little endian order, i.e. the low byte +/// has the lower register address and will be read first. +/// While the temperature readings follow the same principle, the magnetometer readings +/// have a different order. +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct OutZHigh { + /// High byte of the Z-axis angular rate value. + /// + /// Together with [`OutZLowA`] this forms a reading expressed in two's complement. + #[bits(8, access = RO)] + pub bits: u8, +} + +readable_register!(OutZHigh, RegisterAddress::OUT_Z_H); + +/// [`FIFO_CTRL_REG`](RegisterAddress::FIFO_CTRL_REG) (2Eh) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct FifoControlRegister { + /// FIFO mode selection + #[bits(3, access = RW, default = FifoMode::Bypass)] + pub fifo_mode: FifoMode, + + /// FIFO threshold. Watermark level setting. + #[bits(5, access = RW)] + pub watermark: u8, +} + +writable_register!(FifoControlRegister, RegisterAddress::FIFO_CTRL_REG); + +/// [`FIFO_CTRL_REG`](RegisterAddress::FIFO_SRC_REG) (2Fh) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct FifoSourceRegister { + /// Watermark status + /// + /// * `false` - FIFO filling is lower than watermark level. + /// * `true` - FIFO filling is equal or higher than watermark level. + #[bits(1, access = RO)] + pub wtm: bool, + + /// Overrun bit status. + /// + /// * `false` - FIFO is not completely filled. + /// * `true` - FIFO is completely filled. + #[bits(1, access = RO)] + pub ovrn_fifo: bool, + + /// FIFO empty bit. + #[bits(1, access = RO)] + pub empty: bool, + + /// FIFO-stored data level. + #[bits(5, access = RO)] + pub fss: u8, +} + +readable_register!(FifoSourceRegister, RegisterAddress::FIFO_SRC_REG); + +/// [`INT1_CFG`](RegisterAddress::INT1_CFG) (30h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ConfigurationRegister { + /// AND/OR combination of interrupt events. + #[bits(1, access = RW)] + pub aoi: bool, + + /// Latch interrupt request. + #[bits(1, access = RW)] + pub lir: bool, + + /// Enable interrupt generation on Z high event. + #[bits(1, access = RW)] + pub zhie: bool, + + /// Enable interrupt generation on Z low event. + #[bits(1, access = RW)] + pub zlie: bool, + + /// Enable interrupt generation on Y high event. + #[bits(1, access = RW)] + pub yhie: bool, + + /// Enable interrupt generation on Y low event. + #[bits(1, access = RW)] + pub ylie: bool, + + /// Enable interrupt generation on X high event. + #[bits(1, access = RW)] + pub xhie: bool, + + /// Enable interrupt generation on X low event. + #[bits(1, access = RW)] + pub xlie: bool, +} + +writable_register!(Int1ConfigurationRegister, RegisterAddress::INT1_CFG); + +/// [`INT1_SRC_A`](RegisterAddress::INT1_SRC_A) (31h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1SourceRegisterA { + #[bits(1, default = false)] + zero: bool, + + /// Interrupt active. + #[bits(1, access = RO)] + pub ia: bool, + + /// Z high. + #[bits(1, access = RO)] + pub z_high: bool, + + /// Z low. + #[bits(1, access = RO)] + pub z_low: bool, + + /// Y high. + #[bits(1, access = RO)] + pub y_high: bool, + + /// Y low. + #[bits(1, access = RO)] + pub y_low: bool, + + /// X high. + #[bits(1, access = RO)] + pub x_high: bool, + + /// X low. + #[bits(1, access = RO)] + pub x_low: bool, +} + +readable_register!(Int1SourceRegisterA, RegisterAddress::INT1_SRC); + +/// [`INT1_TSH_XH`](RegisterAddress::INT1_TSH_XH) (32h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ThresholdRegisterXH { + #[bits(1, default = false)] + zero: bool, + + /// Interrupt 1 threshold. + #[bits(7, access = RW, default = 0)] + pub threshold: u8, +} + +writable_register!(Int1ThresholdRegisterXH, RegisterAddress::INT1_TSH_XH); + +/// [`INT1_TSH_XL`](RegisterAddress::INT1_TSH_XL) (33h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ThresholdRegisterXL { + /// Interrupt 1 threshold. Low byte. + #[bits(8, access = RW, default = 0)] + pub threshold: u8, +} + +writable_register!(Int1ThresholdRegisterXL, RegisterAddress::INT1_TSH_XL); + +/// [`INT1_TSH_YH`](RegisterAddress::INT1_TSH_YH) (34h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ThresholdRegisterYH { + #[bits(1, default = false)] + zero: bool, + + /// Interrupt 1 threshold. + #[bits(7, access = RW, default = 0)] + pub threshold: u8, +} + +writable_register!(Int1ThresholdRegisterYH, RegisterAddress::INT1_TSH_YH); + +/// [`INT1_TSH_YL`](RegisterAddress::INT1_TSH_YL) (35h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ThresholdRegisterYL { + /// Interrupt 1 threshold. Low byte. + #[bits(8, access = RW, default = 0)] + pub threshold: u8, +} + +writable_register!(Int1ThresholdRegisterYL, RegisterAddress::INT1_TSH_YL); + +/// [`INT1_TSH_ZH`](RegisterAddress::INT1_TSH_ZH) (36h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ThresholdRegisterZH { + #[bits(1, default = false)] + zero: bool, + + /// Interrupt 1 threshold. + #[bits(7, access = RW, default = 0)] + pub threshold: u8, +} + +writable_register!(Int1ThresholdRegisterZH, RegisterAddress::INT1_TSH_ZH); + +/// [`INT1_TSH_ZL`](RegisterAddress::INT1_TSH_ZL) (37h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1ThresholdRegisterZL { + /// Interrupt 1 threshold. Low byte. + #[bits(8, access = RW, default = 0)] + pub threshold: u8, +} + +writable_register!(Int1ThresholdRegisterZL, RegisterAddress::INT1_TSH_ZL); + +/// [`INT1_DURATION`](RegisterAddress::INT1_DURATION) (38h) +#[bitfield(u8, order = Msb)] +#[derive(PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Int1DurationRegister { + /// Wait bit. + /// + /// * `false` - Interrupt falls immediately if the signal crosses the threshold. + /// * `true` - If the signal crosses the selected threshold, the interrupt falls only after the + /// duration has counted the number of samples at the selected data rate, written into the + /// duration counter register. + #[bits(1, access = RW, default = false)] + pub wait: bool, + + /// The minimum duration of the Interrupt 1 event to be recognized. Duration + /// steps and maximum values depend on the ODR chosen. + #[bits(7, access = RW, default = 0)] + pub duration: u8, +} + +writable_register!(Int1DurationRegister, RegisterAddress::INT1_DURATION); diff --git a/src/lib.rs b/src/lib.rs index ebd0c89..6126582 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,9 @@ pub mod prelude { pub use crate::{Register, WritableRegister}; pub use hardware_registers::i2c::*; + pub use hardware_registers::register_address::{RegisterAddress6, RegisterAddress8}; pub use hardware_registers::sizes::R1; + pub use hardware_registers::spi::*; pub use hardware_registers::{FromBits, HardwareRegister, ToBits, WritableHardwareRegister}; } @@ -37,6 +39,15 @@ macro_rules! readable_register { $crate::prelude::RegisterAddress8::new(($addr).addr()); } + impl $crate::prelude::SPIRegister<$crate::prelude::RegisterAddress6, $crate::prelude::R1> + for $type + { + type Backing = u8; + + const REGISTER_ADDRESS: $crate::prelude::RegisterAddress6 = + $crate::prelude::RegisterAddress6::new(($addr).addr()); + } + impl $crate::prelude::ToBits for $type { type Target = u8; @@ -67,8 +78,8 @@ macro_rules! writable_register { }; } -pub mod accel; -pub mod mag; +pub mod gyro; +mod types; /// A sensor register. pub trait Register: prelude::I2CRegister8 + From + Into {} diff --git a/src/mag.rs b/src/mag.rs deleted file mode 100644 index faa013f..0000000 --- a/src/mag.rs +++ /dev/null @@ -1,413 +0,0 @@ -//! Magnetometer and Temperature registers. - -// Resolves a code-generation issue with the bitfield macro. -#![allow(clippy::unnecessary_cast)] - -mod types; - -use bitfield_struct::bitfield; -pub use types::*; - -/// The I2C bus address. -/// -/// For magnetic sensors the default (factory) 7-bit slave address is 0011110xb. -/// -/// The slave address is completed with a Read/Write bit. If the bit is `1` (read), a repeated -/// `START` (`SR`) condition must be issued after the two sub-address bytes. If the bit is `0` (write) -/// the master transmits to the slave with the direction unchanged. -pub const DEFAULT_DEVICE_ADDRESS: u8 = 0b0011110; - -/// Register addresses specific to the magnetometer sensor. -/// -/// See also [`DEFAULT_DEVICE_ADDRESS`]. -#[allow(dead_code)] -#[allow(non_camel_case_types)] -#[allow(missing_docs)] -#[derive(Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum RegisterAddress { - /// See [`ConfigurationARegisterM`]. - CRA_REG_M = 0x00, - /// See [`ConfigurationBRegisterM`]. - CRB_REG_M = 0x01, - /// See [`ModeRegisterM`]. - MR_REG_M = 0x02, - /// See [`OutXHighM`]. - OUT_X_H_M = 0x03, - /// See [`OutXLowM`]. - OUT_X_L_M = 0x04, - /// See [`OutZHighM`]. - OUT_Z_H_M = 0x05, - /// See [`OutZLowM`]. - OUT_Z_L_M = 0x06, - /// See [`OutYHighM`]. - OUT_Y_H_M = 0x07, - /// See [`OutYLowM`]. - OUT_Y_L_M = 0x08, - /// See [`StatusRegisterM`]. - SR_REG_M = 0x09, - /// See [`IdentificationARegisterM`]. - IRA_REG_M = 0x0A, - /// See [`IdentificationBRegisterM`]. - IRB_REG_M = 0x0B, - /// See [`IdentificationCRegisterM`]. - IRC_REG_M = 0x0C, - /// See [`TemperatureOutHighM`]. - TEMP_OUT_H_M = 0x31, - /// See [`TemperatureOutLowM`]. - TEMP_OUT_L_M = 0x32, -} - -impl RegisterAddress { - /// Returns the address of a register. - pub const fn addr(&self) -> u8 { - *self as u8 - } -} - -impl From for u8 { - fn from(value: RegisterAddress) -> Self { - value.addr() - } -} - -/// [`CRA_REG_M`](RegisterAddress::CRA_REG_M) (00h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ConfigurationARegisterM { - /// Temperature sensor enabled. - #[bits(1, access = RW)] - pub temp_en: bool, - - /// Must be zero for correct operation of the device. - #[bits(2, default = 0)] - zeros_56: u8, - - /// Data output rate bits. These bits set the rate at which data is written to all three data - /// output registers. - /// - /// Note that the datasheet has inconsistent information about this field. - /// While section 7.2.1 reports default of `100`, i.e. 15 Hz, the register mapping - /// table 17 appears to be missing a zero. - #[bits(3, access = RW, default = MagOdr::Hz15)] - pub data_output_rate: MagOdr, - - /// Must be zero for correct operation of the device. - #[bits(2, default = 0)] - zeros_01: u8, -} - -writable_register!(ConfigurationARegisterM, RegisterAddress::CRA_REG_M); - -/// Magnetometer gain configuration. -/// -/// [`CRB_REG_M`](RegisterAddress::CRB_REG_M) (01h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ConfigurationBRegisterM { - /// Gain configuration. - #[bits(3, access = RW, default = MagGain::Gauss1_3)] - pub gain: MagGain, - - /// Must be zero for correct operation of the device. - #[bits(5, default = 0)] - zeros_04: u8, -} - -writable_register!(ConfigurationBRegisterM, RegisterAddress::CRB_REG_M); - -/// Magnetometer mode select. -/// -/// [`MR_REG_M`](RegisterAddress::MR_REG_M) (02h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct ModeRegisterM { - /// Must be zero for correct operation of the device. - #[bits(6, default = 0)] - zeros_27: u8, - - /// Device is placed in sleep mode. - #[bits(1, access = RW, default = true)] - pub sleep_mode: bool, - - /// Enables single conversion mode. - /// - /// * `false` - Continuous conversion mode. - /// * `true` - Single conversion mode. - #[bits(1, access = RW, default = true)] - pub single_conversion: bool, -} - -writable_register!(ModeRegisterM, RegisterAddress::MR_REG_M); - -/// [`OUT_X_H_M`](RegisterAddress::OUT_X_H_M) (03h) -/// -/// High byte of the 16-bit acceleration value. See [`OutXLowM`] for the low byte. -/// -/// ## X-Z-Y Order -/// -/// Note that the reading registers are provided in X-Z-Y order, not X, then Y, then Z. -/// -/// ## Big Endian Data Order -/// -/// Note that the registers are provided in big endian order, i.e. the high byte -/// has the lower register address and will be read first. -/// This is different from the accelerometer and temperature reading registers. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutXHighM { - /// High byte of the X-axis magnetic field value. - /// - /// Together with [`OutXLowM`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutXHighM, RegisterAddress::OUT_X_H_M); - -/// [`OUT_X_L_M`](RegisterAddress::OUT_X_L_M) (04h) -/// -/// Low byte of the 16-bit acceleration value. See [`OutXHighM`] for the high byte. -/// -/// ## X-Z-Y Order -/// -/// Note that the reading registers are provided in X-Z-Y order, not X, then Y, then Z. -/// -/// ## Big Endian Data Order -/// -/// Note that the registers are provided in big endian order, i.e. the high byte -/// has the lower register address and will be read first. -/// This is different from the accelerometer and temperature reading registers. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutXLowM { - /// Low byte of the X-axis magnetic field value. - /// - /// Together with [`OutXHighM`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutXLowM, RegisterAddress::OUT_X_L_M); - -/// [`OUT_Z_H_M`](RegisterAddress::OUT_Z_H_M) (05h) -/// -/// High byte of the 16-bit acceleration value. See [`OutZLowM`] for the low byte. -/// -/// ## X-Z-Y Order -/// -/// Note that the reading registers are provided in X-Z-Y order, not X, then Y, then Z. -/// -/// ## Big Endian Data Order -/// -/// Note that the registers are provided in big endian order, i.e. the high byte -/// has the lower register address and will be read first. -/// This is different from the accelerometer and temperature reading registers. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutZHighM { - /// High byte of the Z-axis magnetic field value. - /// - /// Together with [`OutZLowM`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutZHighM, RegisterAddress::OUT_Z_H_M); - -/// [`OUT_Z_L_M`](RegisterAddress::OUT_Z_L_M) (06h) -/// -/// Low byte of the 16-bit acceleration value. See [`OutZHighM`] for the high byte. -/// -/// ## X-Z-Y Order -/// -/// Note that the reading registers are provided in X-Z-Y order, not X, then Y, then Z. -/// -/// ## Big Endian Data Order -/// -/// Note that the registers are provided in big endian order, i.e. the high byte -/// has the lower register address and will be read first. -/// This is different from the accelerometer and temperature reading registers. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutZLowM { - /// Low byte of the Z-axis magnetic field value. - /// - /// Together with [`OutZHighM`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutZLowM, RegisterAddress::OUT_Z_L_M); - -/// [`OUT_Y_H_M`](RegisterAddress::OUT_Y_H_M) (07h) -/// -/// High byte of the 16-bit acceleration value. See [`OutYLowM`] for the low byte. -/// -/// ## X-Z-Y Order -/// -/// Note that the reading registers are provided in X-Z-Y order, not X, then Y, then Z. -/// -/// ## Big Endian Data Order -/// -/// Note that the registers are provided in big endian order, i.e. the high byte -/// has the lower register address and will be read first. -/// This is different from the accelerometer and temperature reading registers. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutYHighM { - /// High byte of the Y-axis magnetic field value. - /// - /// Together with [`OutYLowM`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutYHighM, RegisterAddress::OUT_Y_H_M); - -/// [`OUT_Y_L_M`](RegisterAddress::OUT_Y_L_M) (08h) -/// -/// Low byte of the 16-bit acceleration value. See [`OutYHighM`] for the high byte. -/// -/// ## X-Z-Y Order -/// -/// Note that the reading registers are provided in X-Z-Y order, not X, then Y, then Z. -/// -/// ## Big Endian Data Order -/// -/// Note that the registers are provided in big endian order, i.e. the high byte -/// has the lower register address and will be read first. -/// This is different from the accelerometer and temperature reading registers. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OutYLowM { - /// Low byte of the Y-axis magnetic field value. - /// - /// Together with [`OutYHighM`] this forms a reading expressed in two's complement. - #[bits(8, access = RO)] - pub bits: u8, -} - -readable_register!(OutYLowM, RegisterAddress::OUT_Y_L_M); - -/// [`SR_REG_M`](RegisterAddress::SR_REG_M) (09h) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct StatusRegisterM { - #[bits(6)] - __: u8, - - /// Data output register lock. Once a new set of measurements is available, this bit is - /// set when the first magnetic file data register has been read. - #[bits(1, access = RO)] - pub do_lock: bool, - - /// Data-ready bit. This bit is when a new set of measurements is available. - #[bits(1, access = RO)] - pub data_ready: bool, -} - -readable_register!(StatusRegisterM, RegisterAddress::SR_REG_M); - -/// The identification registers (IR) are used to identify the device. -/// (See Doc ID 16941 Rev 1. for the LSM303DLH, non -C version) -/// -/// [`IRA_REG_M`](RegisterAddress::IRA_REG_M) (0Ah) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct IdentificationARegisterM { - /// Undocumented. Always `01001000`, ASCII `H`. - #[bits(8, access = RO, default = 0b01001000_u8)] - pub value: u8, -} - -readable_register!(IdentificationARegisterM, RegisterAddress::IRA_REG_M); - -/// The identification registers (IR) are used to identify the device. -/// (See Doc ID 16941 Rev 1. for the LSM303DLH, non -C version) -/// -/// [`IRB_REG_M`](RegisterAddress::IRB_REG_M) (0Bh) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct IdentificationBRegisterM { - /// Undocumented. Always `00110100`, ASCII `4`. - #[bits(8, access = RO, default = 0b000110100_u8)] - pub value: u8, -} - -readable_register!(IdentificationBRegisterM, RegisterAddress::IRB_REG_M); - -/// The identification registers (IR) are used to identify the device. -/// (See Doc ID 16941 Rev 1. for the LSM303DLH, non -C version) -/// -/// [`IRC_REG_M`](RegisterAddress::IRC_REG_M) (0Ch) -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct IdentificationCRegisterM { - /// Undocumented. Always `00110011`, ASCII `3`. - #[bits(8, access = RO, default = 0b00110011_u8)] - pub value: u8, -} - -readable_register!(IdentificationCRegisterM, RegisterAddress::IRC_REG_M); - -/// [`TEMP_OUT_H_M`](RegisterAddress::TEMP_OUT_H_M) (0Ch) -/// -/// High byte of the 12-bit temperature reading. -/// -/// Together with [`TemperatureOutLowM`], the value is expressed as two's complement with -/// 8 LSB/deg at 12-bit resolution. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct TemperatureOutHighM { - /// The upper - #[bits(8, access = RO)] - pub value: u8, -} - -readable_register!(TemperatureOutHighM, RegisterAddress::TEMP_OUT_H_M); - -/// [`TEMP_OUT_L_M`](RegisterAddress::TEMP_OUT_L_M) (0Ch) -/// -/// Low byte of the 12-bit temperature reading. -/// -/// Together with [`TemperatureOutLowM`], the value is expressed as two's complement with -/// 8 LSB/deg at 12-bit resolution. -#[bitfield(u8, order = Msb)] -#[derive(PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct TemperatureOutLowM { - /// The lower nibble of the temperature reading. - #[bits(4, access = RO)] - pub value: u8, - - #[bits(4)] - __: u8, -} - -readable_register!(TemperatureOutLowM, RegisterAddress::TEMP_OUT_L_M); - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn cra_defaults() { - let value = ConfigurationARegisterM::new(); - assert_eq!(value.into_bits(), 0b0010000); - } -} diff --git a/src/mag/types.rs b/src/mag/types.rs deleted file mode 100644 index 477b80c..0000000 --- a/src/mag/types.rs +++ /dev/null @@ -1,107 +0,0 @@ -//! Types used in the magnetometer registers. - -/// Magnetometer Output Data Rate -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum MagOdr { - /// 0.75 Hz (`0b000`) - Hz0_75 = 0b000, - /// 1.5 Hz(`0b001`) - Hz1_5 = 0b001, - /// 3 Hz(`0b010`) - Hz3 = 0b010, - /// 7.5 Hz(`0b011`) - Hz7_5 = 0b011, - /// 15 Hz(`0b100`) - Hz15 = 0b100, - /// 30 Hz(`0b101`) - Hz30 = 0b101, - /// 75 Hz(`0b110`) - Hz75 = 0b110, - /// 220 Hz(`0b111`) - Hz220 = 0b111, -} - -impl MagOdr { - /// Converts the value into an `u8`. - pub const fn into_bits(self) -> u8 { - self as u8 - } - - pub(crate) const fn from_bits(value: u8) -> Self { - match value { - 0b000 => MagOdr::Hz0_75, - 0b001 => MagOdr::Hz1_5, - 0b010 => MagOdr::Hz3, - 0b011 => MagOdr::Hz7_5, - 0b100 => MagOdr::Hz15, - 0b101 => MagOdr::Hz30, - 0b110 => MagOdr::Hz75, - 0b111 => MagOdr::Hz220, - _ => unreachable!(), - } - } -} - -/// Magnetometer gain configuration. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -#[repr(u8)] -pub enum MagGain { - /// Sensor input field range ±1.3 Gauss. - /// - /// Gain X, Y and Z: 1100 LSB/Gauss - /// Gain Z: 980 LSB/Gauss - Gauss1_3 = 0b001, - /// Sensor input field range ±1.9 Gauss. - /// - /// Gain X, Y and Z: 855 LSB/Gauss - /// Gain Z: 760 LSB/Gauss - Gauss1_9 = 0b010, - /// Sensor input field range ±2.5 Gauss. - /// - /// Gain X, Y and Z: 670 LSB/Gauss - /// Gain Z: 600 LSB/Gauss - Gauss2_5 = 0b011, - /// Sensor input field range ±4.0 Gauss. - /// - /// Gain X, Y and Z: 450 LSB/Gauss - /// Gain Z: 400 LSB/Gauss - Gauss4_0 = 0b100, - /// Sensor input field range ±4.7 Gauss. - /// - /// Gain X, Y and Z: 400 LSB/Gauss - /// Gain Z: 355 LSB/Gauss - Gauss4_7 = 0b101, - /// Sensor input field range ±5.6 Gauss. - /// - /// Gain X, Y and Z: 330 LSB/Gauss - /// Gain Z: 295 LSB/Gauss - Gauss5_6 = 0b110, - /// Sensor input field range ±8.1 Gauss. - /// - /// Gain X, Y and Z: 230 LSB/Gauss - /// Gain Z: 205 LSB/Gauss - Gauss8_1 = 0b111, -} - -impl MagGain { - /// Converts the value into an `u8`. - pub const fn into_bits(self) -> u8 { - self as u8 - } - - pub(crate) const fn from_bits(value: u8) -> Self { - match value { - 0b001 => MagGain::Gauss1_3, - 0b010 => MagGain::Gauss1_9, - 0b011 => MagGain::Gauss2_5, - 0b100 => MagGain::Gauss4_0, - 0b101 => MagGain::Gauss4_7, - 0b110 => MagGain::Gauss5_6, - 0b111 => MagGain::Gauss8_1, - _ => unreachable!(), - } - } -} diff --git a/src/types.rs b/src/types.rs new file mode 100644 index 0000000..5b68acc --- /dev/null +++ b/src/types.rs @@ -0,0 +1,179 @@ +//! Types used in the Gyroscope registers. + +/// Gyroscope Output Data Rate +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum OutputDataRate { + /// 95 Hz (`0b00`) + Hz95 = 0b00, + /// 190 Hz(`0b01`) + Hz190 = 0b01, + /// 380 Hz(`0b10`) + Hz380 = 0b10, + /// 760 Hz(`0b11`) + Hz760 = 0b11, +} + +impl OutputDataRate { + /// Converts the value into an `u8`. + pub const fn into_bits(self) -> u8 { + self as u8 + } + + pub(crate) const fn from_bits(value: u8) -> Self { + match value { + 0b00 => OutputDataRate::Hz95, + 0b01 => OutputDataRate::Hz190, + 0b10 => OutputDataRate::Hz380, + 0b11 => OutputDataRate::Hz760, + _ => unreachable!(), + } + } +} + +/// Bandwidth +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum Bandwidth { + /// * 12.5 at 95 Hz ([`OutputDataRate::Hz95`]) + /// * 12.5 at 190 Hz ([`OutputDataRate::Hz190`]) + /// * 20 at 380 Hz ([`OutputDataRate::Hz380`]) + /// * 30 at 760 Hz ([`OutputDataRate::Hz760`]) + Bw00 = 0b00, + /// * 25 at 95 Hz ([`OutputDataRate::Hz95`]) + /// * 25 at 190 Hz ([`OutputDataRate::Hz190`]) + /// * 25 at 380 Hz ([`OutputDataRate::Hz380`]) + /// * 35 at 760 Hz ([`OutputDataRate::Hz760`]) + Bw01 = 0b01, + /// * 25 at 95 Hz ([`OutputDataRate::Hz95`]) + /// * 25 at 190 Hz ([`OutputDataRate::Hz190`]) + /// * 25 at 380 Hz ([`OutputDataRate::Hz380`]) + /// * 35 at 760 Hz ([`OutputDataRate::Hz760`]) + Bw10 = 0b10, + /// * 25 at 95 Hz ([`OutputDataRate::Hz95`]) + /// * 70 at 190 Hz ([`OutputDataRate::Hz190`]) + /// * 100 at 380 Hz ([`OutputDataRate::Hz380`]) + /// * 100 at 760 Hz ([`OutputDataRate::Hz760`]) + Bw11 = 0b11, +} + +impl Bandwidth { + /// Converts the value into an `u8`. + pub const fn into_bits(self) -> u8 { + self as u8 + } + + pub(crate) const fn from_bits(value: u8) -> Self { + match value { + 0b00 => Bandwidth::Bw00, + 0b01 => Bandwidth::Bw01, + 0b10 => Bandwidth::Bw10, + 0b11 => Bandwidth::Bw11, + _ => unreachable!(), + } + } +} + +/// High-pass filter mode. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum HighpassFilterMode { + /// Normal mode (reset reading `HP_RESET_FILTER`) + NormalModeResetFilter = 0b00, + /// Reference signal for filtering + ReferenceSignal = 0b01, + // Normal mode + NormalMode = 0b10, + /// Autoreset on interrupt event + AutoresetOnInterrupt = 0b11, +} + +impl HighpassFilterMode { + /// Converts the value into an `u8`. + pub const fn into_bits(self) -> u8 { + self as u8 + } + + pub(crate) const fn from_bits(value: u8) -> Self { + match value { + 0b00 => HighpassFilterMode::NormalModeResetFilter, + 0b01 => HighpassFilterMode::ReferenceSignal, + 0b10 => HighpassFilterMode::NormalMode, + 0b11 => HighpassFilterMode::AutoresetOnInterrupt, + _ => unreachable!(), + } + } +} + +/// Gyroscope sensitivity (full scale selection). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum Sensitivity { + /// 250 dps + G250 = 0b00, + /// 500 dps + G500 = 0b01, + /// 2000 dps + G2000 = 0b10, + /// 2000 dps + G2000_11 = 0b11, +} + +impl Sensitivity { + /// Converts the value into an `u8`. + pub const fn into_bits(self) -> u8 { + self as u8 + } + + pub(crate) const fn from_bits(value: u8) -> Self { + match value { + 0b00 => Sensitivity::G250, + 0b01 => Sensitivity::G500, + 0b10 => Sensitivity::G2000, + 0b11 => Sensitivity::G2000_11, + _ => unreachable!(), + } + } +} + +/// FIFO mode configuration. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[repr(u8)] +pub enum FifoMode { + /// Bypass mode (`0b000`) + /// + /// Bypass the FIFO and store data directly in the output registers. + Bypass = 0b000, + /// FIFO mode (`0b001`) + #[allow(clippy::upper_case_acronyms)] + FIFO = 0b001, + /// Stream mode (`0b010`) + Stream = 0b010, + /// Stream-to-FIFO mode (`0b011`) + StreamToFifo = 0b011, + /// Bypass-to-Stream mode (`0b100`) + BypassToStream = 0b100, +} + +impl FifoMode { + /// Converts the value into an `u8`. + pub const fn into_bits(self) -> u8 { + self as u8 + } + + pub(crate) const fn from_bits(value: u8) -> Self { + match value { + 0b000 => FifoMode::Bypass, + 0b001 => FifoMode::FIFO, + 0b010 => FifoMode::Stream, + 0b011 => FifoMode::StreamToFifo, + 0b100 => FifoMode::BypassToStream, + _ => unreachable!(), + } + } +}