use crate::{AdControl, Ads1256, BlockingDelay, CalibrationCommand, Conversion, DataRate, Multiplexer, Status, }; use core::ops::DerefMut; use embassy_sync::blocking_mutex::raw::RawMutex; use physical_node::GPIO_ERROR_MSG; use physical_node::spi::end_spi; use embassy_sync::mutex::Mutex; use embedded_hal::digital::OutputPin; use embedded_hal::spi; use embedded_hal::spi::SpiBus; use embedded_hal_async::digital::Wait; impl Ads1256 where DelayerT: BlockingDelay, SST: OutputPin, DrdyT: Wait, { /// Functionally the same as [Ads1256::cmd_read_data] but exercises fine-grained control /// over the [Mutex] of a [SpiBus] in cases where one is used. This function will unlock the /// [Mutex] while it is waiting for data from the ADS1256. /// /// Action sequence: /// 1. Wait for data_ready to go low /// 1. Lock mutex, mutably borrow SPI /// 1. Read the conversion value #[inline] pub async fn cmd_read_data_m( &mut self, spi: &Mutex, ) -> Result::Error> { self.data_ready.wait_for_low().await.expect(GPIO_ERROR_MSG); let mut spi_guard = spi.lock().await; let spi = spi_guard.deref_mut(); self.slave_select.set_low().expect(GPIO_ERROR_MSG); let spi_op_result = self.raw_cmd_read_data(spi); end_spi(&mut self.slave_select, spi, spi_op_result) } /// Functionally the same as [Ads1256::autocal_convert] but exercises fine-grained control /// over the [Mutex] of a [SpiBus] in cases where one is used. This function will unlock the /// [Mutex] while it is waiting for data from the ADS1256. /// /// Action sequence: /// 1. Switch inputs and optionally adjust different configuration parameters. /// 1. If only the input was switched without configuration changes. /// 1. Issue sync command followed by wakeup command /// 1. Else, auto-calibration will take place /// 1. Wait for data_ready low /// 1. RDATA command (read the conversion value) /// 1. Optionally enter standby mode /// /// **WARNING:** Auto-calibration must be enabled for intended functionality when changing /// [Status], [AdControl], or [DataRate]. Furthermore if setting [Status] or [AdControl], their /// [Buffer] and [Gain] settings must be modified respectively to trigger auto-calibration. #[inline] pub async fn autocal_convert_m( &mut self, spi_mutex: &Mutex, input: Multiplexer, status: Option, ad_control: Option, data_rate: Option, standby: bool, ) -> Result::Error> { // Acquire SPI lock let mut spi_guard = spi_mutex.lock().await; let spi = spi_guard.deref_mut(); // Slave select low self.slave_select.set_low().expect(GPIO_ERROR_MSG); match (status, ad_control, data_rate) { // Only modifying the multiplexer, not changing any configuration (None, None, None) => { self._none_config(spi, input)?; self._manual_conversion_init(spi)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer) and changing multiplexer (Some(status), None, None) => { self._status_config(spi, input, status)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying AD control (gain) and changing multiplexer (None, Some(ad_control), None) => { self._ad_config(spi, input, ad_control)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying data rate and change multiplexer (None, None, Some(data_rate)) => { self._drate_config(spi, input, data_rate)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer), AD control (gain), and changing multiplexer (Some(status), Some(ad_control), None) => { self._status_ad_config(spi, input, status, ad_control)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer), data rate, and changing multiplexer (Some(status), None, Some(data_rate)) => { self._status_drate_config(spi, input, status, data_rate)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying AD control (gain), data rate, and changing multiplexer (None, Some(ad_control), Some(data_rate)) => { self._ad_drate_config(spi, input, ad_control, data_rate)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer), AD control (gain), data rate, and changing // multiplexer (Some(status), Some(ad_control), Some(data_rate)) => { self._all_config(spi, input, status, ad_control, data_rate)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, } } /// Functionally the same as [Ads1256::loadcal_convert] but exercises fine-grained control /// over the [Mutex] of a [SpiBus] in cases where one is used. This function will unlock the /// [Mutex] while it is waiting for data from the ADS1256. /// /// Action sequence: /// 1. Switch inputs and optionally adjust different configuration parameters. /// 1. Issue sync command followed by wakeup command /// 1. Wait for data_ready low /// 1. RDATA command (read the conversion value) /// 1. Optionally enter standby mode /// /// **WARNING:** Auto-calibration must be disabled for intended functionality when changing /// [Status], [AdControl], or [DataRate]. #[inline] pub async fn loadcal_convert_m( &mut self, spi_mutex: &Mutex, input: Multiplexer, calibration: Option<&CalibrationCommand>, status: Option, ad_control: Option, data_rate: Option, standby: bool, ) -> Result::Error> { // Acquire SPI lock let mut spi_guard = spi_mutex.lock().await; let spi = spi_guard.deref_mut(); // Slave select low self.slave_select.set_low().expect(GPIO_ERROR_MSG); match (status, ad_control, data_rate) { // Only modifying the multiplexer, not changing any configuration (None, None, None) => { self._none_config(spi, input)?; self._manual_conversion_init(spi)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer) and changing multiplexer (Some(status), None, None) => { self._status_config(spi, input, status)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying AD control (gain) and changing multiplexer (None, Some(ad_control), None) => { self._ad_config(spi, input, ad_control)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying data rate and change multiplexer (None, None, Some(data_rate)) => { self._drate_config(spi, input, data_rate)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer), AD control (gain), and changing multiplexer (Some(status), Some(ad_control), None) => { self._status_ad_config(spi, input, status, ad_control)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer), data rate, and changing multiplexer (Some(status), None, Some(data_rate)) => { self._status_drate_config(spi, input, status, data_rate)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying AD control (gain), data rate, and changing multiplexer (None, Some(ad_control), Some(data_rate)) => { self._ad_drate_config(spi, input, ad_control, data_rate)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, // Modifying status (toggle buffer), AD control (gain), data rate, and changing // multiplexer (Some(status), Some(ad_control), Some(data_rate)) => { self._all_config(spi, input, status, ad_control, data_rate)?; self._loadcal_init(spi, calibration)?; spi.flush()?; drop(spi_guard); self._read_when_rdy_m(spi_mutex, standby).await }, } } #[inline] pub async fn loadcal_convert_next_m( &mut self, spi_mutex: &Mutex, next_input: Multiplexer, next_calibration: Option<&CalibrationCommand>, next_status: Option, next_ad_control: Option, next_data_rate: Option, standby: bool, ) -> Result::Error> { self.data_ready.wait_for_low().await.expect(GPIO_ERROR_MSG); self._loadcal_convert_next( spi_mutex.lock().await.deref_mut(), next_input, next_calibration, next_status, next_ad_control, next_data_rate, standby, ) .await } #[inline] async fn _read_when_rdy_m( &mut self, spi_mutex: &Mutex, standby: bool, ) -> Result::Error> { self.slave_select.set_high().expect(GPIO_ERROR_MSG); // Wait for data ready low self.data_ready.wait_for_low().await.expect(GPIO_ERROR_MSG); self.slave_select.set_low().expect(GPIO_ERROR_MSG); // Reacquire lock on SPI mutex and read mux conversion self._read_mux_conversion(spi_mutex.lock().await.deref_mut(), standby) } }