ad7172: Add filter configs for single channel mode
This commit is contained in:
parent
18dd0a7963
commit
a2bb390ae2
|
@ -15,9 +15,7 @@ use uom::si::{
|
|||
electric_potential::volt,
|
||||
};
|
||||
use super::{
|
||||
regs::{self, Register, RegisterData},
|
||||
checksum::{ChecksumMode, Checksum},
|
||||
Mode, Input, RefSource, PostFilter, DigitalFilterOrder,
|
||||
checksum::{Checksum, ChecksumMode}, regs::{self, Register, RegisterData}, sinc3_fine_odr_closest, sinc3_fine_odr_output_rate, DigitalFilterOrder, FilterType, Input, Mode, PostFilter, RefSource, SingleChODR
|
||||
};
|
||||
|
||||
/// AD7172-2 implementation
|
||||
|
@ -57,6 +55,7 @@ impl<SPI: Transfer<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS>
|
|||
|
||||
let mut adc_mode = <regs::AdcMode as Register>::Data::empty();
|
||||
adc_mode.set_ref_en(true);
|
||||
adc_mode.set_sing_cyc(false);
|
||||
adc_mode.set_mode(Mode::Standby);
|
||||
adc.write_reg(®s::AdcMode, &mut adc_mode)?;
|
||||
|
||||
|
@ -96,13 +95,7 @@ impl<SPI: Transfer<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS>
|
|||
data.set_ainbuf_neg(true);
|
||||
data.set_ref_sel(RefSource::External);
|
||||
})?;
|
||||
self.update_reg(®s::FiltCon { index }, |data| {
|
||||
data.set_enh_filt_en(true);
|
||||
data.set_enh_filt(PostFilter::F16SPS);
|
||||
data.set_order(DigitalFilterOrder::Sinc5Sinc1);
|
||||
// output data rate: 10 Hz
|
||||
data.set_odr(0b10011);
|
||||
})?;
|
||||
self.set_sinc5_sinc1_with_50hz_60hz_rejection(index, PostFilter::F16SPS)?;
|
||||
self.update_reg(®s::Channel { index }, |data| {
|
||||
data.set_setup(index);
|
||||
data.set_enabled(true);
|
||||
|
@ -122,35 +115,85 @@ impl<SPI: Transfer<u8, Error = E>, NSS: OutputPin, E: fmt::Debug> Adc<SPI, NSS>
|
|||
pub fn start_continuous_conversion(&mut self) -> Result<(), SPI::Error> {
|
||||
let mut adc_mode = <regs::AdcMode as Register>::Data::empty();
|
||||
adc_mode.set_ref_en(true);
|
||||
// Set SING_CYC = 0 to maximize sampling rate with lowest noise for single channel of temperature measurement
|
||||
adc_mode.set_sing_cyc(false);
|
||||
adc_mode.set_mode(Mode::ContinuousConversion);
|
||||
self.write_reg(®s::AdcMode, &mut adc_mode)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_postfilter(&mut self, index: u8) -> Result<Option<PostFilter>, SPI::Error> {
|
||||
/// Rate is only valid with single channel enabled
|
||||
pub fn get_filter_type_and_rate(&mut self, index: u8) -> Result<(FilterType, f32), SPI::Error> {
|
||||
let mut filter_type: FilterType = FilterType::Sinc5Sinc1With50hz60HzRejection;
|
||||
let mut rate: f32 = -1.0;
|
||||
self.read_reg(®s::FiltCon { index })
|
||||
.map(|data| {
|
||||
if data.enh_filt_en() {
|
||||
Some(data.enh_filt())
|
||||
} else {
|
||||
None
|
||||
if data.sinc3_map() {
|
||||
filter_type = FilterType::Sinc3WithFineODR;
|
||||
let odr : u16 = (data.sinc3_map_fine_odr_msb() as u16) << 8 | data.sinc3_map_fine_odr_lsb() as u16;
|
||||
rate = sinc3_fine_odr_output_rate(odr);
|
||||
} else if data.enh_filt_en() {
|
||||
filter_type = FilterType::Sinc5Sinc1With50hz60HzRejection;
|
||||
match data.enh_filt().output_rate(){
|
||||
Some(val) => { rate = val; }
|
||||
None => { rate = -1.0; }
|
||||
};
|
||||
} else if data.order() == DigitalFilterOrder::Sinc5Sinc1 {
|
||||
filter_type = FilterType::Sinc5Sinc1;
|
||||
match data.odr().output_rate(){
|
||||
Some(val) => { rate = val; }
|
||||
None => { rate = -1.0; }
|
||||
}
|
||||
} else {
|
||||
filter_type = FilterType::Sinc3;
|
||||
match data.odr().output_rate(){
|
||||
Some(val) => { rate = val; }
|
||||
None => { rate = -1.0; }
|
||||
}
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok((filter_type, rate))
|
||||
}
|
||||
|
||||
pub fn set_sinc5_sinc1_with_50hz_60hz_rejection(&mut self, index: u8, rate: PostFilter) -> Result<(), SPI::Error> {
|
||||
self.update_reg(®s::FiltCon { index }, |data| {
|
||||
data.set_sinc3_map(false);
|
||||
data.set_enh_filt_en(true);
|
||||
data.set_order(DigitalFilterOrder::Sinc5Sinc1);
|
||||
data.set_enh_filt(rate);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_postfilter(&mut self, index: u8, filter: Option<PostFilter>) -> Result<(), SPI::Error> {
|
||||
pub fn set_sinc5_sinc1_filter(&mut self, index: u8, rate: SingleChODR) -> Result<(), SPI::Error> {
|
||||
self.update_reg(®s::FiltCon { index }, |data| {
|
||||
match filter {
|
||||
None => data.set_enh_filt_en(false),
|
||||
Some(filter) => {
|
||||
data.set_enh_filt_en(true);
|
||||
data.set_enh_filt(filter);
|
||||
}
|
||||
}
|
||||
data.set_sinc3_map(false);
|
||||
data.set_enh_filt_en(false);
|
||||
data.set_order(DigitalFilterOrder::Sinc5Sinc1);
|
||||
data.set_odr(rate);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_sinc3_filter(&mut self, index: u8, rate: SingleChODR) -> Result<(), SPI::Error> {
|
||||
self.update_reg(®s::FiltCon { index }, |data| {
|
||||
data.set_sinc3_map(false);
|
||||
data.set_enh_filt_en(false);
|
||||
data.set_order(DigitalFilterOrder::Sinc3);
|
||||
data.set_odr(rate);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_sinc3_fine_filter(&mut self, index: u8, rate: f32) -> Result<f32, SPI::Error> {
|
||||
let sinc3_fine_odr_u16 = sinc3_fine_odr_closest(rate);
|
||||
|
||||
self.update_reg(®s::FiltCon { index }, |data| {
|
||||
data.set_sinc3_map(true);
|
||||
data.set_sinc3_map_fine_odr_msb((sinc3_fine_odr_u16 >> 8 & 0xFF) as u8);
|
||||
data.set_sinc3_map_fine_odr_lsb((sinc3_fine_odr_u16 & 0xFF) as u8);
|
||||
}).map(|_| sinc3_fine_odr_output_rate(sinc3_fine_odr_u16))
|
||||
}
|
||||
|
||||
/// Returns the channel the data is from
|
||||
pub fn data_ready(&mut self) -> Result<Option<u8>, SPI::Error> {
|
||||
self.read_reg(®s::Status)
|
||||
|
|
|
@ -203,6 +203,16 @@ impl From<u8> for PostFilter {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Copy, Clone, Debug, Default)]
|
||||
pub enum FilterType {
|
||||
#[default]
|
||||
Sinc5Sinc1With50hz60HzRejection,
|
||||
Sinc5Sinc1,
|
||||
Sinc3,
|
||||
Sinc3WithFineODR,
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum DigitalFilterOrder {
|
||||
Sinc5Sinc1 = 0b00,
|
||||
|
@ -219,3 +229,124 @@ impl From<u8> for DigitalFilterOrder {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[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<Self> {
|
||||
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<f32> {
|
||||
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<u8> 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
|
||||
}
|
||||
|
|
|
@ -227,11 +227,13 @@ impl setup_con::Data {
|
|||
|
||||
def_reg!(FiltCon, u8, filt_con, 0x28, 2);
|
||||
impl filt_con::Data {
|
||||
reg_bit!(sinc3_map, 0, 7, "If set, mapping of filter register changes to directly program the decimation rate of the sinc3 filter");
|
||||
reg_bit!(sinc3_map, set_sinc3_map, 0, 7, "If set, Sinc3 Filter's notch frequency rejection position can be fine tuned with FiltCon[14:0]. Best to be used with Single Channel Enabled");
|
||||
reg_bit!(enh_filt_en, set_enh_filt_en, 0, 3, "Enable postfilters for enhanced 50Hz and 60Hz rejection");
|
||||
reg_bits!(enh_filt, set_enh_filt, 0, 0..=2, PostFilter, "Select postfilters for enhanced 50Hz and 60Hz rejection");
|
||||
reg_bits!(enh_filt, set_enh_filt, 0, 0..=2, PostFilter, "Select postfilters output data rate for enhanced 50Hz and 60Hz rejection");
|
||||
reg_bits!(order, set_order, 1, 5..=6, DigitalFilterOrder, "order of the digital filter that processes the modulator data");
|
||||
reg_bits!(odr, set_odr, 1, 0..=4, "Output data rate");
|
||||
reg_bits!(odr, set_odr, 1, 0..=4, SingleChODR, "Output data rate for normal Sin5c + Sinc1 and Sinc3 filter with SING_CYC = 0 and Single Channel Enabled");
|
||||
reg_bits!(sinc3_map_fine_odr_msb, set_sinc3_map_fine_odr_msb, 0, 0..=6, "MSB Byte Sinc3 Fine Output Config");
|
||||
reg_bits!(sinc3_map_fine_odr_lsb, set_sinc3_map_fine_odr_lsb, 1, 0..=7, "LSB Byte Sinc3 Fine Output Config");
|
||||
}
|
||||
|
||||
def_reg!(Offset, u8, offset, 0x30, 3);
|
||||
|
|
|
@ -379,6 +379,22 @@ impl Thermostat{
|
|||
self.temp_mon.set_lower_limit(t);
|
||||
}
|
||||
|
||||
pub fn set_temp_adc_sinc5_sinc1_filter(&mut self, index: u8, odr: ad7172::SingleChODR) {
|
||||
self.ad7172.set_sinc5_sinc1_filter(index, odr).unwrap();
|
||||
}
|
||||
|
||||
pub fn set_temp_adc_sinc3_filter(&mut self, index: u8, odr: ad7172::SingleChODR) {
|
||||
self.ad7172.set_sinc3_filter(index, odr).unwrap();
|
||||
}
|
||||
|
||||
pub fn set_temp_adc_sinc5_sinc1_with_postfilter(&mut self, index: u8, odr: ad7172::PostFilter) {
|
||||
self.ad7172.set_sinc5_sinc1_with_50hz_60hz_rejection(index, odr).unwrap();
|
||||
}
|
||||
|
||||
pub fn set_temp_adc_sinc3_fine_filter(&mut self, index: u8, rate: f64) {
|
||||
self.ad7172.set_sinc3_fine_filter(index, rate as f32).unwrap();
|
||||
}
|
||||
|
||||
pub fn clear_temp_mon_alarm(&mut self) {
|
||||
self.temp_mon.clear_alarm();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue