Initial node implementation #4

Merged
zack merged 51 commits from develop into master 2023-07-19 18:09:13 +00:00
36 changed files with 1642 additions and 44 deletions
Showing only changes of commit 359b75cba8 - Show all commits

View File

@ -101,15 +101,15 @@ async fn main(spawner: Spawner) {
let inputs = &*ANALOG_INPUTS.init(Inputs { let inputs = &*ANALOG_INPUTS.init(Inputs {
ai1: StatefulPublisher::new( ai1: StatefulPublisher::new(
Cell::new(f32::ElectricPotential::new::<volt>(-1000.0)).into(), Cell::new(f32::ElectricPotential::new::<volt>(f32::NAN)).into(),
PubSubChannel::new().into(), PubSubChannel::new().into(),
), ),
ai2: StatefulPublisher::new( ai2: StatefulPublisher::new(
Cell::new(f32::ElectricPotential::new::<volt>(-1000.0)).into(), Cell::new(f32::ElectricPotential::new::<volt>(f32::NAN)).into(),
PubSubChannel::new().into(), PubSubChannel::new().into(),
), ),
ai3: StatefulPublisher::new( ai3: StatefulPublisher::new(
Cell::new(f32::ElectricPotential::new::<volt>(-1000.0)).into(), Cell::new(f32::ElectricPotential::new::<volt>(f32::NAN)).into(),
PubSubChannel::new().into(), PubSubChannel::new().into(),
), ),
}); });

View File

@ -10,12 +10,12 @@ use {defmt_rtt as _, panic_probe as _};
use {embassy_executor as executor, embassy_stm32 as stm32}; use {embassy_executor as executor, embassy_stm32 as stm32};
use ads1256::standard::input::SingleEnded;
use ads1256::{ use ads1256::{
AdControl, Ads1256, AutoCal, BitOrder, BlockingDelay, Buffer, ClockOut, Config, DState, AdControl, Ads1256, AutoCal, BitOrder, BlockingDelay, Buffer, ClockOut, Config, DState,
DataRate, DigitalIo, DigitalIoDirection, DigitalIoState, DioDirection, Gain, Multiplexer, DataRate, DigitalIo, DigitalIoDirection, DigitalIoState, DioDirection, Gain, Multiplexer,
MuxInput, OutputPin, Sdcs, SpiBus, Status, Wait, MuxInput, OutputPin, Sdcs, SpiBus, Status, Wait,
}; };
use ads1256::standard::input::SingleEnded;
use embassy_time::{Delay, Duration, Timer}; use embassy_time::{Delay, Duration, Timer};
use executor::Spawner; use executor::Spawner;
use stm32::dma::NoDma; use stm32::dma::NoDma;
@ -32,8 +32,12 @@ use defmt::{debug, error, info, trace, unwrap};
use embassy_executor::_export::StaticCell; use embassy_executor::_export::StaticCell;
use embassy_stm32::peripherals::{EXTI6, PF6, PF7, SPI3}; use embassy_stm32::peripherals::{EXTI6, PF6, PF7, SPI3};
use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::blocking_mutex::raw::NoopRawMutex;
use embassy_sync::mutex::Mutex;
use embassy_sync::pubsub::PubSubChannel; use embassy_sync::pubsub::PubSubChannel;
use physical_node::transducer::{Publish, StatefulPublisher}; use physical_ads1256::standard::multiplexer::poll::{
AutocalPoll, AutocalPollStatePub, ModInputOnly,
};
use physical_node::transducer::{Publish, Publisher, StatefulPublisher};
const AUTOCAL_CONF: Config = Config { const AUTOCAL_CONF: Config = Config {
status: Status::setting(Buffer::Enabled, AutoCal::Enabled, BitOrder::MostSigFirst), status: Status::setting(Buffer::Enabled, AutoCal::Enabled, BitOrder::MostSigFirst),
@ -56,16 +60,31 @@ impl ads1256::BlockingDelay for Ads1256Delay {
fn t11_2_delay(&mut self) {} fn t11_2_delay(&mut self) {}
} }
type ExampleInput = AutocalPollStatePub<
'static,
NoopRawMutex,
NoopRawMutex,
ModInputOnly,
Ads1256Delay,
Output<'static, PF7>,
ExtiInput<'static, PF6>,
Spi<'static, SPI3, NoDma, NoDma>,
10,
1,
>;
struct Inputs { struct Inputs {
ai1: StatefulPublisher<f32::ElectricPotential, NoopRawMutex, 10, 1>, ai1: ExampleInput,
ai2: StatefulPublisher<f32::ElectricPotential, NoopRawMutex, 10, 1>, ai2: ExampleInput,
ai3: StatefulPublisher<f32::ElectricPotential, NoopRawMutex, 10, 1>, ai3: ExampleInput,
} }
// Inputs // Inputs
static ANALOG_INPUTS: StaticCell<Inputs> = StaticCell::new(); static ANALOG_INPUTS: StaticCell<Inputs> = StaticCell::new();
static ADS_1256: StaticCell<Ads1256<Ads1256Delay, Output<PF7>, ExtiInput<PF6>>> = StaticCell::new(); static ADS_1256: StaticCell<
static SPI: StaticCell<Spi<SPI3, NoDma, NoDma>> = StaticCell::new(); Mutex<NoopRawMutex, Ads1256<Ads1256Delay, Output<PF7>, ExtiInput<PF6>>>,
> = StaticCell::new();
static SPI: StaticCell<Mutex<NoopRawMutex, Spi<SPI3, NoDma, NoDma>>> = StaticCell::new();
#[embassy_executor::main] #[embassy_executor::main]
async fn main(spawner: Spawner) { async fn main(spawner: Spawner) {
@ -86,7 +105,7 @@ async fn main(spawner: Spawner) {
let ads1256_data_ready = ExtiInput::new(Input::new(p.PF6, Pull::Up), p.EXTI6); let ads1256_data_ready = ExtiInput::new(Input::new(p.PF6, Pull::Up), p.EXTI6);
let select_ads1256 = Output::new(p.PF7, Level::High, Speed::VeryHigh); let select_ads1256 = Output::new(p.PF7, Level::High, Speed::VeryHigh);
let spi = SPI.init(Spi::new( let spi = &*SPI.init(Mutex::new(Spi::new(
p.SPI3, p.SPI3,
p.PC10, p.PC10,
p.PC12, p.PC12,
@ -95,86 +114,48 @@ async fn main(spawner: Spawner) {
NoDma, NoDma,
Hertz(ads1256::defaults::SPI_CLK_HZ), Hertz(ads1256::defaults::SPI_CLK_HZ),
spi_conf, spi_conf,
)); )));
let ads_1256 = ADS_1256.init(Ads1256::new(Ads1256Delay, select_ads1256, ads1256_data_ready)); let ads_1256 =
&*ADS_1256.init(Mutex::new(Ads1256::new(Ads1256Delay, select_ads1256, ads1256_data_ready)));
let inputs = &*ANALOG_INPUTS.init(Inputs { let inputs = &*ANALOG_INPUTS.init(Inputs {
ai1: StatefulPublisher::new( ai1: AutocalPollStatePub {
Cell::new(f32::ElectricPotential::new::<volt>(-1000.0)).into(), poll: AutocalPoll::new(
PubSubChannel::new().into(), ModInputOnly {
), gain: Gain::X2,
ai2: StatefulPublisher::new( multiplexer: SingleEnded::AIn1.into(),
Cell::new(f32::ElectricPotential::new::<volt>(-1000.0)).into(), },
PubSubChannel::new().into(), ads_1256,
), spi,
ai3: StatefulPublisher::new( ),
Cell::new(f32::ElectricPotential::new::<volt>(-1000.0)).into(), publisher: PubSubChannel::new().into(),
PubSubChannel::new().into(), state: Cell::new(f32::ElectricPotential::new::<volt>(f32::NAN)).into(),
), },
ai2: AutocalPollStatePub {
poll: AutocalPoll::new(
ModInputOnly {
gain: Gain::X2,
multiplexer: SingleEnded::AIn2.into(),
},
ads_1256,
spi,
),
publisher: PubSubChannel::new().into(),
state: Cell::new(f32::ElectricPotential::new::<volt>(f32::NAN)).into(),
},
ai3: AutocalPollStatePub {
poll: AutocalPoll::new(
ModInputOnly {
gain: Gain::X2,
multiplexer: SingleEnded::AIn3.into(),
},
ads_1256,
spi,
),
publisher: PubSubChannel::new().into(),
state: Cell::new(f32::ElectricPotential::new::<volt>(f32::NAN)).into(),
},
}); });
spawner.spawn(log_task(inputs)).unwrap();
spawner
.spawn(drive_inputs_task(ads_1256, spi, inputs))
.unwrap();
}
#[embassy_executor::task]
async fn drive_inputs_task(
ads_1256: &'static mut Ads1256<Ads1256Delay, Output<'static, PF7>, ExtiInput<'static, PF6>>,
spi: &'static mut Spi<'static, SPI3, NoDma, NoDma>,
inputs: &'static Inputs,
) {
let Inputs { ai1, ai2, ai3 } = inputs;
loop {
let mut accumulator = f32::ElectricPotential::new::<volt>(0.0);
let voltage = ads_1256
.autocal_convert(spi, SingleEnded::AIn0.into(), None, None, None, false)
.await
.unwrap()
.to_voltage(AUTOCAL_CONF.ad_control.gain());
ai1.update(voltage);
accumulator += voltage;
let voltage = ads_1256
.autocal_convert(spi, SingleEnded::AIn1.into(), None, None, None, false)
.await
.unwrap()
.to_voltage(AUTOCAL_CONF.ad_control.gain());
ai2.update(voltage);
accumulator += voltage;
let voltage = ads_1256
.autocal_convert(spi, SingleEnded::AIn2.into(), None, None, None, false)
.await
.unwrap()
.to_voltage(AUTOCAL_CONF.ad_control.gain());
ai3.update(voltage);
accumulator += voltage;
let accum_volts = accumulator.get::<volt>();
info!("Immediate loop iteration result, combined volts: {}", accum_volts);
}
}
#[embassy_executor::task]
async fn log_task(inputs: &'static Inputs) {
let Inputs { ai1, ai2, ai3 } = inputs;
let mut ai1_sub = ai1.subscribe().unwrap();
let mut ai2_sub = ai2.subscribe().unwrap();
let mut ai3_sub = ai3.subscribe().unwrap();
loop {
let msg = ai1_sub.next_message_pure().await.get::<volt>();
info!("Log task ai1: {}", msg);
let msg = ai2_sub.next_message_pure().await.get::<volt>();
info!("Log task ai2: {}", msg);
let msg = ai3_sub.next_message_pure().await.get::<volt>();
info!("Log task ai3: {}", msg);
}
} }

View File

@ -1,2 +1,2 @@
#[cfg(feature = "standard-input")] #[cfg(feature = "standard-multiplexer")]
pub mod multiplexer; pub mod multiplexer;

View File

@ -25,6 +25,30 @@ where
spi: &'a Mutex<DeviceMutexT, SpiT>, spi: &'a Mutex<DeviceMutexT, SpiT>,
} }
impl<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
where
DeviceMutexT: RawMutex,
ModInT: ModInput,
DelayerT: BlockingDelay,
SST: OutputPin,
DrdyT: Wait,
SpiT: SpiBus,
{
#[inline(always)]
pub fn new(
input_mod: ModInT,
ads1256: &'a Mutex<DeviceMutexT, Ads1256<DelayerT, SST, DrdyT>>,
spi: &'a Mutex<DeviceMutexT, SpiT>,
) -> Self {
Self {
input_mod,
ads1256,
spi,
}
}
}
impl<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT> Poll impl<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT> Poll
for AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT> for AutocalPoll<'a, DeviceMutexT, ModInT, DelayerT, SST, DrdyT, SpiT>
where where
@ -40,6 +64,7 @@ where
async fn poll(&self) -> Result<Self::Value, CriticalError> { async fn poll(&self) -> Result<Self::Value, CriticalError> {
let mut ads1256_guard = self.ads1256.lock().await; let mut ads1256_guard = self.ads1256.lock().await;
let ads1256 = ads1256_guard.deref_mut(); let ads1256 = ads1256_guard.deref_mut();
ads1256.data_ready.wait_for_low().await;
let result = ads1256 let result = ads1256
.autocal_convert_m( .autocal_convert_m(
@ -71,6 +96,36 @@ pub trait ModInput: Copy {
fn data_rate(self) -> Option<DataRate>; fn data_rate(self) -> Option<DataRate>;
} }
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct ModInputOnly {
pub multiplexer: Multiplexer,
/// Only used for converting to voltage, this value must match what is set on the ADS1256, it
/// will not *be* set unlike the other fields.
pub gain: Gain,
}
impl ModInput for ModInputOnly {
fn multiplexer(self) -> Multiplexer {
self.multiplexer
}
fn gain(self) -> Gain {
self.gain
}
fn status(self) -> Option<Status> {
None
}
fn ad_control(self) -> Option<AdControl> {
None
}
fn data_rate(self) -> Option<DataRate> {
None
}
}
/// buffer /// buffer
#[derive(Copy, Clone, Eq, PartialEq)] #[derive(Copy, Clone, Eq, PartialEq)]
pub struct ModInStatus { pub struct ModInStatus {