summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDiego Barrios Romero <eldruin@gmail.com>2018-11-04 21:32:46 +0100
committerDiego Barrios Romero <eldruin@gmail.com>2018-11-04 21:32:46 +0100
commit5a5d08f92768c48949cb175605055b853e559c5c (patch)
treedb71b7805fbb47acc57c09f7a659f9dc205ed47d /src
downloadads1x1x-async-5a5d08f92768c48949cb175605055b853e559c5c.tar.gz
ads1x1x-async-5a5d08f92768c48949cb175605055b853e559c5c.tar.xz
ads1x1x-async-5a5d08f92768c48949cb175605055b853e559c5c.zip
Initial version
Diffstat (limited to 'src')
-rw-r--r--src/devices/ads1013.rs28
-rw-r--r--src/devices/mod.rs19
-rw-r--r--src/interface.rs142
-rw-r--r--src/lib.rs123
4 files changed, 312 insertions, 0 deletions
diff --git a/src/devices/ads1013.rs b/src/devices/ads1013.rs
new file mode 100644
index 0000000..b4628b5
--- /dev/null
+++ b/src/devices/ads1013.rs
@@ -0,0 +1,28 @@
+//! Functions exclusive of ADS1013
+
+extern crate embedded_hal as hal;
+use hal::blocking;
+use core::marker::PhantomData;
+use { Ads1x1x, DEVICE_BASE_ADDRESS, SlaveAddr, ic };
+use interface::I2cInterface;
+
+impl<I2C, E> Ads1x1x<I2cInterface<I2C>, ic::ADS1013>
+where
+ I2C: blocking::i2c::Write<Error = E> + blocking::i2c::WriteRead<Error = E>
+{
+ /// Create a new instance of the ADS1013 device.
+ pub fn new_ads1013(i2c: I2C, address: SlaveAddr) -> Self {
+ Ads1x1x {
+ iface: I2cInterface {
+ i2c,
+ address: address.addr(DEVICE_BASE_ADDRESS)
+ },
+ _ic: PhantomData
+ }
+ }
+
+ /// Destroy driver instance, return I²C bus instance.
+ pub fn destroy_ads1013(self) -> I2C {
+ self.iface.i2c
+ }
+}
diff --git a/src/devices/mod.rs b/src/devices/mod.rs
new file mode 100644
index 0000000..529db04
--- /dev/null
+++ b/src/devices/mod.rs
@@ -0,0 +1,19 @@
+/// IC markers
+pub mod ic {
+ /// ADS1013 IC marker
+ pub struct ADS1013;
+ /// ADS1014 IC marker
+ pub struct ADS1014;
+ /// ADS1015 IC marker
+ pub struct ADS1015;
+ /// ADS1113 IC marker
+ pub struct ADS1113;
+ /// ADS1114 IC marker
+ pub struct ADS1114;
+ /// ADS1115 IC marker
+ pub struct ADS1115;
+ /// ADS1118 IC marker
+ pub struct ADS1118;
+}
+
+mod ads1013;
diff --git a/src/interface.rs b/src/interface.rs
new file mode 100644
index 0000000..2bf14f2
--- /dev/null
+++ b/src/interface.rs
@@ -0,0 +1,142 @@
+//! I2C/SPI interfaces
+
+#![deny(missing_docs)]
+
+extern crate embedded_hal as hal;
+use hal::blocking;
+use Error;
+
+/// I2C interface
+#[derive(Debug, Default)]
+pub struct I2cInterface<I2C> {
+ pub(crate) i2c: I2C,
+ pub(crate) address : u8,
+}
+
+/// SPI interface
+#[derive(Debug, Default)]
+pub struct SpiInterface<SPI, CS> {
+ pub(crate) spi: SPI,
+ pub(crate) cs: CS
+}
+
+/// Write data
+pub trait WriteData {
+ /// Error type
+ type Error;
+ /// Write to an u8 register
+ fn write_register(&mut self, register: u8, data: u8) -> Result<(), Error<Self::Error>>;
+ /// Write data. The first element corresponds to the starting address.
+ fn write_data(&mut self, payload: &mut [u8]) -> Result<(), Error<Self::Error>>;
+}
+
+impl<I2C, E> WriteData for I2cInterface<I2C>
+where
+ I2C: blocking::i2c::Write<Error = E>
+{
+ type Error = E;
+ fn write_register(&mut self, register: u8, data: u8) -> Result<(), Error<E>> {
+ let payload: [u8; 2] = [register, data];
+ self.i2c
+ .write(self.address, &payload)
+ .map_err(Error::Comm)
+ }
+
+ fn write_data(&mut self, payload: &mut [u8]) -> Result<(), Error<Self::Error>> {
+ self.i2c
+ .write(self.address, &payload)
+ .map_err(Error::Comm)
+ }
+}
+
+impl<SPI, CS, E> WriteData for SpiInterface<SPI, CS>
+where
+ SPI: blocking::spi::Write<u8, Error = E>,
+ CS: hal::digital::OutputPin
+{
+ type Error = E;
+ fn write_register(&mut self, register: u8, data: u8) -> Result<(), Error<E>> {
+ self.cs.set_low();
+
+ let payload: [u8; 2] = [register + 0x80, data];
+ let result = self.spi
+ .write(&payload)
+ .map_err(Error::Comm);
+
+ self.cs.set_high();
+ result
+ }
+
+ fn write_data(&mut self, payload: &mut [u8]) -> Result<(), Error<Self::Error>> {
+ self.cs.set_low();
+ payload[0] += 0x80;
+ let result = self.spi
+ .write(&payload)
+ .map_err(Error::Comm);
+
+ self.cs.set_high();
+ result
+ }
+}
+
+
+/// Read data
+pub trait ReadData {
+ /// Error type
+ type Error;
+ /// Read an u8 register
+ fn read_register(&mut self, register: u8) -> Result<u8, Error<Self::Error>>;
+ /// Read some data. The first element corresponds to the starting address.
+ fn read_data(&mut self, payload: &mut [u8]) -> Result<(), Error<Self::Error>>;
+}
+
+impl<I2C, E> ReadData for I2cInterface<I2C>
+where
+ I2C: blocking::i2c::WriteRead<Error = E>
+{
+ type Error = E;
+ fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> {
+ let mut data = [0];
+ self.i2c
+ .write_read(self.address, &[register], &mut data)
+ .map_err(Error::Comm)
+ .and(Ok(data[0]))
+ }
+
+ fn read_data(&mut self, payload: &mut [u8]) -> Result<(), Error<Self::Error>> {
+ let len = payload.len();
+ self.i2c
+ .write_read(self.address, &[payload[0]], &mut payload[1..=(len-1)])
+ .map_err(Error::Comm)
+ }
+}
+
+impl<SPI, CS, E> ReadData for SpiInterface<SPI, CS>
+where
+ SPI: blocking::spi::Transfer<u8, Error = E>,
+ CS: hal::digital::OutputPin
+{
+ type Error = E;
+ fn read_register(&mut self, register: u8) -> Result<u8, Error<E>> {
+ self.cs.set_low();
+ let mut data = [register, 0];
+ let result = self.spi
+ .transfer(&mut data)
+ .map_err(Error::Comm);
+ self.cs.set_high();
+ match result {
+ Ok(result) => Ok(result[1]),
+ Err(e) => Err(e)
+ }
+ }
+
+ fn read_data(&mut self, mut payload: &mut [u8]) -> Result<(), Error<Self::Error>> {
+ self.cs.set_low();
+ let result = self.spi
+ .transfer(&mut payload)
+ .map_err(Error::Comm);
+ self.cs.set_high();
+ result?;
+ Ok(())
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..23c36bb
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,123 @@
+//! This is a platform-agnostic Rust driver for the ADS1013, ADS1014, ADS1015,
+//! ADS1113, ADS1114, ADS1115, ADS1018 and ADS1118 ultra-small, low-power
+//! analog-to-digital converters (ADC), based on the [`embedded-hal`] traits.
+//!
+//! [`embedded-hal`]: https://github.com/rust-embedded/embedded-hal
+//!
+//! This driver allows you to:
+//! - TODO
+//!
+//! ## The devices
+//!
+//! The devices are precision, low power, 12/16-bit analog-to-digital
+//! converters (ADC) that provide all features necessary to measure the most
+//! common sensor signals in an ultra-small package. Depending on the device,
+//! these integrate a programmable gain amplifier (PGA), voltage reference,
+//! oscillator and high-accuracy temperature sensor.
+//!
+//! The devices can perform conversions at data rates up to 3300 samples per
+//! second (SPS). The PGA offers input ranges from ±256 mV to ±6.144 V,
+//! allowing both large and small signals to be measured with high resolution.
+//! An input multiplexer (MUX) allows to measure two differential or four
+//! single-ended inputs. The high-accuracy temperature sensor can be used for
+//! system-level temperature monitoring or cold-junction compensation for
+//! thermocouples.
+//!
+//! The devices operate either in continuous-conversion mode, or in a
+//! single-shot mode that automatically powers down after a conversion.
+//! Single-shot mode significantly reduces current consumption during idle
+//! periods. Data are transferred through a I2C or SPI.
+//!
+//! Here is a comparison of the caracteristics of the devices:
+//!
+//! | Device | Resolution | Sample Rate | Channels | Interface | Multi-channel | Features |
+//! |---------|------------|--------------|----------|-----------|---------------|------------------------------|
+//! | ADS1013 | 12-bit | Max 3300 SPS | 1 | I2C | N/A | |
+//! | ADS1014 | 12-bit | Max 3300 SPS | 1 | I2C | N/A | Comparator, PGA |
+//! | ADS1015 | 12-bit | Max 3300 SPS | 4 | I2C | Multiplexed | Comparator, PGA |
+//! | ADS1018 | 12-bit | Max 3300 SPS | 4 | SPI | Multiplexed | Comparator, PGA, Temp sensor |
+//! | ADS1113 | 16-bit | Max 860 SPS | 1 | I2C | N/A | |
+//! | ADS1114 | 16-bit | Max 860 SPS | 1 | I2C | N/A | Comparator, PGA |
+//! | ADS1115 | 16-bit | Max 860 SPS | 4 | I2C | Multiplexed | Comparator, PGA |
+//! | ADS1118 | 16-bit | Max 860 SPS | 4 | SPI | Multiplexed | Comparator, PGA, Temp sensor |
+//!
+//! Datasheets:
+//! - [ADS101x](http://www.ti.com/lit/ds/symlink/ads1015.pdf)
+//! - [ADS1018](http://www.ti.com/lit/ds/symlink/ads1018.pdf)
+//! - [ADS111x](http://www.ti.com/lit/ds/symlink/ads1115.pdf)
+//! - [ADS1118](http://www.ti.com/lit/ds/symlink/ads1118.pdf)
+//!
+
+#![deny(unsafe_code)]
+#![deny(missing_docs)]
+//TODO #![deny(warnings)]
+#![no_std]
+
+extern crate embedded_hal as hal;
+use core::marker::PhantomData;
+
+/// All possible errors in this crate
+#[derive(Debug)]
+pub enum Error<E> {
+ /// I²C/SPI bus error
+ Comm(E)
+}
+
+const DEVICE_BASE_ADDRESS : u8 = 0b100_1000;
+
+/// Possible slave addresses
+#[derive(Debug, Clone)]
+pub enum SlaveAddr {
+ /// Default slave address
+ Default,
+ /// Alternative slave address providing bit values for A1 and A0
+ Alternative(bool, bool)
+}
+
+impl Default for SlaveAddr {
+ /// Default slave address
+ fn default() -> Self {
+ SlaveAddr::Default
+ }
+}
+
+impl SlaveAddr {
+ fn addr(self, default: u8) -> u8 {
+ match self {
+ SlaveAddr::Default => default,
+ SlaveAddr::Alternative(a1, a0) => default |
+ ((a1 as u8) << 1) |
+ a0 as u8
+ }
+ }
+}
+
+/// ADS1x1x ADC driver
+#[derive(Debug, Default)]
+pub struct Ads1x1x<DI, IC> {
+ iface: DI,
+ _ic: PhantomData<IC>
+}
+
+pub mod interface;
+mod devices;
+pub use devices::ic;
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn can_get_default_address() {
+ let addr = SlaveAddr::default();
+ assert_eq!(DEVICE_BASE_ADDRESS, addr.addr(DEVICE_BASE_ADDRESS));
+ }
+
+ #[test]
+ fn can_generate_alternative_addresses() {
+ assert_eq!(0b100_1000, SlaveAddr::Alternative(false, false).addr(DEVICE_BASE_ADDRESS));
+ assert_eq!(0b100_1001, SlaveAddr::Alternative(false, true).addr(DEVICE_BASE_ADDRESS));
+ assert_eq!(0b100_1010, SlaveAddr::Alternative(true, false).addr(DEVICE_BASE_ADDRESS));
+ assert_eq!(0b100_1011, SlaveAddr::Alternative(true, true).addr(DEVICE_BASE_ADDRESS));
+ }
+}