From 3716d7367ec4a0043c38b4c7e935be0ebed93c33 Mon Sep 17 00:00:00 2001 From: Hubald Verzijl Date: Thu, 6 Nov 2025 11:33:49 +0100 Subject: [PATCH] Implemented LP DAC for enabling common-mode during 4-lead measurement. --- src/ad5940.rs | 107 ++++++++++++++++++++++++++++++++++++++++ src/ad5940_registers.rs | 103 ++++++++++++++++++++++++++++++++++++++ src/impedance.rs | 41 +++++++++++++++ 3 files changed, 251 insertions(+) diff --git a/src/ad5940.rs b/src/ad5940.rs index b3fc588..8ba8a06 100644 --- a/src/ad5940.rs +++ b/src/ad5940.rs @@ -68,6 +68,55 @@ impl SwitchConfig { } } +#[allow(dead_code)] +#[derive(Default)] +pub struct LpConfig { + data_reset: Option, + power_enable: Option, + data_6bit: Option, + common_mode_switch: Option, + tia_switches_enabled: Option, + tia_enable: Option, + filter_resistor: Option, +} + +impl LpConfig { + pub fn data_reset(&mut self, rsten: bool) -> &mut Self { + self.data_reset = Some(rsten); + self + } + + pub fn power_enable(&mut self, pwden: bool) -> &mut Self { + self.power_enable = Some(pwden); + self + } + + pub fn data_6bit(&mut self, data: u8) -> &mut Self { + self.data_6bit = Some(data & 0x3F); + self + } + + pub fn common_mode_enable(&mut self, enable: bool) -> &mut Self { + self.common_mode_switch = Some(enable); + self + } + + pub fn tia_switches_enabled(&mut self, enable: u16) -> &mut Self { + self.tia_switches_enabled = Some(enable); + self + } + + pub fn tia_enable(&mut self, enable: bool) -> &mut Self { + self.tia_enable = Some(enable); + self + } + + pub fn filter_resistor(&mut self, tiarf: TIARF) -> &mut Self { + self.filter_resistor = Some(tiarf); + self + } +} + #[allow(dead_code)] #[derive(Default)] pub struct DspConfig { @@ -594,6 +643,59 @@ impl AD5940 { Ok(()) } + pub async fn apply_lp_config(&mut self, config: &LpConfig) -> Result<(), Error> { + // LPDACCON0 + let mut current = self.read_reg(Register::LPDACCON0).await?; + + if let Some(data_reset) = config.data_reset { + current = RSTEN::apply(current, data_reset as u32); + } + + if let Some(power_enable) = config.power_enable { + current = PWDEN::apply(current, !power_enable as u32); + } + + self.write_reg(Register::LPDACCON0, current).await?; + + // LPDACDAT0 + let mut current = self.read_reg(Register::LPDACDAT0).await?; + + if let Some(data) = config.data_6bit { + current = DACIN6::apply(current, data as u32); + } + + self.write_reg(Register::LPDACDAT0, current).await?; + + // SWMUX + let mut current = self.read_reg(Register::SWMUX).await?; + + if let Some(common_mode_switch) = config.common_mode_switch { + current = SWMUX::apply(current, common_mode_switch as u32); + } + + self.write_reg(Register::SWMUX, current).await?; + + // LPTIASW0 + if let Some(tia_switches_enabled) = config.tia_switches_enabled { + self.write_reg(Register::LPTIASW0, tia_switches_enabled as u32).await?; + } + + // LPTIACON0 + let mut current = self.read_reg(Register::LPTIACON0).await?; + + if let Some(tia_enable) = config.tia_enable { + current = TIAPDEN::apply(current, !tia_enable as u32); + } + + if let Some(tiarf) = config.filter_resistor { + current = TIARF::apply(current, tiarf as u32); + } + + self.write_reg(Register::LPTIACON0, current).await?; + + Ok(()) + } + pub async fn apply_dsp_config(&mut self, config: &DspConfig) -> Result<(), Error> { // ADCCON let mut current = self.read_reg(Register::ADCCON).await?; @@ -849,6 +951,10 @@ pub enum Register { CMDFIFOWRITE = 0x0000_2070, // Command FIFO Write Register TEMPSENSDAT = 0x0000_2084, // Temperature Sensor Result Register ADCDAT = 0x0000_2074, // ADC Raw Result Register + LPTIASW0 = 0x0000_20E4, // Low power TIA switch configuration + LPTIACON0 = 0x0000_20EC, // Low power TIA control bits, Channel 0 + LPDACDAT0 = 0x0000_2120, // Low power DAC data output Register + LPDACCON0 = 0x0000_2128, // Low power DAC configuration register TEMPSENS = 0x0000_2174, // Temperature Sensor Configuration Register ADCCON = 0x0000_21A8, // ADC Configuration Register SEQ0INFO = 0x0000_21CC, // Sequence 0 Information Register @@ -859,6 +965,7 @@ pub enum Register { AFEGENINTSTA = 0x0000_209C, // Analog Generation Interrupt Register CMDFIFOWADDR = 0x0000_21D4, // Command FIFO Write Address Register PMBW = 0x0000_22F0, // Power Mode Configuration Register + SWMUX = 0x0000_235C, // Common-mode switch mux select register INTCFLAG0 = 0x0000_3010, // Interrupt Control Flag 0 Register INTCFLAG1 = 0x0000_3014, // Interrupt Control Flag 1 Register OSCCON = 0x0000_0A10, // Oscillator Control Register diff --git a/src/ad5940_registers.rs b/src/ad5940_registers.rs index 103f1af..4aaac62 100644 --- a/src/ad5940_registers.rs +++ b/src/ad5940_registers.rs @@ -130,6 +130,107 @@ impl RegisterField for DMUXCON { const MASK: u32 = 0b1111; } +#[allow(dead_code)] +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum RSTEN { + Disabled = 0b0, + Enabled = 0b1, +} + +impl RegisterField for RSTEN { + fn reset() -> Self { + RSTEN::Disabled + } + const BIT_OFFSET: u32 = 0; + const MASK: u32 = 0b1; +} + +#[allow(dead_code)] +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum PWDEN { + DACPoweredOn = 0b0, + DACPoweredOff = 0b1, +} + +impl RegisterField for PWDEN { + fn reset() -> Self { + PWDEN::DACPoweredOff + } + const BIT_OFFSET: u32 = 1; + const MASK: u32 = 0b1; +} + +#[allow(dead_code)] +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum DACIN6 { + Default = 0b0, +} + +impl RegisterField for DACIN6 { + fn reset() -> Self { + DACIN6::Default + } + const BIT_OFFSET: u32 = 12; + const MASK: u32 = 0b11_1111; +} + +#[allow(dead_code)] +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum SWMUX { + CommonModeOff = 0b0, + COmmonModeOn = 0b1, +} + +impl RegisterField for SWMUX { + fn reset() -> Self { + SWMUX::CommonModeOff + } + const BIT_OFFSET: u32 = 3; + const MASK: u32 = 0b1; +} + +#[allow(dead_code)] +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum TIAPDEN { + PowerUp = 0b0, + PowerDown = 0b1, +} + +impl RegisterField for TIAPDEN { + fn reset() -> Self { + TIAPDEN::PowerDown + } + const BIT_OFFSET: u32 = 0; + const MASK: u32 = 0b1; +} + +#[allow(dead_code)] +#[repr(u32)] +#[derive(Copy, Clone)] +pub enum TIARF { + Disconnected = 0b0, + R0 = 0b1, + R20k = 0b10, + R100k = 0b11, + R200k = 0b100, + R400k = 0b101, + R600k = 0b110, + R1M = 0b111, +} + +impl RegisterField for TIARF { + fn reset() -> Self { + TIARF::Disconnected + } + const BIT_OFFSET: u32 = 13; + const MASK: u32 = 0b111; +} + #[allow(dead_code)] #[repr(u32)] #[derive(Copy, Clone)] @@ -158,7 +259,9 @@ pub enum MUXSELN HsTiaNeg = 0b00001, LpTiaNeg = 0b00010, AIN1 = 0b00101, + AIN2 = 0b00110, AIN3 = 0b00111, + VBIAS_CAP= 0b01000, ExciNNode= 0b10100, } diff --git a/src/impedance.rs b/src/impedance.rs index b2000bc..807f547 100644 --- a/src/impedance.rs +++ b/src/impedance.rs @@ -83,6 +83,9 @@ impl ImpedanceSetup { self.ad5940.apply_clk_config(&clk_config).await.unwrap(); + // Configure LP DAC and TIA + self.common_mode_output_enable(false).await.unwrap(); + // Set DSP configuration let mut dsp_config = DspConfig::default(); dsp_config @@ -253,7 +256,36 @@ impl ImpedanceSetup { Ok(results) } + pub async fn common_mode_output_enable(&mut self, enable: bool) -> Result<(), Error> { + // Configure LP DAC and TIA + let mut lp_config = LpConfig::default(); + + if enable { + lp_config + .data_reset(true) + .power_enable(true) + .data_6bit(31) // Mid-scale for 6-bit DAC + .common_mode_enable(true) + .tia_switches_enabled(1 << 5 | 1 << 7 | 1 << 9 | 1 << 13) + .tia_enable(true) + .filter_resistor(TIARF::R20k); + + } else { + lp_config + .power_enable(false) + .common_mode_enable(false) + .tia_enable(false); + } + + self.ad5940.apply_lp_config(&lp_config).await.unwrap(); + + Ok(()) + } + pub async fn init_single_frequency_measurement_2_lead(&mut self, frequency: u32, dft_number: IcdDftNum) -> Result { + // Configure LP DAC and TIA + self.common_mode_output_enable(false).await.unwrap(); + // Reset FIFO self.ad5940.clear_and_enable_fifo().await.unwrap(); @@ -333,6 +365,9 @@ impl ImpedanceSetup { } pub async fn init_single_frequency_measurement_4_lead(&mut self, frequency: u32, dft_number: IcdDftNum) -> Result { + // Configure LP DAC and TIA + self.common_mode_output_enable(true).await.unwrap(); + // Reset FIFO self.ad5940.clear_and_enable_fifo().await.unwrap(); @@ -430,6 +465,9 @@ impl ImpedanceSetup { } pub async fn init_multi_frequency_measurement_2_lead(&mut self, number_of_points: MeasurementPointSet) -> Result, ImpedanceInitError> { + // Configure LP DAC and TIA + self.common_mode_output_enable(false).await.unwrap(); + // Create vector to store the periods per DFT for each frequency let mut periods_per_dft_vec = heapless::Vec::::new(); @@ -535,6 +573,9 @@ impl ImpedanceSetup { } pub async fn init_multi_frequency_measurement_4_lead(&mut self, number_of_points: MeasurementPointSet) -> Result, ImpedanceInitError> { + // Configure LP DAC and TIA + self.common_mode_output_enable(true).await.unwrap(); + // Create vector to store the periods per DFT for each frequency let mut periods_per_dft_vec = heapless::Vec::::new();