use defmt::*; use embassy_stm32::{gpio::Output, mode::Blocking, spi::Spi, spi::Error}; use embassy_time::Timer; use heapless::LinearMap; use crate::ad5940_registers::*; #[allow(dead_code)] #[derive(Default)] pub struct SwitchConfig { t9con: Option, tmuxcon: Option, nmuxcon: Option, pmuxcon: Option, dmuxcon: Option, } impl SwitchConfig { pub fn new() -> Self { Self::default() } pub fn t9con(mut self, t9con: T9CON) -> Self { self.t9con = Some(t9con); self } pub fn tmuxcon(mut self, tmuxcon: TMUXCON) -> Self { self.tmuxcon = Some(tmuxcon); self } pub fn nmuxcon(mut self, nmuxcon: NMUXCON) -> Self { self.nmuxcon = Some(nmuxcon); self } pub fn pmuxcon(mut self, pmuxcon: PMUXCON) -> Self { self.pmuxcon = Some(pmuxcon); self } pub fn dmuxcon(mut self, dmuxcon: DMUXCON) -> Self { self.dmuxcon = Some(dmuxcon); self } } #[allow(dead_code)] #[derive(Default)] pub struct DspConfig { muxseln: Option, muxselp: Option, ctiacon: Option, rtiacon: Option, sinc3osr: Option, sinc2osr: Option, adcsamplerate: Option, dftin: Option, dftnum: Option, hanning: Option, } impl DspConfig { pub fn new() -> Self { Self::default() } pub fn adc_mux_n(mut self, muxseln: MUXSELN) -> Self { self.muxseln = Some(muxseln); self } pub fn adc_mux_p(mut self, muxselp: MUXSELP) -> Self { self.muxselp = Some(muxselp); self } pub fn ctiacon(mut self, ctiacon: CTIACON) -> Self { self.ctiacon = Some(ctiacon); self } pub fn rtiacon(mut self, rtiacon: RTIACON) -> Self { self.rtiacon = Some(rtiacon); self } pub fn sinc3osr(mut self, sinc3osr: SINC3OSR) -> Self { self.sinc3osr = Some(sinc3osr); self } pub fn sinc2osr(mut self, sinc2osr: SINC2OSR) -> Self { self.sinc2osr = Some(sinc2osr); self } pub fn adcsamplerate(mut self, adcsamplerate: ADCSAMPLERATE) -> Self { self.adcsamplerate = Some(adcsamplerate); self } pub fn dftin_sel(mut self, dftin: DFTINSEL) -> Self { self.dftin = Some(dftin); self } pub fn dftnum(mut self, dftnum: DFTNUM) -> Self { self.dftnum = Some(dftnum); self } pub fn hanning(mut self, hanning: bool) -> Self { self.hanning = Some(hanning); self } } pub struct Sequencer { } impl Sequencer { pub fn new() -> Self { Sequencer {} } pub async fn configure(&mut self, ad5940: &mut AD5940) -> Result<(), Error> { // Configure the sequencer here if needed // This is a placeholder for future sequencer configuration logic Ok(()) } } pub struct AD5940 { spi: Spi<'static, Blocking>, cs: Output<'static>, rst: Output<'static>, seq_enabled: bool, pub seq_len: usize, pub seq_buffer: [u32; 25], pub seq_gen_db: LinearMap, } impl AD5940 { pub fn new(spi: Spi<'static, Blocking>, cs: Output<'static>, rst: Output<'static>) -> Self { AD5940 { spi, cs, rst, seq_enabled: false, seq_len: 0, seq_buffer: [0; 25], seq_gen_db: LinearMap::new(), } } pub async fn reset(&mut self) -> Result<(), Error> { self.rst.set_low(); Timer::after_millis(1).await; self.rst.set_high(); Ok(()) } pub async fn read_reg(&mut self, address: Register) -> Result { if self.seq_enabled { self.sequencer_read_register(address).await } else { self.read_reg_raw(address as u16).await } } pub async fn read_reg_raw(&mut self, address: u16) -> Result { // Write address command self.cs.set_low(); self.spi.blocking_write(&[Command::SPICMD_SETADDR as u8])?; self.spi.blocking_write(&[address as u16])?; self.cs.set_high(); // Wait after cs is high Timer::after_nanos(80).await; // Read command self.cs.set_low(); self.spi.blocking_write(&[Command::SPICMD_READREG as u8])?; self.spi.blocking_write(&[0 as u8])?; // Dummy byte let result: u32; if (address as u32) >= 0x1000 && (address as u32) <= 0x3014 { let mut data = [0u8; 4]; self.spi.blocking_read(&mut data)?; result = u32::from_be_bytes(data); } else { let mut data = [0u8; 2]; self.spi.blocking_read(&mut data)?; result = u16::from_be_bytes(data) as u32; } // let mut data = [0u8; 5]; // First byte dummy, then four data bytes // self.spi.blocking_read(&mut data)?; self.cs.set_high(); Ok(result) } pub async fn write_reg(&mut self, address: Register, value: u32) -> Result<(), Error> { if self.seq_enabled { self.sequencer_write_register(address, value).await } else { self.write_reg_raw(address as u16, value).await } } pub async fn write_reg_raw(&mut self, address: u16, value: u32) -> Result<(), Error> { // Write address command self.cs.set_low(); self.spi.blocking_write(&[Command::SPICMD_SETADDR as u8])?; self.spi.blocking_write(&[address as u16])?; self.cs.set_high(); // Wait after cs is high Timer::after_nanos(80).await; // Write value command self.cs.set_low(); self.spi.blocking_write(&[Command::SPICMD_WRITEREG as u8])?; if (address>=0x1000) && (address<=0x3014) { self.spi.blocking_write(&[value])?; } else { self.spi.blocking_write(&[value as u16])?; } self.cs.set_high(); Ok(()) } pub async fn system_init(&mut self) -> Result<(), Error> { // See table 14 self.write_reg_raw(0x0908, 0x02C9).await?; self.write_reg_raw(0x0C08, 0x206C).await?; self.write_reg_raw(0x21F0, 0x0010).await?; // REPEATADCCNV self.write_reg_raw(0x0410, 0x02C9).await?; // CMDDATACON self.write_reg_raw(0x0A28, 0x0009).await?; // EI2CON self.write_reg_raw(0x238C, 0x0104).await?; self.write_reg_raw(0x0A04, 0x4859).await?; // PWRKEY self.write_reg_raw(0x0A04, 0xF27B).await?; // PWRKEY self.write_reg_raw(0x0A00, 0x8009).await?; // PWRMOD self.write_reg_raw(0x22F0, 0x0000).await?; // PMBW // According to library self.write_reg_raw(0x2230, 0xDE87A5AF).await?; self.write_reg_raw(0x2250, 0x103F).await?; self.write_reg_raw(0x2230, 0xDE87A5A0).await?; self.write_reg_raw(0x22B0, 0x203C).await?; Ok(()) } pub async fn sequencer_enable(&mut self, enabled: bool) { self.seq_enabled = enabled; if enabled { self.seq_len = 0; } } async fn sequencer_read_register(&mut self, address: Register) -> Result { if address as u32 > 0x21FF { error!("Sequencer read address out of range: 0x{:04X}", address as u32); } // Read from sequencer database, if not present read default (often default) from hardware if let Some(value) = self.seq_gen_db.get(&address) { Ok(*value) } else { self.read_reg_raw(address as u16).await } } async fn sequencer_write_register(&mut self, address: Register, value: u32) -> Result<(), Error> { if address as u32 > 0x21FF { error!("Sequencer write address out of range: 0x{:04X}", address as u32); } // Update or put in sequencer database if self.seq_gen_db.contains_key(&address) { *self.seq_gen_db.get_mut(&address).unwrap() = value; } else { self.seq_gen_db.insert(address, value).unwrap(); } // Place into buffer let cmd = 0b1 << 31 | (((address as u32) >> 2) & 0x7F) << 24 | (value & 0xFF_FFFF); self.sequencer_insert(cmd).await; return Ok(()) } pub async fn sequencer_wait(&mut self, cycles: u32) { if cycles > 0x3FFF_FFFF { error!("Sequencer wait cycles out of range: {}", cycles); return; } let cmd = 0b00 << 30 | 0x0000_0000 | cycles & 0x3FFF_FFFF; self.sequencer_insert(cmd).await; } pub async fn sequencer_trigger_interrupt(&mut self, int: AFEGENINTSTA) { let cmd = 0x10 | int.bits(); self.sequencer_write_register(Register::AFEGENINTSTA, cmd).await.unwrap(); } async fn sequencer_insert(&mut self, cmd: u32) { if self.seq_len >= self.seq_buffer.len() { error!("Sequencer buffer full, cannot insert command: 0x{:08X}", cmd); return; } self.seq_buffer[self.seq_len] = cmd; self.seq_len += 1; } pub async fn sequencer_cmd_write(&mut self, mut start_address: u32) { // let start_address = 3000 >> 2; let mut counter = 0; start_address &= 0x7FF; // Ensure start address is within bounds while counter < self.seq_len { self.write_reg(Register::CMDFIFOWADDR, start_address + counter as u32).await.unwrap(); self.write_reg(Register::CMDFIFOWRITE, self.seq_buffer[counter as usize]).await.unwrap(); counter += 1; } } pub async fn sequencer_info_configure(&mut self, seq: u8, length: usize, start_address: u32) { let cmd = (length as u32 & 0x7FF) << 16 | (start_address & 0x7FF); match seq { 0 => self.write_reg(Register::SEQ0INFO, cmd).await.unwrap(), 1 => self.write_reg(Register::SEQ1INFO, cmd).await.unwrap(), 2 => self.write_reg(Register::SEQ2INFO, cmd).await.unwrap(), 3 => self.write_reg(Register::SEQ3INFO, cmd).await.unwrap(), _ => { error!("Sequencers from 0 till 3 are allows, now: seq={}", seq); }, } } pub async fn sequencer_trigger(&mut self, seq: u8) { // Trigger the sequencer match seq { 0 => self.write_reg(Register::TRIGSEQ, 1 << 0).await.unwrap(), 1 => self.write_reg(Register::TRIGSEQ, 1 << 1).await.unwrap(), 2 => self.write_reg(Register::TRIGSEQ, 1 << 2).await.unwrap(), 3 => self.write_reg(Register::TRIGSEQ, 1 << 3).await.unwrap(), _ => { error!("Sequencers from 0 till 3 are allows, now: seq={}", seq); }, } } pub async fn apply_switch_config(&mut self, config: SwitchConfig) -> Result<(), Error> { // SWCON let mut current = self.read_reg(Register::SWCON).await?; if let Some(t9con) = config.t9con { current &= !(0b1 << 17); current |= (t9con as u32) << 17; } if let Some(tmuxcon) = config.tmuxcon { current &= !(0b1111 << 12); current |= (tmuxcon as u32) << 12; } if let Some(nmuxcon) = config.nmuxcon { current &= !(0b1111 << 8); current |= (nmuxcon as u32) << 8; } if let Some(pmuxcon) = config.pmuxcon { current &= !(0b1111 << 4); current |= (pmuxcon as u32) << 4; } if let Some(dmuxcon) = config.dmuxcon { current &= !(0b1111); current |= dmuxcon as u32; } self.write_reg(Register::SWCON, 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?; if let Some(muxseln) = config.muxseln { current &= !(0b11111 << 8); current |= (muxseln as u32) << 8; } if let Some(muxselp) = config.muxselp { current &= !(0b11111); current |= muxselp as u32; } self.write_reg(Register::ADCCON, current).await?; // HSRTIACON let mut current = self.read_reg(Register::HSRTIACON).await?; if let Some(ctiacon) = config.ctiacon { current &= !(0b1111 << 5); current |= (ctiacon as u32) << 5; } if let Some(rtiacon) = config.rtiacon { current &= !(0b1111); current |= rtiacon as u32; } self.write_reg(Register::HSRTIACON, current).await?; // ADCFILTERCON let mut current = self.read_reg(Register::ADCFILTERCON).await?; if let Some(sinc3osr) = config.sinc3osr{ current &= !(0b11 << 12); current |= (sinc3osr as u32) << 12; } if let Some(sinc2osr) = config.sinc2osr { current &= !(0b1111 << 8); current |= (sinc2osr as u32) << 8; } if let Some(adcsamplerate) = config.adcsamplerate { current &= !1; current |= adcsamplerate as u32; } self.write_reg(Register::ADCFILTERCON, current).await?; // DFTCON let mut current = self.read_reg(Register::DFTCON).await?; if let Some(dftin) = config.dftin { current &= !(0b11 << 20); current |= (dftin as u32) << 20; } if let Some(dftnum) = config.dftnum { current &= !(0b1111 << 4); current |= (dftnum as u32) << 4; } if let Some(hanning) = config.hanning { current &= !(0b1 << 0); current |= (hanning as u32) << 0; } self.write_reg(Register::DFTCON, current).await?; Ok(()) } pub async fn afecon(&mut self, ctr: AFECON, state: bool) { let reg = self.read_reg(Register::AFECON).await.unwrap(); let mut reg = AFECON::from_bits_truncate(reg); let flags = [ AFECON::DACBUFEN, AFECON::DACREFEN, AFECON::SINC2EN, AFECON::DFTEN, AFECON::WAVEGENEN, AFECON::TEMPCONVEN, AFECON::TEMPSENSEN, AFECON::TIAEN, AFECON::INAMPEN, AFECON::EXBUFEN, AFECON::ADCCONVEN, AFECON::ADCEN, AFECON::DACEN, AFECON::HSREFDIS, ]; for &flag in flags.iter() { if ctr.contains(flag) { reg = if state { reg | flag } else { reg & !flag }; } } self.write_reg(Register::AFECON, reg.bits()).await.unwrap(); } pub async fn wgfcw(&mut self, frequency: u32) { let sinefcw = (frequency as f64) * (1_073_741_824.0 / 16_000_000.0); let sinefcw = 0x00FFFFFF & sinefcw as u32; self.write_reg(Register::WGFCW, sinefcw).await.unwrap(); } pub async fn cmddatacon(&mut self) { // Disable sequencer let mut reg = self.read_reg(Register::SEQCON).await.unwrap(); reg &= !0x0000_0001; // Clear the enable bits self.write_reg(Register::SEQCON, reg).await.unwrap(); // Reset SEQCON self.write_reg(Register::SEQCNT, 0x0000_0001).await.unwrap(); // Disable fifo self.write_reg(Register::FIFOCON, 0b010 << 13).await.unwrap(); // self.write_reg(Register::FIFOCON, 0b011 << 13).await.unwrap(); let cmd = 0b101 << 9 | 0b001 << 6 | 0b01 << 3 | 0b01; self.write_reg(Register::CMDDATACON, cmd).await.unwrap(); // Enable FIFO self.write_reg(Register::FIFOCON, 0b010 << 13 | 1 << 11 ).await.unwrap(); // self.write_reg(Register::FIFOCON, 0b011 << 13 | 1 << 11 ).await.unwrap(); // Enable sequencer let mut reg = self.read_reg(Register::SEQCON).await.unwrap(); reg |= 0x0000_0001; // Set the enable bit self.write_reg(Register::SEQCON, reg).await.unwrap(); } pub async fn get_chipid(&mut self) -> u16 { self.read_reg(Register::CHIPID).await.unwrap() as u16 } pub async fn get_adiid(&mut self) -> u16 { self.read_reg(Register::ADIID).await.unwrap() as u16 } pub async fn init_temperature(&mut self) -> Result<(), Error> { // AFECON: self.afecon(AFECON::TEMPSENSEN | AFECON::ADCEN, true).await; // ADCCON let config_adccon = ADCCON::GNPGA_1_5.bits() | ADCCON::MUXSELN_TEMP.bits() | ADCCON::MUXSELP_TEMP.bits(); self.write_reg(Register::ADCCON, config_adccon).await?; // AFECON - start conversion self.afecon(AFECON::TEMPCONVEN | AFECON::ADCCONVEN, true).await; Ok(()) } pub async fn get_temperature(&mut self) -> Result { // See page 57 of the datasheet for temperature calculation let pga_gain = 1.5; let k = 8.13; let mut tempsensdat0: u32 = self.read_reg(Register::TEMPSENSDAT).await?; tempsensdat0 &= 0x0000FFFF; Ok((tempsensdat0 as f32/(pga_gain * k)) - 273.15) } pub async fn get_fifo_count(&mut self) -> Result { let data = self.read_reg(Register::FIFOCNTSTA).await?; Ok((data >> 16) & 0x7FF) } pub async fn init_waveform(&mut self) -> Result<(), Error> { // Set frequency let freq: u32 = 1000; self.wgfcw(freq).await; // Init amplitude let wg_amplitude = 2047; // 2047 is the maximum amplitude for a 12-bit DAC --> 1.62V peak-to-peak self.write_reg(Register::WGAMPLITUDE, wg_amplitude).await?; // WGCON, enable waveform generator and set to sinusoidal, NO DACCAL let config_wgcon = WGCON::TYPESEL_SIN.bits(); self.write_reg(Register::WGCON, config_wgcon).await?; // SWCON - set up switch matri let switch_config = SwitchConfig::new() .nmuxcon(NMUXCON::N2Closed) .pmuxcon(PMUXCON::P11Closed) .dmuxcon(DMUXCON::D5Closed); self.apply_switch_config(switch_config).await?; // AFECON: self.afecon( AFECON::DACREFEN | AFECON::EXBUFEN | AFECON::INAMPEN | AFECON::DACEN | AFECON::WAVEGENEN, true, ) .await; Ok(()) } pub async fn init_impedance(&mut self) -> Result<(), Error> { // AFECON: self.afecon( AFECON::DACBUFEN | AFECON::DACREFEN | AFECON::SINC2EN | AFECON::TIAEN | AFECON::INAMPEN | AFECON::EXBUFEN | AFECON::DACEN, true, ) .await; // Set DSP configuration let dsp_config = DspConfig::default() .adc_mux_n(MUXSELN::HsTiaNeg) .adc_mux_p(MUXSELP::HsTiaPos) .ctiacon(CTIACON::C32) .rtiacon(RTIACON::R5k) .sinc3osr(SINC3OSR::R5) .sinc2osr(SINC2OSR::R178) .adcsamplerate(ADCSAMPLERATE::R800Hz) .dftin_sel(DFTINSEL::GainOffset) .dftnum(DFTNUM::Num16384) .hanning(true); self.apply_dsp_config(dsp_config).await.unwrap(); // WGCON: set sinus output let config_wgcon = WGCON::TYPESEL_SIN.bits(); self.write_reg(Register::WGCON, config_wgcon).await.unwrap(); Ok(()) } } #[allow(dead_code)] #[allow(non_camel_case_types)] enum Command { SPICMD_SETADDR = 0x20, SPICMD_READREG = 0x6D, SPICMD_WRITEREG = 0x2D, SPICMD_READFIFO = 0x5F, } #[allow(dead_code)] #[allow(non_camel_case_types)] #[repr(u16)] #[derive(Clone, Copy, Eq, PartialEq, Debug, defmt::Format)] pub enum Register { ADIID = 0x0000_0400, // Analog Devices Inc., identification register CHIPID = 0x0000_0404, // Chip identification register TRIGSEQ = 0x0000_0430, // Trigger Sequencer Register AFECON = 0x0000_2000, // Configuration Register SEQCON = 0x0000_2004, // Sequencer Configuration Register FIFOCON = 0x0000_2008, // FIFO Configuration Register SWCON = 0x0000_200C, // Switch Matrix Configuration Register WGCON = 0x0000_2014, // Waveform Generator Configuration Register WGFCW = 0x0000_2030, // Waveform Generator, Sinusoid Frequency Control Word Register WGAMPLITUDE = 0x0000_203C, // Waveform Generator, Sinusoid Amplitude Register SEQCNT = 0x0000_2064, // Sequencer Command Count Register CMDFIFOWRITE = 0x0000_2070, // Command FIFO Write Register TEMPSENSDAT = 0x0000_2084, // Temperature Sensor Result Register ADCDAT = 0x0000_2074, // ADC Raw Result Register TEMPSENS = 0x0000_2174, // Temperature Sensor Configuration Register ADCCON = 0x0000_21A8, // ADC Configuration Register SEQ0INFO = 0x0000_21CC, // Sequence 0 Information Register SEQ1INFO = 0x0000_21E8, // Sequence 1 Information Register SEQ2INFO = 0x0000_21D0, // Sequence 2 Information Register CMDDATACON = 0x0000_21D8, // Command Data Control Register SEQ3INFO = 0x0000_21E4, // Sequence 3 Information Register AFEGENINTSTA = 0x0000_209C, // Analog Generation Interrupt Register CMDFIFOWADDR = 0x0000_21D4, // Command FIFO Write Address Register PMBW = 0x0000_22F0, // Power Mode Configuration Register INTCFLAG0 = 0x0000_3010, // Interrupt Control Flag 0 Register INTCFLAG1 = 0x0000_3014, // Interrupt Control Flag 1 Register OSCCON = 0x0000_0A10, // Oscillator Control Register SEQTIMEOUT = 0x0000_2068, // Sequencer Timeout Counter Register SEQCRC = 0x0000_2060, // Sequencer CRC Value Register DATAFIFOTHRES = 0x0000_21E0, // Data FIFO Threshold Register SYNCEXTDEVICE = 0x0000_2054, // Sync External Device Register GP0CON = 0x0000_0000, // GPIO Port 0 Configuration Register DATAFIFORD = 0x0000_206C, // Data FIFO Read Register DFTCON = 0x0000_20D0, // DFT Configuration Register HSDACCON = 0x0000_2010, // High Speed DAC Configuration Register HSRTIACON = 0x0000_20F0, // High Speed RTIA Configuration Register BUFSENCON = 0x0000_2180, // HIGH POWER AND LOW POWER BUFFER CONTROL REGISTER FIFOCNTSTA = 0x0000_2200, // Command and data FIFO internal data count register ADCFILTERCON = 0x0000_2044 // ADC Output Filters Configuration Register }