use core::fmt; use fugit::MegahertzU32; use num_traits::float::Float; use serde::{Deserialize, Serialize}; use stm32f4xx_hal::spi; mod checksum; pub mod regs; pub use checksum::ChecksumMode; mod adc; pub use adc::*; /// SPI Mode 3 pub const SPI_MODE: spi::Mode = spi::Mode { polarity: spi::Polarity::IdleHigh, phase: spi::Phase::CaptureOnSecondTransition, }; /// AD7172 Max Frequency: 40MHz | SPI3 Max Frequency: 21MHz pub const SPI_CLOCK_MHZ: MegahertzU32 = MegahertzU32::from_raw(21); pub const MAX_VALUE: u32 = 0xFF_FFFF; #[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum Mode { ContinuousConversion = 0b000, SingleConversion = 0b001, Standby = 0b010, PowerDown = 0b011, InternalOffsetCalibration = 0b100, Invalid, SystemOffsetCalibration = 0b110, SystemGainCalibration = 0b111, } impl From for Mode { fn from(x: u8) -> Self { use Mode::*; match x { 0b000 => ContinuousConversion, 0b001 => SingleConversion, 0b010 => Standby, 0b011 => PowerDown, 0b100 => InternalOffsetCalibration, 0b110 => SystemOffsetCalibration, 0b111 => SystemGainCalibration, _ => Invalid, } } } #[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum Input { Ain0 = 0, Ain1 = 1, Ain2 = 2, Ain3 = 3, Ain4 = 4, TemperaturePos = 17, TemperatureNeg = 18, AnalogSupplyPos = 19, AnalogSupplyNeg = 20, RefPos = 21, RefNeg = 22, Invalid = 0b11111, } impl From for Input { fn from(x: u8) -> Self { match x { 0 => Input::Ain0, 1 => Input::Ain1, 2 => Input::Ain2, 3 => Input::Ain3, 4 => Input::Ain4, 17 => Input::TemperaturePos, 18 => Input::TemperatureNeg, 19 => Input::AnalogSupplyPos, 20 => Input::AnalogSupplyNeg, 21 => Input::RefPos, 22 => Input::RefNeg, _ => Input::Invalid, } } } impl fmt::Display for Input { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { use Input::*; match self { Ain0 => "ain0", Ain1 => "ain1", Ain2 => "ain2", Ain3 => "ain3", Ain4 => "ain4", TemperaturePos => "temperature+", TemperatureNeg => "temperature-", AnalogSupplyPos => "analogsupply+", AnalogSupplyNeg => "analogsupply-", RefPos => "ref+", RefNeg => "ref-", _ => "", } .fmt(fmt) } } /// Reference source for ADC conversion #[repr(u8)] pub enum RefSource { /// External reference External = 0b00, /// Internal 2.5V reference Internal = 0b10, /// AVDD1 − AVSS Avdd1MinusAvss = 0b11, Invalid = 0b01, } impl From for RefSource { fn from(x: u8) -> Self { match x { 0 => RefSource::External, 1 => RefSource::Internal, 2 => RefSource::Avdd1MinusAvss, _ => RefSource::Invalid, } } } impl fmt::Display for RefSource { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { use RefSource::*; match self { External => "external", Internal => "internal", Avdd1MinusAvss => "avdd1-avss", _ => "", } .fmt(fmt) } } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[repr(u8)] pub enum PostFilter { /// 27 SPS, 47 dB rejection, 36.7 ms settling F27SPS = 0b010, /// 21.25 SPS, 62 dB rejection, 40 ms settling F21SPS = 0b011, /// 20 SPS, 86 dB rejection, 50 ms settling F20SPS = 0b101, /// 16.67 SPS, 92 dB rejection, 60 ms settling F16SPS = 0b110, Invalid = 0b111, } impl PostFilter { pub const VALID_VALUES: &'static [Self] = &[ PostFilter::F27SPS, PostFilter::F21SPS, PostFilter::F20SPS, PostFilter::F16SPS, ]; pub fn closest(rate: f32) -> Option { let mut best: Option<(f32, Self)> = None; for value in Self::VALID_VALUES { let error = (rate - value.output_rate().unwrap()).abs(); let better = best.map(|(best_error, _)| error < best_error).unwrap_or(true); if better { best = Some((error, *value)); } } best.map(|(_, best)| best) } /// Samples per Second pub fn output_rate(&self) -> Option { match self { PostFilter::F27SPS => Some(27.0), PostFilter::F21SPS => Some(21.25), PostFilter::F20SPS => Some(20.0), PostFilter::F16SPS => Some(16.67), PostFilter::Invalid => None, } } } impl From for PostFilter { fn from(x: u8) -> Self { match x { 0b010 => PostFilter::F27SPS, 0b011 => PostFilter::F21SPS, 0b101 => PostFilter::F20SPS, 0b110 => PostFilter::F16SPS, _ => PostFilter::Invalid, } } } #[derive(Deserialize, Serialize, Copy, Clone, Debug, Default)] pub enum FilterType { #[default] Sinc5Sinc1With50hz60HzRejection, Sinc5Sinc1, Sinc3, Sinc3WithFineODR, } #[derive(PartialEq)] #[repr(u8)] pub enum DigitalFilterOrder { Sinc5Sinc1 = 0b00, Sinc3 = 0b11, Invalid = 0b10, } impl From for DigitalFilterOrder { fn from(x: u8) -> Self { match x { 0b00 => DigitalFilterOrder::Sinc5Sinc1, 0b11 => DigitalFilterOrder::Sinc3, _ => DigitalFilterOrder::Invalid, } } } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[allow(unused)] #[repr(u8)] pub enum SingleChODR { F31250_0SPS = 0b00101, F15625_0SPS = 0b00110, F10417_0SPS = 0b00111, F5208_0SPS = 0b01000, F2597_0SPS = 0b01001, F1007_0SPS = 0b01010, F503_8SPS = 0b01011, F381_0SPS = 0b01100, F200_3SPS = 0b01101, F100_2SPS = 0b01110, F59_52SPS = 0b01111, F49_68SPS = 0b10000, F20_01SPS = 0b10001, F16_63SPS = 0b10010, F10_0SPS = 0b10011, F5_0SPS = 0b10100, F2_5SPS = 0b10101, F1_25SPS = 0b10110, Invalid = 0b11111, } impl SingleChODR { pub const VALID_VALUES: &'static [Self] = &[ SingleChODR::F31250_0SPS, SingleChODR::F15625_0SPS, SingleChODR::F10417_0SPS, SingleChODR::F5208_0SPS, SingleChODR::F2597_0SPS, SingleChODR::F1007_0SPS, SingleChODR::F503_8SPS, SingleChODR::F381_0SPS, SingleChODR::F200_3SPS, SingleChODR::F100_2SPS, SingleChODR::F59_52SPS, SingleChODR::F49_68SPS, SingleChODR::F20_01SPS, SingleChODR::F16_63SPS, SingleChODR::F10_0SPS, SingleChODR::F5_0SPS, SingleChODR::F2_5SPS, SingleChODR::F1_25SPS, ]; pub fn closest(rate: f32) -> Option { let mut best: Option<(f32, Self)> = None; for value in Self::VALID_VALUES { let error = (rate - value.output_rate().unwrap()).abs(); let better = best.map(|(best_error, _)| error < best_error).unwrap_or(true); if better { best = Some((error, *value)); } } best.map(|(_, best)| best) } /// Samples per Second pub fn output_rate(&self) -> Option { match self { SingleChODR::F31250_0SPS => Some(31250.0), SingleChODR::F15625_0SPS => Some(15625.0), SingleChODR::F10417_0SPS => Some(10417.0), SingleChODR::F5208_0SPS => Some(5208.0), SingleChODR::F2597_0SPS => Some(2597.0), SingleChODR::F1007_0SPS => Some(1007.0), SingleChODR::F503_8SPS => Some(503.8), SingleChODR::F381_0SPS => Some(381.0), SingleChODR::F200_3SPS => Some(200.3), SingleChODR::F100_2SPS => Some(100.2), SingleChODR::F59_52SPS => Some(59.52), SingleChODR::F49_68SPS => Some(49.68), SingleChODR::F20_01SPS => Some(20.01), SingleChODR::F16_63SPS => Some(16.63), SingleChODR::F10_0SPS => Some(10.0), SingleChODR::F5_0SPS => Some(5.0), SingleChODR::F2_5SPS => Some(2.5), SingleChODR::F1_25SPS => Some(1.25), SingleChODR::Invalid => None, } } } impl From for SingleChODR { fn from(x: u8) -> Self { match x { 0b00101 => SingleChODR::F31250_0SPS, 0b00110 => SingleChODR::F15625_0SPS, 0b00111 => SingleChODR::F10417_0SPS, 0b01000 => SingleChODR::F5208_0SPS, 0b01001 => SingleChODR::F2597_0SPS, 0b01010 => SingleChODR::F1007_0SPS, 0b01011 => SingleChODR::F503_8SPS, 0b01100 => SingleChODR::F381_0SPS, 0b01101 => SingleChODR::F200_3SPS, 0b01110 => SingleChODR::F100_2SPS, 0b01111 => SingleChODR::F59_52SPS, 0b10000 => SingleChODR::F49_68SPS, 0b10001 => SingleChODR::F20_01SPS, 0b10010 => SingleChODR::F16_63SPS, 0b10011 => SingleChODR::F10_0SPS, 0b10100 => SingleChODR::F5_0SPS, 0b10101 => SingleChODR::F2_5SPS, 0b10110 => SingleChODR::F1_25SPS, _ => SingleChODR::Invalid, } } } pub fn sinc3_fine_odr_output_rate(odr: u16) -> f32 { 1.0 * 1e6 / (32.0 * odr as f32) } pub fn sinc3_fine_odr_closest(rate: f32) -> u16 { (1.0e6 / (32.0 * rate)).max(1.0 as f32).min(0x7FFF as f32) as u16 }