#![no_std] #![no_main] #![feature(type_alias_impl_trait, async_fn_in_trait)] use core::cell::Cell; use cortex_m::prelude::_embedded_hal_blocking_delay_DelayUs; use {defmt_rtt as _, panic_probe as _}; use {embassy_executor as executor, embassy_stm32 as stm32}; use ads1256::standard::input::SingleEnded; use ads1256::{ AdControl, Ads1256, AutoCal, BitOrder, Buffer, ClockOut, Config, DState, DataRate, DigitalIo, DigitalIoDirection, DigitalIoState, Gain, Multiplexer, MuxInput, Sdcs, Status, }; use embassy_time::{Delay, Duration, Timer}; use executor::Spawner; use stm32::dma::NoDma; use stm32::exti::ExtiInput; use stm32::gpio::{Input, Level, Output, Pull, Speed}; use stm32::spi::Spi; use stm32::time::Hertz; use stm32::{pac, spi}; use uom::si::electric_potential::volt; use uom::si::f32; use defmt::info; use embassy_executor::_export::StaticCell; use embassy_stm32::peripherals::{EXTI6, PF6, PF7, SPI3}; use embassy_sync::blocking_mutex::raw::NoopRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::pubsub::PubSubChannel; use physical_ads1256::standard::multiplexer::poll::{ AutocalPoll, AutocalPollStatePub, ModInputOnly, }; use physical_node::transducer::input::Poll; use physical_node::transducer::{Publish, Publisher, StatefulPublisher}; const AUTOCAL_CONF: Config = Config { status: Status::setting(Buffer::Enabled, AutoCal::Enabled, BitOrder::MostSigFirst), multiplexer: Multiplexer::setting(MuxInput::AIn0, MuxInput::Common), ad_control: AdControl::setting(Gain::X2, Sdcs::Off, ClockOut::Off), data_rate: DataRate::Sps2_5, digital_io: DigitalIo::setting(DigitalIoState::default(), DigitalIoDirection::default()), }; struct Ads1256Delay; impl ads1256::BlockingDelay for Ads1256Delay { #[inline] fn t6_delay(&mut self) { Delay.delay_us(1u32); } fn t11_1_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 { ai1: ExampleInput, ai2: ExampleInput, ai3: ExampleInput, } // Inputs static ANALOG_INPUTS: StaticCell = StaticCell::new(); static ADS_1256: StaticCell< Mutex, ExtiInput>>, > = StaticCell::new(); static SPI: StaticCell>> = StaticCell::new(); #[embassy_executor::main] async fn main(spawner: Spawner) { unsafe { pac::FLASH.acr().modify(|v| { v.set_prften(true); v.set_icen(true); v.set_dcen(true); }); } let p = embassy_stm32::init(Default::default()); let mut spi_conf = spi::Config::default(); spi_conf.mode = spi::MODE_1; spi_conf.bit_order = spi::BitOrder::MsbFirst; 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 spi = SPI.init(Mutex::new(Spi::new( p.SPI3, p.PC10, p.PC12, p.PC11, NoDma, NoDma, Hertz(ads1256::defaults::SPI_CLK_HZ), spi_conf, ))); let ads_1256 = ADS_1256.init(Mutex::new(Ads1256::new(Ads1256Delay, select_ads1256, ads1256_data_ready))); ads_1256 .get_mut() .write_config(spi.get_mut(), AUTOCAL_CONF) .unwrap(); let inputs = &*ANALOG_INPUTS.init(Inputs { ai1: AutocalPollStatePub { poll: AutocalPoll::new( ModInputOnly { gain: Gain::X2, multiplexer: SingleEnded::AIn1.into(), }, ads_1256, spi, ), publisher: PubSubChannel::new().into(), state: Cell::new(f32::ElectricPotential::new::(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::(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::(f32::NAN)).into(), }, }); spawner.spawn(log_task(&inputs.ai1, 1)).unwrap(); spawner.spawn(log_task(&inputs.ai2, 2)).unwrap(); spawner.spawn(log_task(&inputs.ai3, 3)).unwrap(); spawner .spawn(poll_task(&inputs.ai1, 1, Duration::from_secs(5))) .unwrap(); spawner .spawn(poll_task(&inputs.ai2, 2, Duration::from_secs(10))) .unwrap(); spawner .spawn(poll_task(&inputs.ai3, 3, Duration::from_secs(20))) .unwrap(); } #[embassy_executor::task(pool_size = 3)] async fn poll_task(input: &'static ExampleInput, input_num: u8, every: Duration) { loop { Timer::after(every).await; let result = input.poll().await.unwrap().get::(); info!("ai{} poll result: {} volts", input_num, result); } } #[embassy_executor::task(pool_size = 3)] async fn log_task(input: &'static ExampleInput, input_num: u8) { let mut subscriber = input.subscribe().unwrap(); loop { let msg = subscriber.next_message_pure().await.get::(); info!("Log task ai{}: {}", input_num, msg); } }