diff --git a/src/libDevCom/ADS1015.cpp b/src/libDevCom/ADS1015.cpp index 8ceb540f44f276d920870cd28dee97e5b8116c1b..06b77d482e22c830a531d5232e399e92a15282f0 100644 --- a/src/libDevCom/ADS1015.cpp +++ b/src/libDevCom/ADS1015.cpp @@ -89,8 +89,8 @@ int32_t ADS1015::readCount(uint8_t channel) { // write the configuration m_com->write_reg16(static_cast<uint16_t>(Address::POINTER_CONFIG), config); - std::this_thread::sleep_for(std::chrono::microseconds( - 1000)); // wait for conversion delay (plus some headroom) + while (!conversionComplete()) { + } uint16_t result = m_com->read_reg16(static_cast<uint16_t>(Address::POINTER_CONVERT)); @@ -224,3 +224,84 @@ void ADS1015::setFullScaleRange(double val) { m_calibration = std::make_shared<LinearCalibration>(val, m_maxValue); this->setCalibration(m_calibration); } + +double ADS1015::readDifferentialP0N1() { + return readDifferential(DifferentialConfig::P0_N1); +} + +double ADS1015::readDifferentialP2N3() { + return readDifferential(DifferentialConfig::P2_N3); +} + +double ADS1015::readDifferential(DifferentialConfig diff_config) { + int16_t counts = readCountDifferential(diff_config); + double multiplier = m_fullscale_range / m_maxValue; + logger(logINFO) << __PRETTY_FUNCTION__ << " counts = " << counts + << ", multiplier = " << multiplier; + return counts * multiplier; +} + +int16_t ADS1015::readCountDifferentialP0N1() { + return readCountDifferential(DifferentialConfig::P0_N1); +} + +int16_t ADS1015::readCountDifferentialP2N3() { + return readCountDifferential(DifferentialConfig::P2_N3); +} + +int16_t ADS1015::readCountDifferential(DifferentialConfig diff_config) { + uint16_t config = 0; + + // set single shot conifguration + setSingleShot(config); + + // set the programmable gain amplifier configuration + setPGA(config); + + // set the differential channel mux + switch (diff_config) { + case DifferentialConfig::P0_N1: + config |= static_cast<uint16_t>(Config::CONFIG_MUX_DIFF_P0_N1); + break; + case DifferentialConfig::P2_N3: + config |= static_cast<uint16_t>(Config::CONFIG_MUX_DIFF_P2_N3); + break; + default: + throw std::runtime_error( + "Invalid differential channel config provided for ADS1015 " + "device"); + break; + } + + // set the 'start signle-conversion' bit + setStartConversion(config); + + // write the configuration + m_com->write_reg16(static_cast<uint16_t>(Address::POINTER_CONFIG), config); + while (!conversionComplete()) { + } + + uint16_t raw_result = + m_com->read_reg16(static_cast<uint16_t>(Address::POINTER_CONVERT)); + + logger(logINFO) << __PRETTY_FUNCTION__ << " raw_result = " << raw_result; + // ADS1015 writes 12-bit results shifted by four, so remove the shift + raw_result = raw_result >> 4; + logger(logINFO) << __PRETTY_FUNCTION__ + << " shifted raw_result = " << raw_result; + + // differential measurements are signed, so check the sign bit + if (raw_result > 0x07FF) { + // negative number: set the sign bit + raw_result |= 0xF000; + } + + // return the signed interpretation + return static_cast<int16_t>(raw_result); +} + +bool ADS1015::conversionComplete() { + uint16_t reg = + m_com->read_reg16(static_cast<uint16_t>(Address::POINTER_CONFIG)); + return (reg & 0x8000) != 0; +} diff --git a/src/libDevCom/ADS1015.h b/src/libDevCom/ADS1015.h index 4b104c54142b35a547ae1788bb412d66962a9cac..02682d5baf5d0c5b527f81604b558d3e5b5161e9 100644 --- a/src/libDevCom/ADS1015.h +++ b/src/libDevCom/ADS1015.h @@ -14,8 +14,11 @@ class I2CCom; * * The `ADS1015` class provides a driver for the Texas Instruments low-power, * I2C compatible 4-channel 12-bit ADC. Support for single-shot ADC conversions - * is supported, whereas the differential measurement capabilities of the - * ADS1015 are not. + * is supported across all four channels in single-ended measurement mode. + * Support for differential measurements are supported in the following + * configuration: + * - Across channel 0 and 1: channel 0 as AINP and channel 1 as AINN + * - Across channel 2 and 3: channel 2 as AINP and channel 3 as AINN * * [Datasheet](https://cdn.sparkfun.com/assets/a/c/4/9/b/ads1015.pdf) */ @@ -85,6 +88,22 @@ class ADS1015 : public ADCDevice { */ void setFullScaleRange(double val); + //! \brief Return the differential measurement with channel 0 as AINP and + //! channel 1 as AINN + int16_t readCountDifferentialP0N1(); + + //! \brief Return the differential measurement with channel 2 as AINP and + //! channel 3 as AINN + int16_t readCountDifferentialP2N3(); + + //! \brief Return the differential measurement between channel 0 (AINP) and + //! channel 1 (AINN) converted to Volts + double readDifferentialP0N1(); + + //! \brief Return the differential measurement between channel 2 (AINP) and + //! channel 3 (AINN) converted to Volts) + double readDifferentialP2N3(); + private: void init(double full_scale_range, std::shared_ptr<I2CCom> com); @@ -156,6 +175,15 @@ class ADS1015 : public ADCDevice { // in high state (default) }; + // The ADS1015 can be configured for differential measurements with the + // negative channel being either channel 1 or channel 3, however it is + // recommended to only perform differential measurements between the + // adjacent channels due to the internal capacitive network. This enum + // defines the possible differential measurement configuration, but is not + // known to the user which will call the more direct `readDifferentialP0N1` + // and `readDifferentialP2N3` methods. + enum class DifferentialConfig { P0_N1, P2_N3 }; + // map between programmable gain configuration and ADS1015 full scale range // in volts const std::map<Gain, std::string> gainToFSRMap{ @@ -185,6 +213,7 @@ class ADS1015 : public ADCDevice { double m_fullscale_range; // volts // some helper methods + bool conversionComplete(); Gain fsrToGain(double fsr); std::string fsrToString(); std::string fsrValToString(double val); @@ -195,6 +224,10 @@ class ADS1015 : public ADCDevice { void setPGA(uint16_t& config); void setSingleChannel(uint16_t& config, uint8_t channel); void setStartConversion(uint16_t& config); + + // methods for performing differential measurement + int16_t readCountDifferential(DifferentialConfig config); + double readDifferential(DifferentialConfig config); }; #endif // DEVCOM_ADS1015_H