Initial proof of concept

This commit is contained in:
Zachary Levy
2025-03-09 12:13:14 -07:00
commit e06e76e46b
55 changed files with 4508 additions and 0 deletions
+271
View File
@@ -0,0 +1,271 @@
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<DelayerT, SST, DrdyT> Ads1256<DelayerT, SST, DrdyT>
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<MutexT: RawMutex, SpiT: SpiBus>(
&mut self,
spi: &Mutex<MutexT, SpiT>,
) -> Result<Conversion, <SpiT as spi::ErrorType>::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<MutexT: RawMutex, SpiT: SpiBus>(
&mut self,
spi_mutex: &Mutex<MutexT, SpiT>,
input: Multiplexer,
status: Option<Status>,
ad_control: Option<AdControl>,
data_rate: Option<DataRate>,
standby: bool,
) -> Result<Conversion, <SpiT as spi::ErrorType>::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<MutexT: RawMutex, SpiT: SpiBus>(
&mut self,
spi_mutex: &Mutex<MutexT, SpiT>,
input: Multiplexer,
calibration: Option<&CalibrationCommand>,
status: Option<Status>,
ad_control: Option<AdControl>,
data_rate: Option<DataRate>,
standby: bool,
) -> Result<Conversion, <SpiT as spi::ErrorType>::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<MutexT: RawMutex, SpiT: SpiBus>(
&mut self,
spi_mutex: &Mutex<MutexT, SpiT>,
next_input: Multiplexer,
next_calibration: Option<&CalibrationCommand>,
next_status: Option<Status>,
next_ad_control: Option<AdControl>,
next_data_rate: Option<DataRate>,
standby: bool,
) -> Result<Conversion, <SpiT as spi::ErrorType>::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<MutexT: RawMutex, SpiT: SpiBus>(
&mut self,
spi_mutex: &Mutex<MutexT, SpiT>,
standby: bool,
) -> Result<Conversion, <SpiT as spi::ErrorType>::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)
}
}