1#![no_std]
4
5pub const ADDRESS: u8 = 0x1E;
6
7pub mod regs {
8
9 pub const CONFIG_A: u8 = 0x00;
10 pub const CONFIG_B: u8 = 0x01;
11 pub const MODE: u8 = 0x02;
12 pub const DATA_X_MSB: u8 = 0x03;
13 pub const DATA_X_LSB: u8 = 0x04;
14 pub const DATA_Z_MSB: u8 = 0x05;
15 pub const DATA_Z_LSB: u8 = 0x06;
16 pub const DATA_Y_MSB: u8 = 0x07;
17 pub const DATA_Y_LSB: u8 = 0x08;
18 pub const STATUS: u8 = 0x09;
19 pub const IDENT_A: u8 = 0x0A;
20 pub const IDENT_B: u8 = 0x0B;
21 pub const IDENT_C: u8 = 0x0C;
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[repr(u8)]
27pub enum Samples {
28 Samples1 = 0b00, Samples2 = 0b01, Samples4 = 0b10, Samples8 = 0b11, }
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35#[repr(u8)]
36pub enum Rate {
37 Hz0_75 = 0b000,
38 Hz1_5 = 0b001,
39 Hz3 = 0b010,
40 Hz7_5 = 0b011,
41 Hz15 = 0b100,
42 Hz30 = 0b101,
43 Hz75 = 0b110,
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52#[repr(u8)]
53pub enum Gain {
54 Gain1370 = 0b000,
56 Gain1090 = 0b001,
58 Gain820 = 0b010,
60 Gain660 = 0b011,
62 Gain440 = 0b100,
64 Gain390 = 0b101,
66 Gain330 = 0b110,
68 Gain230 = 0b111,
70}
71
72impl Gain {
73 fn resolution(&self) -> f32 {
74 match self {
75 Gain::Gain1370 => 0.73,
76 Gain::Gain1090 => 0.92,
77 Gain::Gain820 => 1.22,
78 Gain::Gain660 => 1.52,
79 Gain::Gain440 => 2.27,
80 Gain::Gain390 => 2.56,
81 Gain::Gain330 => 3.03,
82 Gain::Gain230 => 4.35,
83 }
84 }
85}
86
87#[derive(Clone, Copy)]
93pub struct Config {
94 pub data_rate: Rate,
95 pub gain: Gain,
96 pub samples: Samples,
97}
98
99impl Default for Config {
100 fn default() -> Self {
101 Config {
102 data_rate: Rate::Hz15,
103 gain: Gain::Gain1090,
104 samples: Samples::Samples8,
105 }
106 }
107}
108
109#[derive(Debug)]
110pub enum Error<IE> {
111 Bus(IE),
112 InvalidDevice,
113}
114
115impl<E> From<E> for Error<E> {
116 fn from(e: E) -> Self {
117 Error::Bus(e)
118 }
119}
120
121pub struct HMC5883L<I2C> {
122 i2c: I2C,
123 addr: u8,
124 gain: Gain,
125}
126
127impl<I2C> HMC5883L<I2C>
128where
129 I2C: embedded_hal::i2c::I2c,
130{
131 pub fn new(i2c: I2C, addr: u8) -> Self {
132 Self {
133 i2c,
134 addr,
135 gain: Gain::Gain1090,
136 }
137 }
138
139 pub fn new_primary(i2c: I2C) -> Self {
140 Self::new(i2c, ADDRESS)
141 }
142
143 pub fn init(&mut self, config: Config) -> Result<(), Error<I2C::Error>> {
144 let id_a = self.read_reg(regs::IDENT_A)?;
145 let id_b = self.read_reg(regs::IDENT_B)?;
146 let id_c = self.read_reg(regs::IDENT_C)?;
147
148 if id_a != 0x48 || id_b != 0x34 || id_c != 0x33 {
149 return Err(Error::InvalidDevice);
150 }
151
152 let mut cra = 0; cra |= (config.samples as u8) << 5; cra |= (config.data_rate as u8) << 2; self.write_reg(regs::CONFIG_A, cra)?;
156
157 let crb = (config.gain as u8) << 5; self.write_reg(regs::CONFIG_B, crb)?;
159
160 self.write_reg(regs::MODE, 0x00)?; self.gain = config.gain;
163
164 Ok(())
165 }
166
167 pub fn read_raw(&mut self) -> Result<(i16, i16, i16), Error<I2C::Error>> {
168 let mut buf = [0u8; 6];
169
170 self.i2c
172 .write_read(self.addr, &[regs::DATA_X_MSB], &mut buf)?;
173 self.i2c.write(self.addr, &[regs::DATA_X_MSB])?;
174
175 let x = ((buf[0] as i16) << 8) | buf[1] as i16;
176 let y = ((buf[4] as i16) << 8) | buf[5] as i16;
177 let z = ((buf[2] as i16) << 8) | buf[3] as i16;
178
179 Ok((x, y, z))
180 }
181
182 pub fn read_normalized(&mut self) -> Result<(f32, f32, f32), Error<I2C::Error>> {
183 let (x, y, z) = self.read_raw()?;
184
185 let resolution = self.gain.resolution();
186
187 let x_norm = x as f32 * resolution;
188 let y_norm = y as f32 * resolution;
189 let z_norm = z as f32 * resolution;
190
191 Ok((x_norm, y_norm, z_norm))
192 }
193
194 pub fn read_reg(&mut self, reg: u8) -> Result<u8, I2C::Error> {
195 let mut buf = [0];
196 self.i2c.write_read(self.addr, &[reg], &mut buf)?;
197 Ok(buf[0])
198 }
199
200 fn write_reg(&mut self, reg: u8, value: u8) -> Result<(), I2C::Error> {
202 self.i2c.write(self.addr, &[reg, value])
203 }
204}