1#![deny(missing_docs)]
8#![no_std]
9
10extern crate embedded_hal as hal;
11
12use hal::blocking::i2c::{Write, WriteRead};
13
14const I2C_ADDRESS: u8 = 0x0d;
15
16#[allow(dead_code)]
17#[allow(non_camel_case_types)]
18#[derive(Copy, Clone)]
19#[repr(u8)]
20enum Register {
21 DATA_OUT_X_L = 0,
22 DATA_OUT_X_H = 1,
23 DATA_OUT_Y_L = 2,
24 DATA_OUT_Y_H = 3,
25 DATA_OUT_Z_L = 4,
26 DATA_OUT_Z_H = 5,
27 STATUS = 6,
28 TOUT_L = 7,
29 TOUT_H = 8,
30 CONTROL1 = 9,
31 CONTROL2 = 10,
32 PERIOD = 11,
33 CHIP_ID = 13,
34}
35
36const STATUS_OVL: u8 = 0b010;
37const STATUS_DRDY: u8 = 0b001;
38
39const MODE_CONTINUOUS: u8 = 0b01;
40
41const CTRL2_SOFT_RST: u8 = 1 << 7;
42const CTRL2_ROL_PNT: u8 = 1 << 6;
43const CTRL2_INT_ENB: u8 = 1 << 0;
44
45#[repr(u8)]
47pub enum OutputDataRate {
48 Rate10Hz = 0,
50 Rate50Hz = 0b0100,
52 Rate100Hz = 0b1000,
54 Rate200Hz = 0b1100,
56}
57
58#[repr(u8)]
61pub enum OversampleRate {
62 Rate64 = 3 << 6,
64 Rate128 = 1 << 7,
66 Rate256 = 1 << 6,
68 Rate512 = 0,
70}
71
72#[repr(u8)]
74pub enum FieldRange {
75 Range2Gauss = 0,
77 Range8Gauss = 1 << 3,
79}
80
81#[derive(Debug, Copy, Clone)]
83pub enum Error<E> {
84 InvalidDevice(u8),
86 NotReady,
88 Overflow,
90 BusError(E),
92}
93
94impl<E> core::convert::From<E> for Error<E> {
95 fn from(e: E) -> Self {
96 Error::BusError(e)
97 }
98}
99
100pub struct QMC5883L<I2C> {
102 i2c: I2C,
103}
104
105impl<I2C, E> QMC5883L<I2C>
106where
107 I2C: WriteRead<Error = E> + Write<Error = E>,
108{
109 pub fn new(i2c: I2C) -> Result<Self, Error<E>> {
111 let mut dev = QMC5883L { i2c: i2c };
112 let id = dev.read_u8(Register::CHIP_ID)?;
113 if id != 0xff {
114 return Err(Error::InvalidDevice(id));
115 }
116 dev.reset()?;
117 Ok(dev)
118 }
119
120 pub fn reset(&mut self) -> Result<(), E> {
122 self.write_u8(Register::CONTROL2, CTRL2_SOFT_RST)?;
123 self.write_u8(Register::CONTROL2, CTRL2_ROL_PNT | CTRL2_INT_ENB)?;
124 self.write_u8(Register::PERIOD, 1)
125 }
126
127 pub fn set_field_range(&mut self, rng: FieldRange) -> Result<(), E> {
129 let ctrl1 = self.read_u8(Register::CONTROL1)?;
130 let v = (ctrl1 & !(FieldRange::Range8Gauss as u8)) | (rng as u8);
131 self.write_u8(Register::CONTROL1, v)
132 }
133
134 pub fn set_oversample(&mut self, osr: OversampleRate) -> Result<(), E> {
136 let ctrl1 = self.read_u8(Register::CONTROL1)?;
137 let v = (ctrl1 & !(OversampleRate::Rate64 as u8)) | (osr as u8);
138 self.write_u8(Register::CONTROL1, v)
139 }
140
141 pub fn set_output_data_rate(&mut self, odr: OutputDataRate) -> Result<(), E> {
143 let ctrl1 = self.read_u8(Register::CONTROL1)?;
144 let v = (ctrl1 & !(OutputDataRate::Rate200Hz as u8)) | (odr as u8);
145 self.write_u8(Register::CONTROL1, v)
146 }
147
148 pub fn continuous(&mut self) -> Result<(), E> {
150 let ctrl1 = self.read_u8(Register::CONTROL1)?;
151 self.write_u8(Register::CONTROL1, ctrl1 | MODE_CONTINUOUS)
152 }
153
154 pub fn standby(&mut self) -> Result<(), E> {
156 let ctrl1 = self.read_u8(Register::CONTROL1)?;
157 self.write_u8(Register::CONTROL1, ctrl1 & !MODE_CONTINUOUS)
158 }
159
160 pub fn enable_interrupt(&mut self) -> Result<(), E> {
162 self.write_u8(Register::CONTROL2, CTRL2_ROL_PNT)
163 }
164
165 pub fn disable_interrupt(&mut self) -> Result<(), E> {
167 self.write_u8(Register::CONTROL2, CTRL2_ROL_PNT | CTRL2_INT_ENB)
168 }
169
170 pub fn temp(&mut self) -> Result<i16, E> {
172 let temp_l = self.read_u8(Register::TOUT_L)? as i16;
173 let temp_h = self.read_u8(Register::TOUT_H)? as i16;
174 Ok((temp_h << 8) | temp_l)
175 }
176
177 pub fn mag(&mut self) -> Result<(i16, i16, i16), Error<E>> {
179 let buf: &mut [u8; 7] = &mut [0; 7];
180 self.i2c
181 .write_read(I2C_ADDRESS, &[Register::STATUS as u8], buf)?;
182 let status = buf[0];
183 if (status & STATUS_DRDY) == 0 {
184 return Err(Error::NotReady);
185 } else if (status & STATUS_OVL) != 0 {
186 return Err(Error::Overflow);
187 }
188 let x = ((buf[2] as i16) << 8) | (buf[1] as i16);
189 let y = ((buf[4] as i16) << 8) | (buf[3] as i16);
190 let z = ((buf[6] as i16) << 8) | (buf[5] as i16);
191 Ok((x, y, z))
192 }
193
194 fn read_u8(&mut self, reg: Register) -> Result<u8, E> {
195 let buf: &mut [u8; 1] = &mut [0];
196 self.i2c.write_read(I2C_ADDRESS, &[reg as u8], buf)?;
197 Ok(buf[0])
198 }
199
200 fn write_u8(&mut self, reg: Register, v: u8) -> Result<(), E> {
201 self.i2c.write(I2C_ADDRESS, &[reg as u8, v])
202 }
203}