embedded_devices/devices/analog_devices/max31865/
mod.rs1use embedded_devices_derive::forward_register_fns;
59use embedded_devices_derive::sensor;
60use embedded_interfaces::TransportError;
61use registers::{
62 Configuration, ConversionMode, FaultDetectionCycle, FaultThresholdHigh, FaultThresholdLow, FilterMode, WiringMode,
63};
64use uom::si::f64::ThermodynamicTemperature;
65use uom::si::thermodynamic_temperature::degree_celsius;
66
67use crate::utils::callendar_van_dusen;
68
69pub mod registers;
70
71#[cfg_attr(feature = "defmt", derive(defmt::Format))]
72#[derive(Debug, thiserror::Error)]
73pub enum FaultDetectionError<BusError> {
74 #[error("transport error")]
76 Transport(#[from] TransportError<(), BusError>),
77 #[error("fault detection timeout")]
79 Timeout,
80 #[error("fault detected")]
82 FaultDetected,
83}
84
85#[cfg_attr(feature = "defmt", derive(defmt::Format))]
86#[derive(Debug, thiserror::Error)]
87pub enum MeasurementError<BusError> {
88 #[error("transport error")]
90 Transport(#[from] TransportError<(), BusError>),
91 #[error("fault detected")]
93 FaultDetected,
94}
95
96#[derive(Debug, embedded_devices_derive::Measurement)]
98pub struct Measurement {
99 #[measurement(Temperature)]
101 pub temperature: ThermodynamicTemperature,
102}
103
104#[maybe_async_cfg::maybe(
109 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
110 sync(feature = "sync"),
111 async(feature = "async")
112)]
113pub struct MAX31865<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> {
114 delay: D,
116 interface: I,
118 reference_resistor_ratio: f64,
123}
124
125pub trait MAX31865Register {}
126
127#[maybe_async_cfg::maybe(
128 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), SpiDevice),
129 sync(feature = "sync"),
130 async(feature = "async")
131)]
132impl<D, I> MAX31865<D, embedded_interfaces::spi::SpiDevice<I>>
133where
134 I: hal::spi::r#SpiDevice,
135 D: hal::delay::DelayNs,
136{
137 #[inline]
147 pub fn new_spi(delay: D, interface: I, reference_resistor_ratio: f64) -> Self {
148 Self {
149 delay,
150 interface: embedded_interfaces::spi::SpiDevice::new(interface),
151 reference_resistor_ratio,
152 }
153 }
154}
155
156#[forward_register_fns]
157#[sensor(Temperature)]
158#[maybe_async_cfg::maybe(
159 idents(hal(sync = "embedded_hal", async = "embedded_hal_async"), RegisterInterface),
160 sync(feature = "sync"),
161 async(feature = "async")
162)]
163impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> MAX31865<D, I> {
164 pub async fn init(
168 &mut self,
169 wiring_mode: WiringMode,
170 filter_mode: FilterMode,
171 ) -> Result<(), FaultDetectionError<I::BusError>> {
172 self.write_register(
174 Configuration::default()
175 .with_wiring_mode(wiring_mode)
176 .with_filter_mode(filter_mode),
177 )
178 .await?;
179
180 self.write_register(FaultThresholdLow::default().with_resistance_ratio(0))
181 .await?;
182 self.write_register(FaultThresholdHigh::default().with_resistance_ratio(0x7fff))
183 .await?;
184
185 self.detect_faults().await
186 }
187
188 pub async fn detect_faults(&mut self) -> Result<(), FaultDetectionError<I::BusError>> {
190 let reg_conf = self.read_register::<Configuration>().await?;
191
192 self.write_register(
196 reg_conf
197 .with_enable_bias_voltage(true)
198 .with_conversion_mode(ConversionMode::NormallyOff)
199 .with_clear_fault_status(false)
200 .with_fault_detection_cycle(FaultDetectionCycle::Automatic),
201 )
202 .await?;
203
204 self.delay.delay_us(550).await;
208 const TRIES: u8 = 5;
209 for _ in 0..TRIES {
210 let cycle = self
211 .read_register::<Configuration>()
212 .await?
213 .read_fault_detection_cycle();
214
215 if cycle == FaultDetectionCycle::Finished {
217 self.write_register(reg_conf.with_enable_bias_voltage(false)).await?;
219
220 let has_fault = self.read_register::<registers::Resistance>().await?.read_fault();
221 if has_fault {
222 return Err(FaultDetectionError::FaultDetected);
224 } else {
225 return Ok(());
227 }
228 }
229
230 self.delay.delay_us(100).await;
231 }
232
233 self.write_register(reg_conf.with_enable_bias_voltage(false)).await?;
235
236 Err(FaultDetectionError::Timeout)
237 }
238
239 pub fn temperature_to_raw_resistance_ratio(&mut self, temperature: ThermodynamicTemperature) -> u16 {
246 let temperature = temperature.get::<degree_celsius>() as f32;
247 let resistance = callendar_van_dusen::temperature_to_resistance_r100(temperature);
248 let ratio = resistance / (100.0 * self.reference_resistor_ratio) as f32;
249 if ratio >= 1.0 {
250 (1 << 15) - 1
251 } else {
252 (ratio * (1 << 15) as f32) as u16
253 }
254 }
255
256 pub fn raw_resistance_ratio_to_temperature(&mut self, raw_resistance: u16) -> ThermodynamicTemperature {
259 let resistance = (100.0 * raw_resistance as f32 * self.reference_resistor_ratio as f32) / ((1 << 15) as f32);
263 let temperature = callendar_van_dusen::resistance_to_temperature_r100(resistance);
264 ThermodynamicTemperature::new::<degree_celsius>(temperature as f64)
265 }
266
267 pub async fn read_temperature(&mut self) -> Result<ThermodynamicTemperature, MeasurementError<I::BusError>> {
272 let resistance = self.read_register::<registers::Resistance>().await?;
273
274 if resistance.read_fault() {
275 return Err(MeasurementError::FaultDetected);
276 }
277
278 Ok(self.raw_resistance_ratio_to_temperature(resistance.read_resistance_ratio()))
279 }
280}
281
282#[maybe_async_cfg::maybe(
283 idents(
284 hal(sync = "embedded_hal", async = "embedded_hal_async"),
285 RegisterInterface,
286 OneshotSensor
287 ),
288 sync(feature = "sync"),
289 async(feature = "async")
290)]
291impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::OneshotSensor
292 for MAX31865<D, I>
293{
294 type Error = MeasurementError<I::BusError>;
295 type Measurement = Measurement;
296
297 async fn measure(&mut self) -> Result<Self::Measurement, Self::Error> {
301 let reg_conf = self
302 .read_register::<Configuration>()
303 .await?
304 .with_enable_bias_voltage(false)
305 .with_conversion_mode(ConversionMode::NormallyOff)
306 .with_oneshot(false);
307
308 self.write_register(reg_conf.with_enable_bias_voltage(true)).await?;
312 self.delay.delay_us(2000).await;
313
314 self.write_register(reg_conf.with_enable_bias_voltage(true).with_oneshot(true))
316 .await?;
317
318 let measurement_time_us = match reg_conf.read_filter_mode() {
320 FilterMode::F_60Hz => 52000,
321 FilterMode::F_50Hz => 62500,
322 };
323 self.delay.delay_us(2000 + measurement_time_us).await;
324
325 self.write_register(reg_conf).await?;
327
328 Ok(Measurement {
330 temperature: self.read_temperature().await?,
331 })
332 }
333}
334
335#[maybe_async_cfg::maybe(
336 idents(
337 hal(sync = "embedded_hal", async = "embedded_hal_async"),
338 RegisterInterface,
339 ContinuousSensor
340 ),
341 sync(feature = "sync"),
342 async(feature = "async")
343)]
344impl<D: hal::delay::DelayNs, I: embedded_interfaces::registers::RegisterInterface> crate::sensor::ContinuousSensor
345 for MAX31865<D, I>
346{
347 type Error = MeasurementError<I::BusError>;
348 type Measurement = Measurement;
349
350 async fn start_measuring(&mut self) -> Result<(), Self::Error> {
352 let reg_conf = self.read_register::<Configuration>().await?;
353
354 self.write_register(
356 reg_conf
357 .with_enable_bias_voltage(true)
358 .with_conversion_mode(ConversionMode::Automatic)
359 .with_oneshot(false),
360 )
361 .await?;
362
363 Ok(())
364 }
365
366 async fn stop_measuring(&mut self) -> Result<(), Self::Error> {
368 let reg_conf = self.read_register::<Configuration>().await?;
369
370 self.write_register(
372 reg_conf
373 .with_enable_bias_voltage(false)
374 .with_conversion_mode(ConversionMode::NormallyOff)
375 .with_oneshot(false),
376 )
377 .await?;
378
379 Ok(())
380 }
381
382 async fn measurement_interval_us(&mut self) -> Result<u32, Self::Error> {
384 let reg_conf = self.read_register::<Configuration>().await?;
385 let measurement_time_us = match reg_conf.read_filter_mode() {
386 FilterMode::F_60Hz => 1_000_000 / 60,
387 FilterMode::F_50Hz => 1_000_000 / 50,
388 };
389
390 Ok(measurement_time_us)
391 }
392
393 async fn current_measurement(&mut self) -> Result<Option<Self::Measurement>, Self::Error> {
395 Ok(Some(Measurement {
396 temperature: self.read_temperature().await?,
397 }))
398 }
399
400 async fn is_measurement_ready(&mut self) -> Result<bool, Self::Error> {
402 Ok(true)
404 }
405
406 async fn next_measurement(&mut self) -> Result<Self::Measurement, Self::Error> {
408 let interval = self.measurement_interval_us().await?;
409 self.delay.delay_us(interval).await;
410 self.current_measurement().await?.ok_or_else(|| {
411 MeasurementError::Transport(TransportError::Unexpected(
412 "measurement was not ready even though we expected it to be",
413 ))
414 })
415 }
416}