diff --git a/Cargo.lock b/Cargo.lock index 07fb129..3b66a63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -39,14 +39,19 @@ dependencies = [ name = "bioz-firmware-rs" version = "0.1.0" dependencies = [ + "bitflags 2.9.1", "cortex-m", "cortex-m-rt", "defmt 1.0.1", "defmt-rtt", + "embassy-embedded-hal", "embassy-executor", "embassy-stm32", + "embassy-sync 0.7.0", "embassy-time", + "embedded-hal 1.0.0", "panic-probe", + "static_cell", ] [[package]] @@ -230,13 +235,14 @@ dependencies = [ [[package]] name = "embassy-embedded-hal" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fea5ef5bed4d3468dfd44f5c9fa4cda8f54c86d4fb4ae683eacf9d39e2ea12" +checksum = "8578db196d74db92efdd5ebc546736dac1685499ee245b22eff92fa5e4b57945" dependencies = [ - "defmt 0.3.100", + "defmt 1.0.1", "embassy-futures", - "embassy-sync", + "embassy-hal-internal 0.3.0", + "embassy-sync 0.7.0", "embassy-time", "embedded-hal 0.2.7", "embedded-hal 1.0.0", @@ -289,6 +295,15 @@ dependencies = [ "num-traits", ] +[[package]] +name = "embassy-hal-internal" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95285007a91b619dc9f26ea8f55452aa6c60f7115a4edc05085cd2bd3127cd7a" +dependencies = [ + "num-traits", +] + [[package]] name = "embassy-net-driver" version = "0.2.0" @@ -317,9 +332,9 @@ dependencies = [ "embassy-embedded-hal", "embassy-executor", "embassy-futures", - "embassy-hal-internal", + "embassy-hal-internal 0.2.0", "embassy-net-driver", - "embassy-sync", + "embassy-sync 0.6.2", "embassy-time", "embassy-time-driver", "embassy-time-queue-utils", @@ -362,6 +377,21 @@ dependencies = [ "heapless", ] +[[package]] +name = "embassy-sync" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef1a8a1ea892f9b656de0295532ac5d8067e9830d49ec75076291fd6066b136" +dependencies = [ + "cfg-if", + "critical-section", + "defmt 1.0.1", + "embedded-io-async", + "futures-sink", + "futures-util", + "heapless", +] + [[package]] name = "embassy-time" version = "0.4.0" @@ -415,7 +445,7 @@ checksum = "08e753b23799329780c7ac434264026d0422044d6649ed70a73441b14a6436d7" dependencies = [ "critical-section", "defmt 0.3.100", - "embassy-sync", + "embassy-sync 0.6.2", "embassy-usb-driver", ] @@ -610,6 +640,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + [[package]] name = "proc-macro-error-attr2" version = "2.0.0" @@ -698,6 +734,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "static_cell" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0530892bb4fa575ee0da4b86f86c667132a94b74bb72160f58ee5a4afec74c23" +dependencies = [ + "portable-atomic", +] + [[package]] name = "stm32-fmc" version = "0.3.2" diff --git a/Cargo.toml b/Cargo.toml index 6b4057b..44063c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,9 +6,10 @@ edition = "2021" [dependencies] # 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-sync = { version = "0.7.0", features = ["defmt"] } +embassy-sync = { version = "0.7.0", features = ["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-embedded-hal = { version = "0.3.1", features = ["defmt"] } # embassy-net = { version = "0.7.0", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6"] } # embassy-usb = { version = "0.4.0", features = ["defmt"] } # embassy-futures = { version = "0.1.0"} @@ -21,7 +22,7 @@ bitflags = "2.9.1" cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } cortex-m-rt = "0.7.0" # embedded-hal = "0.2.6" -# embedded-hal-1 = { package = "embedded-hal", version = "1.0" } +embedded-hal-1 = { package = "embedded-hal", version = "1.0" } # embedded-hal-async = { version = "1.0" } # embedded-io-async = { version = "0.6.1" } # embedded-nal-async = "0.8.0" @@ -31,7 +32,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] } # micromath = "2.0.0" # stm32-fmc = "0.3.0" # embedded-storage = "0.3.1" -# static_cell = "2" +static_cell = "2" # # cargo build/run # [profile.dev] diff --git a/src/adg2128.rs b/src/adg2128.rs new file mode 100644 index 0000000..e8d098d --- /dev/null +++ b/src/adg2128.rs @@ -0,0 +1,160 @@ +use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; +use embassy_stm32::{i2c::I2c, mode::Blocking}; +use embassy_sync::blocking_mutex::raw::NoopRawMutex; + +use embedded_hal_1::i2c::I2c as _; + +#[derive(Copy, Clone)] +#[allow(dead_code)] +pub enum SetX { + X0 = 0b0000, + X1, + X2, + X3, + X4, + X5, + X6 = 0b1000, + X7, + X8, + X9, + X10, + X11, +} + +impl SetX{ + pub fn from_u8(value: u8) -> Self { + const VARIANTS: [SetX; 12] = [ + SetX::X0, SetX::X1, SetX::X2, SetX::X3, + SetX::X4, SetX::X5, SetX::X6, SetX::X7, + SetX::X8, SetX::X9, SetX::X10, SetX::X11, + ]; + + *VARIANTS.get(value as usize).expect("Invalid value for SetX") + } +} + +#[derive(Copy, Clone)] +#[allow(dead_code)] +pub enum SetY { + Y0 = 0b000, + Y1, + Y2, + Y3, + Y4, + Y5, + Y6, + Y7, +} + +impl SetY { + pub fn from_u8(value: u8) -> Self { + const VARIANTS: [SetY; 8] = [ + SetY::Y0, SetY::Y1, SetY::Y2, SetY::Y3, + SetY::Y4, SetY::Y5, SetY::Y6, SetY::Y7, + ]; + + *VARIANTS.get(value as usize).expect("Invalid value for SetY") + } +} + +#[derive(Copy, Clone)] +#[allow(dead_code)] +pub enum GetX { + X0 = 0b0011_0100, + X1 = 0b0011_1100, + X2 = 0b0111_0100, + X3 = 0b0111_1100, + X4 = 0b0011_0101, + X5 = 0b0011_1101, + X6 = 0b0111_0101, + X7 = 0b0111_1101, + X8 = 0b0011_0110, + X9 = 0b0011_1110, + X10 = 0b0111_0110, + X11 = 0b0111_1110, +} + +impl GetX { + pub fn from_u8(value: u8) -> Self { + const VARIANTS: [GetX; 12] = [ + GetX::X0, GetX::X1, GetX::X2, GetX::X3, + GetX::X4, GetX::X5, GetX::X6, GetX::X7, + GetX::X8, GetX::X9, GetX::X10, GetX::X11, + ]; + + *VARIANTS.get(value as usize).expect("Invalid value for GetX") + } +} + +#[allow(dead_code)] +pub enum State { + DISABLED = 0b0, + ENABLED = 0b1, +} + +#[allow(dead_code)] +enum LDSW { + EN = 0b1, + DIS = 0b0, +} + +pub struct ADG2128 { + i2c: I2cDevice<'static, NoopRawMutex, I2c<'static, Blocking>>, + address: u8, + states_xy: [u8; 12] +} + +impl ADG2128 { + pub fn new(i2c: I2cDevice<'static, NoopRawMutex, I2c<'static, Blocking>>, address: u8) -> Self { + ADG2128 { i2c, address, states_xy: [0u8; 12]} + } + + pub fn set(&mut self, io_1: SetX, io_2: SetY, state: State) { + let mut data = [0u8; 2]; + data[0] = (state as u8) << 7 | (io_1 as u8) << 3 | (io_2 as u8); + data[1] = LDSW::EN as u8; + self.i2c.write(self.address, &data).unwrap() + } + + pub fn get(&mut self, io: GetX) -> u8 { + let mut data_out = [0u8; 2]; + let mut data_in = [0u8; 2]; + data_out[0] = io as u8; + self.i2c.write_read(self.address, &mut data_out, &mut data_in).unwrap(); + + data_in[1] + } + + pub fn get_all(&mut self) -> [u8; 12] { + let mut states_xy = [0u8; 12]; + + for (x_line, y_states) in states_xy.iter_mut().enumerate() { + let x_line_data = GetX::from_u8(x_line as u8); + *y_states = self.get(x_line_data); + } + + self.states_xy.copy_from_slice(states_xy.as_slice()); + + states_xy + } + + pub fn reset_all(&mut self) { + let states_xy = self.get_all(); + + // Find bits that are set + for (x_line, &state) in states_xy.iter().enumerate() { + if state == 0 { + continue; // Skip zero states early + } + for value in 0..8 { + if (state >> value) & 1 == 1 { + self.set( + SetX::from_u8(x_line as u8), + SetY::from_u8(value), + State::DISABLED, + ); + } + } + } + } +} \ No newline at end of file diff --git a/src/electrodes.rs b/src/electrodes.rs new file mode 100644 index 0000000..3fde9cf --- /dev/null +++ b/src/electrodes.rs @@ -0,0 +1,88 @@ +use embassy_embedded_hal::shared_bus::blocking::i2c::I2cDevice; +use embassy_stm32::{i2c, mode::Blocking}; +use embassy_sync::blocking_mutex::NoopMutex; +use static_cell::StaticCell; +use core::cell::RefCell; + +use crate::{ad5940, adg2128::{GetX, SetX, SetY, State, ADG2128}}; + +static I2C_BUS: StaticCell>>> = StaticCell::new(); + +#[derive(Copy, Clone)] +#[allow(dead_code)] +pub enum Electrode { + E0, E1, E2, E3, E4, E5, E6, E7, + E8, E9, E10, E11, E12, E13, E14, E15, + E16, E17, E18, E19, E20, E21, E22, E23, +} + +impl Electrode { + pub fn from_u8(value: u8) -> Self { + const VARIANTS: [Electrode; 24] = [ + Electrode::E0, Electrode::E1, Electrode::E2, Electrode::E3, + Electrode::E4, Electrode::E5, Electrode::E6, Electrode::E7, + Electrode::E8, Electrode::E9, Electrode::E10, Electrode::E11, + Electrode::E12, Electrode::E13, Electrode::E14, Electrode::E15, + Electrode::E16, Electrode::E17, Electrode::E18, Electrode::E19, + Electrode::E20, Electrode::E21, Electrode::E22, Electrode::E23, + ]; + + *VARIANTS.get(value as usize).expect("Invalid value for SetX") + } +} + +#[derive(Copy, Clone)] +#[allow(dead_code)] +pub enum AD5940Pin { + CE0, RE0, SE0, DE0, + AIN0, AIN1, AIN2, AIN3, +} + +pub struct Electrodes { + mux_1: ADG2128, + mux_2: ADG2128, +} + +impl Electrodes { + pub fn new(i2c: i2c::I2c<'static, Blocking>) -> Self { + let i2c_bus = NoopMutex::new(RefCell::new(i2c)); + let i2c_bus = I2C_BUS.init(i2c_bus); + + Electrodes { + mux_1: ADG2128::new(I2cDevice::new(i2c_bus), 0b1110_000), + mux_2: ADG2128::new(I2cDevice::new(i2c_bus), 0b1110_001), + } + } + + pub fn set(&mut self, electrode: Electrode, ad5940_pin: AD5940Pin, state: State) { + let electrode = electrode as u8; + let ad5940_pin = ad5940_pin as u8; + match electrode { + 0..=11 => { + self.mux_1.set(SetX::from_u8(electrode), SetY::from_u8(ad5940_pin), state); + } + 12..=23 => { + self.mux_2.set(SetX::from_u8(electrode-12), SetY::from_u8(ad5940_pin), state); + } + _ => panic!("Invalid electrode number"), + } + } + + pub fn get(&mut self, io: Electrode) -> u8 { + let number = io as u8; + match number { + 0..=11 => self.mux_1.get(GetX::from_u8(number)), + 12..=23 => self.mux_2.get(GetX::from_u8(number-12)), + _ => panic!("Invalid electrode number"), + } + } + + pub fn get_all(&mut self) -> ([u8; 12], [u8; 12]) { + (self.mux_1.get_all(), self.mux_2.get_all()) + } + + pub fn reset_all(&mut self) { + self.mux_1.reset_all(); + self.mux_2.reset_all(); + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 5e61a74..6827c94 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,13 +4,20 @@ use defmt::*; use embassy_executor::Spawner; use embassy_stm32::gpio::{Level, Output, Speed}; -use embassy_stm32::{adc, spi, Config}; +use embassy_stm32::{i2c, spi, Config}; +use embassy_stm32::time::Hertz; use embassy_time::Timer; use {defmt_rtt as _, panic_probe as _}; mod ad5940; use ad5940::AD5940; +mod adg2128; +use adg2128::State; + +mod electrodes; +use electrodes::{Electrodes, Electrode, AD5940Pin}; + mod ad5940_registers; #[embassy_executor::main] @@ -34,6 +41,7 @@ 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 spi = spi::Spi::new_blocking( @@ -49,6 +57,21 @@ async fn main(_spawner: Spawner) { ad5940.init_temperature().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() + ); + + // Initialize electrodes + let mut electrodes = Electrodes::new(i2c); + electrodes.reset_all(); + electrodes.set(Electrode::E11, AD5940Pin::CE0, State::ENABLED); + electrodes.set(Electrode::E12, AD5940Pin::RE0, State::ENABLED); + loop { // Read chip id // let chip_id = ad5940.get_chipid().await.unwrap(); @@ -58,6 +81,9 @@ 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); + // info!("high"); // led.set_high(); Timer::after_millis(500).await;