mirror of
https://github.com/hubaldv/bioz-firmware-rs.git
synced 2025-12-06 05:01:18 +00:00
Added external interrupt and test to determine impedance. Not working yet.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -409,7 +409,6 @@ dependencies = [
|
|||||||
"defmt 0.3.100",
|
"defmt 0.3.100",
|
||||||
"document-features",
|
"document-features",
|
||||||
"embassy-embedded-hal 0.3.1",
|
"embassy-embedded-hal 0.3.1",
|
||||||
"embassy-executor",
|
|
||||||
"embassy-futures",
|
"embassy-futures",
|
||||||
"embassy-hal-internal 0.2.0",
|
"embassy-hal-internal 0.2.0",
|
||||||
"embassy-net-driver",
|
"embassy-net-driver",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Change stm32h563zi to your chip name, if necessary.
|
# Change stm32h563zi to your chip name, if necessary.
|
||||||
embassy-stm32 = { version = "0.2.0", features = ["defmt", "stm32h533re", "memory-x", "time-driver-any", "exti", "unstable-pac", "low-power"] }
|
embassy-stm32 = { version = "0.2.0", features = ["defmt", "stm32h533re", "memory-x", "time-driver-any", "exti", "unstable-pac"] }
|
||||||
embassy-sync = { version = "0.6.0", features = ["defmt"] }
|
embassy-sync = { version = "0.6.0", features = ["defmt"] }
|
||||||
embassy-executor = { version = "0.7.0", features = ["arch-cortex-m", "executor-thread", "defmt"] }
|
embassy-executor = { version = "0.7.0", features = ["arch-cortex-m", "executor-thread", "defmt"] }
|
||||||
embassy-time = { version = "0.4.0", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
embassy-time = { version = "0.4.0", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
|
||||||
|
|||||||
@@ -207,8 +207,8 @@ impl AD5940 {
|
|||||||
// info!("DATAFIFORD: 0x{:08X}", test);
|
// info!("DATAFIFORD: 0x{:08X}", test);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let test = self.read_reg_raw(0x2200).await.unwrap();
|
// let test = self.read_reg_raw(0x2200).await.unwrap();
|
||||||
info!("FIFOCNTSTA: {}", (test>>16) & 0b111_1111_1111);
|
// info!("FIFOCNTSTA: {}", (test>>16) & 0b111_1111_1111);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn afecon(&mut self, ctr: AFECON, state: bool) {
|
pub async fn afecon(&mut self, ctr: AFECON, state: bool) {
|
||||||
@@ -249,6 +249,22 @@ impl AD5940 {
|
|||||||
let reg = self.read_reg(Register::SWCON).await.unwrap();
|
let reg = self.read_reg(Register::SWCON).await.unwrap();
|
||||||
let mut reg = SWCON::from_bits_truncate(reg);
|
let mut reg = SWCON::from_bits_truncate(reg);
|
||||||
|
|
||||||
|
// T9CON
|
||||||
|
if ctr.contains(SWCON::T9CON) {
|
||||||
|
reg |= SWCON::T9CON;
|
||||||
|
} else {
|
||||||
|
reg &= !SWCON::T9CON;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TMUXCON
|
||||||
|
if (ctr & SWCON::TMUXCON_MSK) == SWCON::TMUXCON_T2 {
|
||||||
|
reg &= !SWCON::TMUXCON_MSK;
|
||||||
|
reg |= SWCON::TMUXCON_T2;
|
||||||
|
} else if (ctr & SWCON::TMUXCON_MSK) == SWCON::TMUXCON_TR1 {
|
||||||
|
reg &= !SWCON::TMUXCON_MSK;
|
||||||
|
reg |= SWCON::TMUXCON_TR1;
|
||||||
|
}
|
||||||
|
|
||||||
// NMUXCON
|
// NMUXCON
|
||||||
if (ctr & SWCON::NMUXCON_MSK) == SWCON::NMUXCON_N2 {
|
if (ctr & SWCON::NMUXCON_MSK) == SWCON::NMUXCON_N2 {
|
||||||
reg &= !SWCON::NMUXCON_MSK;
|
reg &= !SWCON::NMUXCON_MSK;
|
||||||
@@ -256,7 +272,10 @@ impl AD5940 {
|
|||||||
} else if (ctr & SWCON::NMUXCON_MSK) == SWCON::NMUXCON_N5 {
|
} else if (ctr & SWCON::NMUXCON_MSK) == SWCON::NMUXCON_N5 {
|
||||||
reg &= !SWCON::NMUXCON_MSK;
|
reg &= !SWCON::NMUXCON_MSK;
|
||||||
reg |= SWCON::NMUXCON_N5;
|
reg |= SWCON::NMUXCON_N5;
|
||||||
};
|
} else if (ctr & SWCON::NMUXCON_MSK) == SWCON::NMUXCON_NR1 {
|
||||||
|
reg &= !SWCON::NMUXCON_MSK;
|
||||||
|
reg |= SWCON::NMUXCON_NR1;
|
||||||
|
}
|
||||||
|
|
||||||
// PMUXCON
|
// PMUXCON
|
||||||
if (ctr & SWCON::PMUXCON_MSK) == SWCON::PMUXCON_P2 {
|
if (ctr & SWCON::PMUXCON_MSK) == SWCON::PMUXCON_P2 {
|
||||||
@@ -265,12 +284,18 @@ impl AD5940 {
|
|||||||
} else if (ctr & SWCON::PMUXCON_MSK) == SWCON::PMUXCON_P11 {
|
} else if (ctr & SWCON::PMUXCON_MSK) == SWCON::PMUXCON_P11 {
|
||||||
reg &= !SWCON::PMUXCON_MSK;
|
reg &= !SWCON::PMUXCON_MSK;
|
||||||
reg |= SWCON::PMUXCON_P11;
|
reg |= SWCON::PMUXCON_P11;
|
||||||
|
} else if (ctr & SWCON::PMUXCON_MSK) == SWCON::PMUXCON_PR0 {
|
||||||
|
reg &= !SWCON::PMUXCON_MSK;
|
||||||
|
reg |= SWCON::PMUXCON_PR0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// DMUXCON
|
// DMUXCON
|
||||||
if ctr.contains(SWCON::DMUXCON_D5) {
|
if (ctr & SWCON::DMUXCON_MSK) == SWCON::DMUXCON_D5 {
|
||||||
reg &= !SWCON::DMUXCON_MSK;
|
reg &= !SWCON::DMUXCON_MSK;
|
||||||
reg |= SWCON::DMUXCON_D5;
|
reg |= SWCON::DMUXCON_D5;
|
||||||
|
} else if { ctr & SWCON::DMUXCON_MSK } == SWCON::DMUXCON_DR0 {
|
||||||
|
reg &= !SWCON::DMUXCON_MSK;
|
||||||
|
reg |= SWCON::DMUXCON_DR0;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.write_reg(Register::SWCON, reg.bits()).await.unwrap();
|
self.write_reg(Register::SWCON, reg.bits()).await.unwrap();
|
||||||
@@ -397,7 +422,7 @@ impl AD5940 {
|
|||||||
| SWCON::PMUXCON_P11
|
| SWCON::PMUXCON_P11
|
||||||
| SWCON::DMUXCON_D5).await;
|
| SWCON::DMUXCON_D5).await;
|
||||||
//
|
//
|
||||||
self.write_reg_raw(0x0000_20D0, 0b1000 << 4).await.unwrap();
|
self.write_reg_raw(0x0000_20D0, 0b1000 << 4).await.unwrap(); // 1024 OSR
|
||||||
// SINC3 = 5 --> 160000 Hz
|
// SINC3 = 5 --> 160000 Hz
|
||||||
// SINC2 = 178 --> 898,8764044944Hz
|
// SINC2 = 178 --> 898,8764044944Hz
|
||||||
// ... (DFTNUM = 2048)
|
// ... (DFTNUM = 2048)
|
||||||
@@ -452,4 +477,7 @@ pub enum Register {
|
|||||||
SEQTIMEOUT = 0x0000_2068, // Sequencer Timeout Counter Register
|
SEQTIMEOUT = 0x0000_2068, // Sequencer Timeout Counter Register
|
||||||
SEQCRC = 0x0000_2060, // Sequencer CRC Value Register
|
SEQCRC = 0x0000_2060, // Sequencer CRC Value Register
|
||||||
DATAFIFOTHRES = 0x0000_21E0, // Data FIFO Threshold 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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,13 +28,20 @@ bitflags! {
|
|||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub struct SWCON: u32 {
|
pub struct SWCON: u32 {
|
||||||
|
const T9CON = 1 << 17; // T9 switch // RTIA switch
|
||||||
|
const TMUXCON_MSK = 0b1111 << 12;
|
||||||
|
const TMUXCON_T2 = 0b0010 << 12; // T2 switch
|
||||||
|
const TMUXCON_TR1 = 0b1000 << 12; // TR1 switch
|
||||||
const NMUXCON_MSK = 0b1111 << 8;
|
const NMUXCON_MSK = 0b1111 << 8;
|
||||||
const NMUXCON_N2 = 0b0010 << 8; // N2 switch
|
const NMUXCON_N2 = 0b0010 << 8; // N2 switch
|
||||||
const NMUXCON_N5 = 0b0101 << 8; // N5 switch
|
const NMUXCON_N5 = 0b0101 << 8; // N5 switch
|
||||||
|
const NMUXCON_NR1 = 0b1010 << 8; // NR1 switch
|
||||||
const PMUXCON_MSK = 0b1111 << 4;
|
const PMUXCON_MSK = 0b1111 << 4;
|
||||||
|
const PMUXCON_PR0 = 0b0001 << 4; // PR0 switch
|
||||||
const PMUXCON_P2 = 0b0010 << 4; // P2 switch
|
const PMUXCON_P2 = 0b0010 << 4; // P2 switch
|
||||||
const PMUXCON_P11 = 0b1011 << 4; // P11 switch
|
const PMUXCON_P11 = 0b1011 << 4; // P11 switch
|
||||||
const DMUXCON_MSK = 0b1111;
|
const DMUXCON_MSK = 0b1111;
|
||||||
|
const DMUXCON_DR0 = 0b0001; // DR0 switch
|
||||||
const DMUXCON_D5 = 0b0101; // D5 switch
|
const DMUXCON_D5 = 0b0101; // D5 switch
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
133
src/main.rs
133
src/main.rs
@@ -3,13 +3,14 @@
|
|||||||
|
|
||||||
use defmt::info;
|
use defmt::info;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
|
use embassy_stm32::exti::ExtiInput;
|
||||||
use embassy_time::{Timer, Duration};
|
use embassy_time::{Timer, Duration};
|
||||||
use embassy_futures::{select::select, select::Either};
|
use embassy_futures::{select::select, select::Either};
|
||||||
use embassy_stm32::gpio::{Level, Output, Speed};
|
use embassy_stm32::gpio::{Level, Output, Speed};
|
||||||
use embassy_stm32::{i2c, spi, Config};
|
use embassy_stm32::{i2c, spi, Config};
|
||||||
use embassy_stm32::time::Hertz;
|
use embassy_stm32::time::Hertz;
|
||||||
|
|
||||||
use crate::ad5940_registers::{AFECON, AFEGENINTSTA};
|
use crate::ad5940_registers::{AFECON, SWCON};
|
||||||
|
|
||||||
use {defmt_rtt as _, panic_probe as _};
|
use {defmt_rtt as _, panic_probe as _};
|
||||||
|
|
||||||
@@ -69,6 +70,10 @@ async fn main(spawner: Spawner) {
|
|||||||
let cs = Output::new(p.PC9, Level::High, Speed::Low);
|
let cs = Output::new(p.PC9, Level::High, Speed::Low);
|
||||||
let rst = Output::new(p.PB3, Level::High, Speed::Low);
|
let rst = Output::new(p.PB3, Level::High, Speed::Low);
|
||||||
|
|
||||||
|
// Set up interrupt at GPIO for AD5940
|
||||||
|
let ad5940_gpio_0 = ExtiInput::new(p.PC8, p.EXTI8, embassy_stm32::gpio::Pull::Up);
|
||||||
|
spawner.must_spawn(ad5940_readout_task(ad5940_gpio_0));
|
||||||
|
|
||||||
let spi = spi::Spi::new_blocking(
|
let spi = spi::Spi::new_blocking(
|
||||||
p.SPI1,
|
p.SPI1,
|
||||||
p.PA5, // SCK
|
p.PA5, // SCK
|
||||||
@@ -103,18 +108,37 @@ async fn main(spawner: Spawner) {
|
|||||||
// // electrodes.set(Electrode::E12, AD5940Pin::RE0, State::ENABLED);
|
// // electrodes.set(Electrode::E12, AD5940Pin::RE0, State::ENABLED);
|
||||||
|
|
||||||
// Turn on the green LED
|
// Turn on the green LED
|
||||||
ad5940.write_reg_raw(0x0000_0004, 1 << 1).await.unwrap();
|
// ad5940.write_reg_raw(0x0000_0004, 1 << 1).await.unwrap();
|
||||||
ad5940.write_reg_raw(0x0000_001C, 1 << 1).await.unwrap();
|
// ad5940.write_reg_raw(0x0000_001C, 1 << 1).await.unwrap();
|
||||||
|
|
||||||
// // Sequencer test
|
ad5940.write_reg(ad5940::Register::GP0CON, 0b10 << 4 | 0b10 << 2 | 0b10).await.unwrap();
|
||||||
|
ad5940.write_reg(ad5940::Register::SYNCEXTDEVICE, 0b111).await.unwrap();
|
||||||
|
|
||||||
|
// Sequencer test
|
||||||
ad5940.sequencer_enable(true).await;
|
ad5940.sequencer_enable(true).await;
|
||||||
ad5940.afecon(AFECON::WAVEGENEN, true).await;
|
ad5940.wgfcw(100).await;
|
||||||
ad5940.wgfcw(1000).await;
|
|
||||||
ad5940.sequencer_wait(300_000).await;
|
// Rcal
|
||||||
ad5940.wgfcw(2000).await;
|
ad5940.swcon(SWCON::DMUXCON_DR0 | SWCON::PMUXCON_PR0 | SWCON::NMUXCON_NR1 | SWCON::TMUXCON_TR1 | SWCON::T9CON).await; // RCAL0 -->
|
||||||
ad5940.sequencer_wait(160_000).await;
|
ad5940.afecon(AFECON::WAVEGENEN | AFECON::ADCEN, true).await;
|
||||||
// ad5940.sequencer_trigger_interrupt(AFEGENINTSTA::CUSTOMINT0).await;
|
ad5940.sequencer_wait(16*10).await; // 10 us
|
||||||
ad5940.afecon(AFECON::WAVEGENEN, false).await;
|
ad5940.afecon(AFECON::ADCCONVEN | AFECON::DFTEN, true).await;
|
||||||
|
ad5940.sequencer_wait(16 * 1_500_000).await; // 1.5 second
|
||||||
|
ad5940.afecon(AFECON::WAVEGENEN | AFECON:: ADCEN | AFECON::ADCCONVEN | AFECON::DFTEN, false).await;
|
||||||
|
|
||||||
|
// Rz
|
||||||
|
ad5940.swcon(SWCON::DMUXCON_D5 | SWCON::PMUXCON_P11 | SWCON::NMUXCON_N2 | SWCON::TMUXCON_MSK | SWCON::TMUXCON_T2).await;
|
||||||
|
ad5940.afecon(AFECON::WAVEGENEN | AFECON::ADCEN, true).await;
|
||||||
|
ad5940.sequencer_wait(16*10).await; // 10 us
|
||||||
|
ad5940.afecon(AFECON::ADCCONVEN | AFECON::DFTEN, true).await;
|
||||||
|
ad5940.sequencer_wait(16 * 1_500_000).await; // 1.5 second
|
||||||
|
ad5940.afecon(AFECON::WAVEGENEN | AFECON:: ADCEN | AFECON::ADCCONVEN | AFECON::DFTEN, false).await;
|
||||||
|
|
||||||
|
// Toggle leds
|
||||||
|
ad5940.write_reg(ad5940::Register::SYNCEXTDEVICE, 0b010).await.unwrap();
|
||||||
|
ad5940.sequencer_wait(16 * 100_000).await; // 0.1 second
|
||||||
|
ad5940.write_reg(ad5940::Register::SYNCEXTDEVICE, 0b111).await.unwrap();
|
||||||
|
|
||||||
ad5940.sequencer_enable(false).await;
|
ad5940.sequencer_enable(false).await;
|
||||||
|
|
||||||
// // Configure the sequencer cmd data sram
|
// // Configure the sequencer cmd data sram
|
||||||
@@ -148,13 +172,26 @@ async fn main(spawner: Spawner) {
|
|||||||
|
|
||||||
ad5940.sequencer_trigger(0).await;
|
ad5940.sequencer_trigger(0).await;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// info!("Mainloop still running!");
|
// info!("Mainloop still running!");
|
||||||
|
|
||||||
Timer::after_millis(250).await;
|
Timer::after_millis(3500).await;
|
||||||
|
|
||||||
|
// let test = ad5940.read_reg_raw(0x2200).await.unwrap();
|
||||||
|
// info!("FIFOCNTSTA: {}", (test>>16) & 0b111_1111_1111);
|
||||||
|
|
||||||
|
let mut data: [u32; 4] = [0; 4];
|
||||||
|
data[0] = ad5940.read_reg(ad5940::Register::DATAFIFORD).await.unwrap();
|
||||||
|
data[1] = ad5940.read_reg(ad5940::Register::DATAFIFORD).await.unwrap();
|
||||||
|
data[2] = ad5940.read_reg(ad5940::Register::DATAFIFORD).await.unwrap();
|
||||||
|
data[3] = ad5940.read_reg(ad5940::Register::DATAFIFORD).await.unwrap();
|
||||||
|
|
||||||
|
let result = calculate_impedance(data);
|
||||||
|
|
||||||
|
// You’ll need to implement your own logging or send this over serial in embedded
|
||||||
|
info!("Impedance: Magnitude = {} Ω, Phase = {} rad", result.magnitude, result.phase);
|
||||||
|
|
||||||
|
// let test = ad5940.read_reg_raw(0x2200).await.unwrap();
|
||||||
|
// info!("FIFOCNTSTA: {}", (test>>16) & 0b111_1111_1111);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,3 +217,71 @@ async fn green_led(mut led: Output<'static>) {
|
|||||||
led.toggle();
|
led.toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[embassy_executor::task]
|
||||||
|
async fn ad5940_readout_task(mut pin: ExtiInput<'static>) {
|
||||||
|
loop {
|
||||||
|
pin.wait_for_falling_edge().await;
|
||||||
|
info!("AD5940 interrupt triggered!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern crate libm;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct Complex {
|
||||||
|
real: i32,
|
||||||
|
imag: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ImpedanceResult {
|
||||||
|
pub magnitude: f32,
|
||||||
|
pub phase: f32,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example Rcal value (Ohms)
|
||||||
|
const RCAL_VAL: f32 = 1000.0;
|
||||||
|
|
||||||
|
/// Convert raw 18-bit 2's complement value to signed i32
|
||||||
|
fn sign_extend_18bit(val: u32) -> i32 {
|
||||||
|
let masked = val & 0x3FFFF;
|
||||||
|
if masked & (1 << 17) != 0 {
|
||||||
|
(masked | 0xFFFC0000) as i32
|
||||||
|
} else {
|
||||||
|
masked as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calculate magnitude and phase of Rz using Rcal reference
|
||||||
|
pub fn calculate_impedance(data: [u32; 4]) -> ImpedanceResult {
|
||||||
|
let mut signed_data = [0i32; 4];
|
||||||
|
for (i, &val) in data.iter().enumerate() {
|
||||||
|
signed_data[i] = sign_extend_18bit(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dft_rcal = Complex {
|
||||||
|
real: signed_data[0],
|
||||||
|
imag: signed_data[1],
|
||||||
|
};
|
||||||
|
|
||||||
|
let dft_rz = Complex {
|
||||||
|
real: signed_data[2],
|
||||||
|
imag: signed_data[3],
|
||||||
|
};
|
||||||
|
|
||||||
|
let rcal_mag = libm::sqrtf((dft_rcal.real as f32) * (dft_rcal.real as f32)
|
||||||
|
+ (dft_rcal.imag as f32) * (dft_rcal.imag as f32));
|
||||||
|
|
||||||
|
let rz_mag = libm::sqrtf((dft_rz.real as f32) * (dft_rz.real as f32)
|
||||||
|
+ (dft_rz.imag as f32) * (dft_rz.imag as f32));
|
||||||
|
|
||||||
|
let rcal_phase = libm::atan2f(-(dft_rcal.imag as f32), dft_rcal.real as f32);
|
||||||
|
let rz_phase = libm::atan2f(-(dft_rz.imag as f32), dft_rz.real as f32);
|
||||||
|
|
||||||
|
let magnitude = (rcal_mag / rz_mag) * RCAL_VAL;
|
||||||
|
let phase = rcal_phase - rz_phase;
|
||||||
|
|
||||||
|
ImpedanceResult { magnitude, phase }
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user