diff --git a/.gitignore b/.gitignore index ea8c4bf..0592392 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ /target +.DS_Store diff --git a/src/ad5940.rs b/src/ad5940.rs index c024e58..5920a39 100644 --- a/src/ad5940.rs +++ b/src/ad5940.rs @@ -1,3 +1,5 @@ +use defmt::*; + use embassy_stm32::{gpio::Output, mode::Blocking, spi::Spi, spi::Error}; use embassy_time::Timer; @@ -7,11 +9,21 @@ pub struct AD5940 { spi: Spi<'static, Blocking>, cs: Output<'static>, rst: Output<'static>, + seq_enabled: bool, + pub seq_len: usize, + pub seq_buffer: [u32; 16], } impl AD5940 { pub fn new(spi: Spi<'static, Blocking>, cs: Output<'static>, rst: Output<'static>) -> Self { - AD5940 { spi, cs, rst } + AD5940 { + spi, + cs, + rst, + seq_enabled: false, + seq_len: 0, + seq_buffer: [0; 16], + } } pub async fn reset(&mut self) -> Result<(), Error> { @@ -21,7 +33,11 @@ impl AD5940 { Ok(()) } - async fn read_reg_16(&mut self, address: Register) -> Result { + pub async fn read_reg(&mut self, address: Register) -> Result { + 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])?; @@ -29,20 +45,41 @@ impl AD5940 { self.cs.set_high(); // Wait after cs is high - Timer::after_nanos(80).await; + // Timer::after_nanos(80).await; + Timer::after_millis(10).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; 3]; // First byte dummy, then two data bytes - self.spi.blocking_read(&mut data)?; + // let mut data = [0u8; 5]; // First byte dummy, then four data bytes + // self.spi.blocking_read(&mut data)?; self.cs.set_high(); + Timer::after_millis(1).await; - Ok(u16::from_be_bytes([data[1], data[2]])) + Ok(result) } - async fn read_reg_32(&mut self, address: Register) -> 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])?; @@ -50,85 +87,157 @@ impl AD5940 { 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])?; - - let mut data = [0u8; 5]; // First byte dummy, then four data bytes - self.spi.blocking_read(&mut data)?; - self.cs.set_high(); - - Ok(u32::from_be_bytes([data[1], data[2], data[3], data[4]])) - } - - async fn write_reg_32(&mut self, address: Register, value: u32) -> Result<(), Error> { - self.write_reg_32_raw(address as u16, value).await - } - - async fn write_reg_32_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; + // Timer::after_nanos(80).await; + Timer::after_millis(10).await; // Write value command self.cs.set_low(); self.spi.blocking_write(&[Command::SPICMD_WRITEREG as u8])?; - self.spi.blocking_write(&[value])?; + if (address>=0x1000) && (address<=0x3014) { + self.spi.blocking_write(&[value])?; + } else { + self.spi.blocking_write(&[value as u16])?; + } self.cs.set_high(); - - Ok(()) - } - - async fn write_reg_16_raw(&mut self, address: u16, value: u16) -> 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])?; - self.spi.blocking_write(&[value])?; - self.cs.set_high(); - + Timer::after_millis(1).await; + + Ok(()) } pub async fn system_init(&mut self) -> Result<(), Error> { // See table 14 - self.write_reg_16_raw(0x0908, 0x02C9).await?; - self.write_reg_16_raw(0x0C08, 0x206C).await?; - self.write_reg_16_raw(0x21F0, 0x0010).await?; - self.write_reg_16_raw(0x0410, 0x02C9).await?; - self.write_reg_16_raw(0x0A28, 0x0009).await?; - self.write_reg_16_raw(0x238C, 0x0104).await?; - self.write_reg_16_raw(0x0A04, 0x4859).await?; - self.write_reg_16_raw(0x0A04, 0xF27B).await?; - self.write_reg_16_raw(0x0A00, 0x8009).await?; - self.write_reg_16_raw(0x22F0, 0x0000).await?; + 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_32_raw(0x2230, 0xDE87A5AF).await?; - // self.write_reg_16_raw(0x2250, 0x103F).await?; - // self.write_reg_16_raw(0x22B0, 0x203C).await?; - // self.write_reg_32_raw(0x2230, 0xDE87A5A0).await?; - + 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_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); + } + let cmd = (((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 = 0b01 << 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 >= 16 { + 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(); + Timer::after_millis(1).await; + self.write_reg(Register::CMDFIFOWRITE, self.seq_buffer[counter as usize]).await.unwrap(); + // self.write_reg(Register::CMDFIFOWRITE, 0).await.unwrap(); + Timer::after_millis(1).await; + // info!("{:032b}", self.seq_buffer[counter as usize]); + 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) { + // Trigger the sequencer + self.write_reg(Register::TRIGSEQ, 1 << 0).await.unwrap(); + // self.write_reg(Register::TRIGSEQ, 1 << 1).await.unwrap(); + // self.write_reg(Register::TRIGSEQ, 1 << 2).await.unwrap(); + // self.write_reg(Register::TRIGSEQ, 1 << 3).await.unwrap(); + + // wait + // Timer::after_millis(10).await; + + let test = self.read_reg(Register::SEQCNT).await.unwrap(); + info!("Sequencer triggered, SEQCNT: {}", test); + + + let test = self.read_reg(Register::INTCFLAG0).await.unwrap(); + info!("INTCFLAG0: 0x{:08X}", test); + let test = self.read_reg(Register::INTCFLAG1).await.unwrap(); + info!("INTCFLAG1: 0x{:08X}", test); + + self.write_reg_raw(0x3008, 0xFFFF_FFFF).await.unwrap(); + self.write_reg_raw(0x300C, 0xFFFF_FFFF).await.unwrap(); + + let test = self.read_reg(Register::SEQTIMEOUT).await.unwrap(); + info!("SEQTIMEOUT: {}", test); + + let test = self.read_reg(Register::CMDFIFOWADDR).await.unwrap(); + info!("CMDFIFOWADDR: {}", test); + + // for i in 0..200 { + let test= self.read_reg_raw(0x206C).await.unwrap(); + info!("DATAFIFORD: 0x{:08X}", test); + // } + + + let test = self.read_reg_raw(0x2200).await.unwrap(); + info!("FIFOCNTSTA: {}", (test>>16) & 0b111_1111_1111); + } + pub async fn afecon(&mut self, ctr: AFECON, state: bool) { - let reg = self.read_reg_32(Register::AFECON).await.unwrap(); + let reg = self.read_reg(Register::AFECON).await.unwrap(); let mut reg = AFECON::from_bits_truncate(reg); let flags = [ @@ -158,11 +267,11 @@ impl AD5940 { } } - self.write_reg_32(Register::AFECON, reg.bits()).await.unwrap(); + self.write_reg(Register::AFECON, reg.bits()).await.unwrap(); } pub async fn swcon(&mut self, ctr: SWCON) { - let reg = self.read_reg_32(Register::SWCON).await.unwrap(); + let reg = self.read_reg(Register::SWCON).await.unwrap(); let mut reg = SWCON::from_bits_truncate(reg); // NMUXCON @@ -189,21 +298,46 @@ impl AD5940 { reg |= SWCON::DMUXCON_D5; } - self.write_reg_32(Register::SWCON, reg.bits()).await.unwrap(); + self.write_reg(Register::SWCON, 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_32(Register::WGFCW, sinefcw).await.unwrap(); + self.write_reg(Register::WGFCW, sinefcw).await.unwrap(); } - pub async fn get_chipid(&mut self) -> Result { - self.read_reg_16(Register::CHIPID).await + 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_0002).await.unwrap(); + + // Disable fifo + self.write_reg(Register::FIFOCON, 0b010 << 13).await.unwrap(); + + let cmd = 0b10 << 9 | 0b001 << 6 | 1 << 3 | 1; + self.write_reg(Register::CMDDATACON, cmd).await.unwrap(); + + // Enable FIFO + self.write_reg(Register::FIFOCON, 0b010 << 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_adiid(&mut self) -> Result { - self.read_reg_16(Register::ADIID).await + 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> { @@ -212,7 +346,7 @@ impl AD5940 { // ADCCON let config_adccon = ADCCON::GNPGA_1_5.bits() | ADCCON::MUXSELN_TEMP.bits() | ADCCON::MUXSELP_TEMP.bits(); - self.write_reg_32(Register::ADCCON, config_adccon).await?; + self.write_reg(Register::ADCCON, config_adccon).await?; // AFECON - start conversion self.afecon(AFECON::TEMPCONVEN | AFECON::ADCCONVEN, true).await; @@ -225,7 +359,7 @@ impl AD5940 { let pga_gain = 1.5; let k = 8.13; - let mut tempsensdat0: u32 = self.read_reg_32(Register::TEMPSENSDAT).await?; + let mut tempsensdat0: u32 = self.read_reg(Register::TEMPSENSDAT).await?; tempsensdat0 &= 0x0000FFFF; Ok((tempsensdat0 as f32/(pga_gain * k)) - 273.15) @@ -238,11 +372,11 @@ impl AD5940 { // Init amplitude let wg_amplitude = 2047; // 2047 is the maximum amplitude for a 12-bit DAC --> 1.62V peak-to-peak - self.write_reg_32(Register::WGAMPLITUDE, wg_amplitude).await?; + 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_32(Register::WGCON, config_wgcon).await?; + self.write_reg(Register::WGCON, config_wgcon).await?; // SWCON - set up switch matrix self.swcon( @@ -267,6 +401,9 @@ impl AD5940 { #[allow(dead_code)] #[allow(non_camel_case_types)] + + + enum Command { SPICMD_SETADDR = 0x20, SPICMD_READREG = 0x6D, @@ -277,17 +414,36 @@ enum Command { #[allow(dead_code)] #[allow(non_camel_case_types)] #[repr(u16)] -enum Register { +#[derive(Clone, Copy)] +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 } diff --git a/src/ad5940_registers.rs b/src/ad5940_registers.rs index ea269c5..a9fe431 100644 --- a/src/ad5940_registers.rs +++ b/src/ad5940_registers.rs @@ -53,6 +53,17 @@ bitflags! { } } +bitflags! { + // Analog Generation Interrupt Register + // Address 0x0000209C, Reset: 0x00000010, Name: AFEGENINTSTA + pub struct AFEGENINTSTA: u32 { + const CUSTOMINT3 = 1 << 3; // General-Purpose Custom Interrupt 3 + const CUSTOMINT2 = 1 << 2; // General-Purpose Custom Interrupt 2 + const CUSTOMINT1 = 1 << 1; // General-Purpose Custom Interrupt 1 + const CUSTOMINT0 = 1 << 0; // General-Purpose Custom Interrupt 0 + } +} + bitflags! { // ADC Configuration Register, // Address 0x000021A8, Reset: 0x00000000, Name: ADCCON diff --git a/src/main.rs b/src/main.rs index 1499025..addb660 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,8 @@ use embassy_stm32::gpio::{Level, Output, Speed}; use embassy_stm32::{i2c, spi, Config}; use embassy_stm32::time::Hertz; use embassy_time::Timer; +use crate::ad5940_registers::{AFECON, AFEGENINTSTA}; + use {defmt_rtt as _, panic_probe as _}; mod ad5940; @@ -41,41 +43,62 @@ async fn main(_spawner: Spawner) { // let mut led = Output::new(p.PA5, Level::High, Speed::Low); - // Set up SPI for AD5940 - let cs = Output::new(p.PC9, Level::High, Speed::Low); - let rst = Output::new(p.PB3, Level::High, Speed::Low); + // // Set up SPI for AD5940 + // let cs = Output::new(p.PC9, Level::High, Speed::Low); + // let rst = Output::new(p.PB3, Level::High, Speed::Low); - let spi = spi::Spi::new_blocking( - p.SPI1, - p.PA5, // SCK - p.PA7, // MOSI - p.PA6, // MISO - spi::Config::default() - ); + // let spi = spi::Spi::new_blocking( + // p.SPI1, + // p.PA5, // SCK + // p.PA7, // MOSI + // p.PA6, // MISO + // spi::Config::default() + // ); - let mut ad5940 = AD5940::new(spi, cs, rst); - ad5940.reset().await.unwrap(); - Timer::after_millis(1).await; - ad5940.system_init().await.unwrap(); + // let mut ad5940 = AD5940::new(spi, cs, rst); + // ad5940.reset().await.unwrap(); + // Timer::after_millis(1).await; + // ad5940.system_init().await.unwrap(); // ad5940.init_temperature().await.unwrap(); - ad5940.init_waveform().await.unwrap(); + // ad5940.init_waveform().await.unwrap(); - // Set up I2C for ADG2128 - let i2c = i2c::I2c::new_blocking( - p.I2C1, - p.PB6, - p.PB7, - Hertz(400_000), - i2c::Config::default() - ); + // // Set up I2C for ADG2128 + // let i2c = i2c::I2c::new_blocking( + // p.I2C1, + // p.PB6, + // p.PB7, + // Hertz(400_000), + // i2c::Config::default() + // ); - // Initialize electrodes - let mut electrodes = Electrodes::new(i2c); - electrodes.reset_all(); - electrodes.set(Electrode::E1, AD5940Pin::CE0, State::ENABLED); - electrodes.set(Electrode::E3, AD5940Pin::AIN1, State::ENABLED); - // electrodes.set(Electrode::E12, AD5940Pin::RE0, State::ENABLED); + // // Initialize electrodes + // let mut electrodes = Electrodes::new(i2c); + // electrodes.reset_all(); + // electrodes.set(Electrode::E1, AD5940Pin::CE0, State::ENABLED); + // electrodes.set(Electrode::E3, AD5940Pin::AIN1, State::ENABLED); + // // electrodes.set(Electrode::E12, AD5940Pin::RE0, State::ENABLED); + + // // Sequencer test + // ad5940.sequencer_enable(true).await; + // ad5940.afecon(AFECON::WAVEGENEN, true).await; + // ad5940.wgfcw(1000).await; + // ad5940.sequencer_wait(600_000).await; + // ad5940.wgfcw(2000).await; + // ad5940.sequencer_trigger_interrupt(AFEGENINTSTA::CUSTOMINT0).await; + // ad5940.sequencer_trigger_interrupt(AFEGENINTSTA::CUSTOMINT1).await; + // ad5940.sequencer_wait(160_000).await; + // ad5940.afecon(AFECON::WAVEGENEN, false).await; + // ad5940.sequencer_enable(false).await; + + // // Configure the sequencer cmd data sram + // ad5940.cmddatacon().await; + + // let start_address = 100; // 20 works + // ad5940.sequencer_cmd_write(start_address).await; + + // ad5940.sequencer_info_configure(0, ad5940.seq_len, start_address).await; + // info!("{}", ad5940.seq_len); loop { // Read chip id @@ -86,15 +109,14 @@ async fn main(_spawner: Spawner) { // let temp = ad5940.get_temperature().await.unwrap(); // info!("Temperature: {}°C", temp); - let result = electrodes.get_all(); - info!("Electrodes states: {:?}", result); + // let result = electrodes.get_all(); + // info!("Electrodes states: {:?}", result); // info!("high"); // led.set_high(); - Timer::after_millis(500).await; + + Timer::after_millis(1000).await; - // info!("low"); - // led.set_low(); - Timer::after_millis(500).await; + // ad5940.sequencer_trigger().await; } } \ No newline at end of file