1#![no_std]
2
3use bitflags::bitflags;
10use core::fmt::Debug;
11use core::marker::PhantomData;
12use maybe_async_cfg::maybe;
13
14#[cfg(feature = "async")]
15use embedded_hal_async::{delay::DelayNs, i2c, i2c::Error as I2cError};
16
17#[cfg(feature = "blocking")]
18use embedded_hal::{delay::DelayNs, i2c, i2c::Error as I2cError};
19
20#[cfg(feature = "std")]
21extern crate std;
22
23#[cfg(feature = "defmt")]
24#[allow(unused_imports)]
25#[macro_use]
26extern crate defmt;
27
28pub struct Tlv493d<I2c, I2cErr, Delay> {
29 i2c: I2c,
30 delay: Delay,
31 addr: u8,
32 initial: [u8; 10],
33 last_frm: Option<u8>,
34 _e_i2c: PhantomData<I2cErr>,
35}
36
37pub const ADDRESS_BASE: u8 = 0b1011110;
40
41#[derive(Debug, PartialEq, Clone)]
42#[cfg_attr(feature = "defmt", derive(defmt::Format))]
43pub enum ReadRegisters {
45 Rx = 0x00, By = 0x01, Bz = 0x02, Temp = 0x03, Bx2 = 0x04, Bz2 = 0x05, Temp2 = 0x06, FactSet1 = 0x07,
54 FactSet2 = 0x08,
55 FactSet3 = 0x09,
56}
57
58#[derive(Debug, PartialEq, Clone)]
59#[cfg_attr(feature = "defmt", derive(defmt::Format))]
60pub enum WriteRegisters {
62 Res = 0x00, Mode1 = 0x01, Res2 = 0x02, Mode2 = 0x03, }
67
68#[derive(Debug, PartialEq, Clone)]
70#[cfg_attr(feature = "defmt", derive(defmt::Format))]
71pub struct Values {
72 pub x: f32, pub y: f32, pub z: f32, pub temp: f32, }
77
78#[derive(Debug, PartialEq, Clone)]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82pub enum Mode {
83 Disabled, Master, Fast, LowPower, UltraLowPower, }
89
90bitflags! {
91 pub struct Mode1: u8 {
93 const PARITY = 0b1000_0000; const I2C_ADDR_1 = 0b0100_0000; const I2C_ADDR_0 = 0b0010_0000; const IRQ_EN = 0b0000_0100; const FAST = 0b0000_0010; const LOW = 0b0000_0001; }
100}
101
102bitflags! {
103 pub struct Mode2: u8 {
105 const TEMP_DISABLE = 0b1000_0000; const LOW_POW_PERIOD = 0b0100_0000; const PARITY_TEST_EN = 0b0010_0000; }
109}
110
111#[derive(Debug)]
113#[cfg_attr(feature = "defmt", derive(defmt::Format))]
114#[cfg_attr(feature = "std", derive(thiserror::Error))]
115pub enum Error<I2cErr: I2cError + Debug> {
116 #[cfg_attr(
118 feature = "std",
119 error("No device found with specified i2c bus and address")
120 )]
121 NoDevice,
122
123 #[cfg_attr(feature = "std", error("Device ADC lockup, reset required"))]
125 AdcLockup,
126
127 #[cfg_attr(feature = "std", error("I2C device error: {0:?}"))]
129 I2c(I2cErr),
130}
131
132maybe_async_cfg::content! {
133 impl<I2c, I2cErr, Delay> Tlv493d<I2c, I2cErr, Delay>
134 where
135 I2c: i2c::I2c,
136 I2cErr: I2cError + Debug,
137 Error<I2cErr>: From<Error<<I2c as i2c::ErrorType>::Error>>,
138 Delay: DelayNs,
139 {
140 #[maybe(
142 sync(feature = "blocking"),
143 async(feature = "async")
144 )]
145 pub async fn new(
146 i2c: I2c,
147 delay: Delay,
148 addr: u8,
149 mode: Mode,
150 ) -> Result<Self, (Error<I2cErr>, I2c)> {
151 #[cfg(feature = "defmt")]
152 debug!("New Tlv493d with address: 0x{:02x}", addr);
153
154 let mut s = Self {
156 i2c,
157 delay,
158 addr,
159 initial: [0u8; 10],
160 last_frm: None,
161 _e_i2c: PhantomData,
162 };
163
164 #[cfg(feature = "async")]
166 if let Err(err) = s.configure_async(mode, true).await {
167 return Err((err, s.i2c));
168 };
169 #[cfg(feature = "blocking")]
170 if let Err(err) = s.configure_sync(mode, true) {
171 return Err((err, s.i2c));
172 };
173
174 Ok(s)
176 }
177
178 pub fn into_i2c(self) -> I2c {
179 self.i2c
180 }
181
182 #[maybe(
184 sync(feature = "blocking"),
185 async(feature = "async")
186 )]
187 pub async fn configure(&mut self, mode: Mode, reset: bool) -> Result<(), Error<I2cErr>> {
188 if reset {
192 #[cfg(feature = "defmt")]
193 debug!("Resetting device");
194
195 #[cfg(feature = "async")]
197 self.delay.delay_ms(1).await;
198 #[cfg(feature = "blocking")]
199 self.delay.delay_ms(1);
200
201 #[cfg(feature = "async")]
203 self.i2c.write(0xff, &[]).await
204 .map_err(Error::I2c).ok();
205 #[cfg(feature = "blocking")]
206 self.i2c.write(0xff, &[])
207 .map_err(Error::I2c).ok();
208
209 #[cfg(feature = "defmt")]
210 debug!("Setting device address");
211
212 #[cfg(feature = "async")]
214 self.i2c.write(0x00, &[0xff]).await
215 .map_err(Error::I2c).ok();
216 #[cfg(feature = "blocking")]
217 self.i2c.write(0x00, &[0xff])
218 .map_err(Error::I2c).ok();
219
220 #[cfg(feature = "defmt")]
221 debug!("Read device initial state");
222
223 #[cfg(feature = "async")]
225 self.i2c.read(self.addr, &mut self.initial[..]).await
226 .map_err(Error::I2c)?;
227 #[cfg(feature = "blocking")]
228 self.i2c.read(self.addr, &mut self.initial[..])
229 .map_err(Error::I2c)?;
230
231 #[cfg(feature = "defmt")]
232 debug!("Initial state: {:02x}", self.initial);
233 }
234
235 let Some(mut mod1) = Mode1::from_bits(self.initial[7]) else {
237 panic!("implementation error");
238 };
239 let Some(mod2) = Mode2::from_bits(self.initial[9]) else {
240 panic!("implementation error");
241 };
242
243 mod1.remove(Mode1::PARITY);
245 mod1.remove(Mode1::FAST | Mode1::LOW);
246
247 match mode {
248 Mode::Disabled => (),
249 Mode::Master => mod1 |= Mode1::FAST | Mode1::LOW,
250 Mode::Fast => mod1 |= Mode1::FAST | Mode1::IRQ_EN,
251 Mode::LowPower => mod1 |= Mode1::LOW | Mode1::IRQ_EN,
252 Mode::UltraLowPower => mod1 |= Mode1::IRQ_EN,
253 }
254
255 let mut cfg = [0x00, mod1.bits(), self.initial[8], mod2.bits()];
256
257 self.initial[7] = mod1.bits();
258 self.initial[9] = mod2.bits();
259
260 let mut parity = 0;
261 for v in &cfg {
262 for i in 0..8 {
263 if v & (1 << i) != 0 {
264 parity += 1;
265 }
266 }
267 }
268 if parity % 2 == 0 {
269 mod1 |= Mode1::PARITY;
270 cfg[1] = mod1.bits();
271 }
272
273 #[cfg(feature = "async")]
274 self.i2c.write(self.addr, &cfg).await
275 .map_err(Error::I2c)?;
276 #[cfg(feature = "blocking")]
277 self.i2c.write(self.addr, &cfg)
278 .map_err(Error::I2c)?;
279
280 Ok(())
281 }
282
283 #[maybe(
285 sync(feature = "blocking"),
286 async(feature = "async")
287 )]
288 pub async fn read_raw(&mut self) -> Result<[i16; 4], Error<I2cErr>> {
289 let mut v = [0i16; 4];
290
291 let mut b = [0u8; 7];
293 #[cfg(feature = "async")]
294 self.i2c.read(self.addr, &mut b[..]).await
295 .map_err(Error::I2c)?;
296 #[cfg(feature = "blocking")]
297 self.i2c.read(self.addr, &mut b[..])
298 .map_err(Error::I2c)?;
299
300 let frm = b[3] & 0b0000_1100;
302 if let Some(last_frm) = self.last_frm
303 && last_frm == frm
304 {
305 return Err(Error::AdcLockup);
306 }
307 self.last_frm = Some(frm);
308
309 v[0] = (b[0] as i8 as i16) << 4 | ((b[4] & 0xf0) >> 4) as i16;
312 v[1] = (b[1] as i8 as i16) << 4 | (b[4] & 0x0f) as i16;
313 v[2] = (b[2] as i8 as i16) << 4 | (b[5] & 0x0f) as i16;
314 v[3] = (b[3] as i8 as i16 & 0xf0) << 4 | (b[6] as i16 & 0xff);
315
316 #[cfg(feature = "defmt")]
317 debug!("Read data {:02x} values: {:04x}", b, v);
318
319 Ok(v)
320 }
321
322 #[maybe(
324 sync(feature = "blocking"),
325 async(feature = "async")
326 )]
327 pub async fn read(&mut self) -> Result<Values, Error<I2cErr>> {
328 #[cfg(feature = "async")]
329 let raw = self.read_raw_async().await?;
330 #[cfg(feature = "blocking")]
331 let raw = self.read_raw_sync()?;
332
333 Ok(Values {
334 x: raw[0] as f32 * 0.098f32,
335 y: raw[1] as f32 * 0.098f32,
336 z: raw[2] as f32 * 0.098f32,
337 temp: (raw[3] - 340) as f32 * 1.1f32 + 24.2f32,
338 })
339 }
340
341 #[cfg(feature = "math")]
342 #[maybe(
343 sync(feature = "blocking"),
344 async(feature = "async")
345 )]
346 pub async fn read_angle_f32(&mut self) -> Result<f32, Error<I2cErr>> {
347 #[cfg(feature = "async")]
349 let v = self.read_async().await?;
350 #[cfg(feature = "blocking")]
351 let v = self.read_sync()?;
352
353 Ok(libm::Libm::<f32>::atan2(v.x, v.y))
355 }
356 }
357}