diff --git a/Cargo.lock b/Cargo.lock index 40f143f0..83bbf76f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -374,6 +374,7 @@ dependencies = [ "defmt", "embassy-sync 0.6.0", "heapless", + "hyped_adc", "hyped_core", "hyped_gpio", "hyped_i2c", diff --git a/boards/stm32l432kc/Cargo.lock b/boards/stm32l432kc/Cargo.lock index 5cff0fcf..139b55fb 100644 --- a/boards/stm32l432kc/Cargo.lock +++ b/boards/stm32l432kc/Cargo.lock @@ -543,6 +543,14 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "hyped_adc" +version = "0.1.0" +dependencies = [ + "embassy-sync 0.6.1", + "heapless", +] + [[package]] name = "hyped_boards_stm32l432kc" version = "0.1.0" @@ -585,6 +593,7 @@ name = "hyped_gpio" version = "0.1.0" dependencies = [ "heapless", + "hyped_core", ] [[package]] @@ -602,6 +611,7 @@ dependencies = [ "defmt", "embassy-sync 0.6.0", "heapless", + "hyped_adc", "hyped_core", "hyped_gpio", "hyped_i2c", diff --git a/boards/stm32l432kc/src/bin/current_levitation_test.rs b/boards/stm32l432kc/src/bin/current_levitation_test.rs new file mode 100644 index 00000000..982566c9 --- /dev/null +++ b/boards/stm32l432kc/src/bin/current_levitation_test.rs @@ -0,0 +1,52 @@ +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_stm32::adc::Adc; +use embassy_sync::{ + blocking_mutex::{ + raw::{CriticalSectionRawMutex, NoopRawMutex}, + Mutex, + }, + watch::Watch, +}; +use embassy_time::{Duration, Timer}; +use hyped_boards_stm32l432kc::tasks::current_levitation::read_current_levitation; +use hyped_sensors::{current_levitation::CurrentLevitation, SensorValueRange::*}; +use {defmt_rtt as _, panic_probe as _}; + +static CURRENT_LEVITATION_READING: Watch, 1> = + Watch::new(); + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> { + let p = embassy_stm32::init(Default::default()); + let adc = Adc::new(p.ADC1, Delay); + + // Create a sender to pass to the current levitation reading task, and a receiver for reading the values back. + let current_levitation_reading_sender = CURRENT_LEVITATION_READING.sender(); + let mut current_levitation_reading_receiver = CURRENT_LEVITATION_READING.receiver().unwrap(); + + spawner + .spawn(read_current_levitation(current_levitation_reading_sender)) + .unwrap(); + + // Every 100ms we read for the latest value from the current levitation sensor. + loop { + match current_levitation_reading_receiver.try_changed() { + Some(reading) => match reading { + Safe(value) => { + defmt::info!("Current: {} A (safe)", value) + } + Warning(value) => { + defmt::warn!("Current: {} A (warning)", value) + } + Critical(value) => { + defmt::error!("Current: {} A (critical)", value) + } + None => (), + } + } + Timer::after(Duration::from_millis(100)).await; + } +} \ No newline at end of file diff --git a/boards/stm32l432kc/src/tasks.rs b/boards/stm32l432kc/src/tasks.rs index e69de29b..e83afb53 100644 --- a/boards/stm32l432kc/src/tasks.rs +++ b/boards/stm32l432kc/src/tasks.rs @@ -0,0 +1 @@ +pub mod current_levitation; diff --git a/boards/stm32l432kc/src/tasks/read_current_levitation.rs b/boards/stm32l432kc/src/tasks/read_current_levitation.rs new file mode 100644 index 00000000..6751959d --- /dev/null +++ b/boards/stm32l432kc/src/tasks/read_current_levitation.rs @@ -0,0 +1,27 @@ +use embassy_stm32::adc::Adc; +use embassy_time::Delay; +use hyped_sensors::{current_levitation::CurrentLevitation, SensorValueRange::*}; +use defmt_rtt as _; +use embassy_sync::{ + blocking_mutex::{ + raw::{CriticalSectionRawMutex, NoopRawMutex}, + Mutex, + }, + watch::Sender, +}; + + +/// Test task that reads the current and sends it with the Watch Sender +#[embassy_executor::task] +pub async fn read_current_levitation( + sender: Sender<'static, CriticalSectionRawMutex, SensorValueRange, 1>, +) -> ! { + let p = embassy_stm32::init(Default::default()); + let adc = Adc::new(p.ADC1, Delay); + + let mut current_levitation_sensor = CurrentLevitation::new(&mut adc); + + loop { + sender.send(current_levitation_sensor.read()) + } + } diff --git a/lib/sensors/Cargo.toml b/lib/sensors/Cargo.toml index e3c5b5fa..2ba16cbb 100644 --- a/lib/sensors/Cargo.toml +++ b/lib/sensors/Cargo.toml @@ -9,6 +9,7 @@ embassy-sync = { version = "0.6.0", features = ["defmt"], git = "https://github. hyped_core = { path = "../core" } hyped_i2c = { path = "../io/hyped_i2c" } hyped_gpio = { path = "../io/hyped_gpio" } +hyped_adc = { path = "../io/hyped_adc" } defmt = "0.3" [dev-dependencies] diff --git a/lib/sensors/src/current_levitation.rs b/lib/sensors/src/current_levitation.rs new file mode 100644 index 00000000..26083710 --- /dev/null +++ b/lib/sensors/src/current_levitation.rs @@ -0,0 +1,53 @@ +use crate::SensorValueRange; +use hyped_adc::HypedAdc; + +/// current_levitation implements the logic to read current from the ACHS-7121 current sensor using the +/// Hyped ADC trait. +/// +/// Data sheet: https://docs.broadcom.com/doc/ACHS-712x-DS +pub struct CurrentLevitation { + adc: T, + calculate_bounds: fn(f32) -> SensorValueRange, +} + +impl CurrentLevitation { + /// Create a new instance of the Current Levitation sensor + pub fn new(adc: T) -> CurrentLevitation { + Self::new_with_bounds(adc, default_calculate_bounds) + } + + pub fn new_with_bounds( + adc: T, + calculate_bounds: fn(f32) -> SensorValueRange, + ) -> CurrentLevitation { + CurrentLevitation { + adc, + calculate_bounds, + } + } + /// The ACHS-7121 has a current range of +- 10 A, sensitivity of 185 mV/A. + /// Assuming we're supplying 5V to the sensor, our off-set is 2.5V in the output reading - note that this offset is given + /// by the supply voltage divided by 2, so if you change the supply voltage, you'll have to change the offset that we subtract + /// in the read function accordingly. + pub fn read(&mut self) -> SensorValueRange { + let current = self.adc.read_value() as f32; + (self.calculate_bounds)((current - OFFSET) / SENSITIVITY) + } +} + +pub fn default_calculate_bounds(value: f32) -> SensorValueRange { + if value <= MIN_AMPS || value >= MAX_AMPS { + SensorValueRange::Critical(value) + } else if value <= WARN_AMPS_LOW || value >= WARN_AMPS_HIGH { + SensorValueRange::Warning(value) + } else { + SensorValueRange::Safe(value) + } +} + +const OFFSET: f32 = 2.5; +const SENSITIVITY: f32 = 0.185; +const MIN_AMPS: f32 = 10.0; +const MAX_AMPS: f32 = -10.0; +const WARN_AMPS_LOW: f32 = -8.0; +const WARN_AMPS_HIGH: f32 = 8.0; diff --git a/lib/sensors/src/lib.rs b/lib/sensors/src/lib.rs index bc516606..e8115c62 100644 --- a/lib/sensors/src/lib.rs +++ b/lib/sensors/src/lib.rs @@ -1,5 +1,6 @@ #![no_std] +pub mod current_levitation; pub mod keyence; pub mod temperature; pub mod time_of_flight;