#pragma once // using external voltage reference #include "esphome/core/component.h" #include "esphome/components/spi/spi.h" #include "esphome/components/sensor/sensor.h" namespace esphome { namespace ads131m08 { typedef union { int32_t i; float f; uint16_t u[2]; uint8_t b[4]; } flex32_t; /* Adc Structure. Ch can be read as int32 or float*/ struct AdcOutput { uint16_t status; flex32_t ch[8]; }; enum ADS131M08_DRDY_STATE { DS_LOGIC_HIGH = 0, // DEFAULT DS_HI_Z = 1 }; enum ADS131M08_POWERMODE { PM_VERY_LOW_POWER = 0, PM_LOW_POWER = 1, PM_HIGH_RESOLUTION = 2 // DEFAULT }; enum ADS131M08_PGA_GAIN { PGA_1 = 0, PGA_2 = 1, PGA_4 = 2, PGA_8 = 3, PGA_16 = 4, PGA_32 = 5, PGA_64 = 6, PGA_128 = 7, PGA_INVALID }; enum ADS131M08_INPUT_CHANNEL_MUX { ICM_AIN0P_AIN0N = 0, // DEFAULT ICM_INPUT_SHORTED = 1, ICM_POSITIVE_DC_TEST_SIGNAL = 2, ICM_NEGATIVE_DC_TEST_SIGNAL = 3, }; enum ADS131M08_OVERSAMPLING_RATIO { OSR_128 = 0, OSR_256 = 1, OSR_512 = 2, OSR_1024 = 3, // default OSR_2048 = 4, OSR_4096 = 5, OSR_8192 = 6, OSR_16384 = 7 }; enum ADS131M08_WAIT_TIME { WT_128 = 856, WT_256 = 1112, WT_512 = 1624, WT_1024 = 2648, WT_2048 = 4696, WT_4096 = 8792, WT_8192 = 16984, WT_16384 = 33368 }; // MODE Register enum ADS131M08_RESET : uint16_t { MODE_NO_RESET = 0x0000, // DEFAULT MODE_RESET_HAPPENED = 0x0400 }; enum ADS131M08_CRC_TYPE : uint16_t { CRC_CCITT_16BIT = 0x0000, // DEFAULT CRC_ANSI_16BIT = 0x0800 }; enum ADS131M08_WORD_LENGTH : uint16_t { WLENGTH_16_BITS = 0x0000, WLENGTH_24_BITS = 0x0100, // DEFAULT WLENGTH_32_BITS_LSB_ZERO_PADDING = 0x0200, WLENGTH_32_BITS_MSB_SIGN_EXTEND = 0x0300 }; enum ADS131M08_TIMEOUT : uint16_t { TIMEOUT_DISABLED = 0x0000, TIMEOUT_ENABLED = 0x0010 // DEFAULT }; enum ADS131M08_DRDY_SELECTION : uint16_t { DRDY_SEL_MOST_LAGGING = 0x0000, // DEFAULT DRDY_SEL_LOGICAL_OR = 0x0004, DRDY_SEL_MOST_LEADING_CHAN = 0x0008, DRDY_SEL_MOST_LEADING_CHAN = 0x000C }; enum ADS131M08_DRDY_FORMAT : uint16_t { DRDY_FMT_LEVEL = 0x0000, // Logic low (default) DRDY_FMT_PULSE = 0x0001 // Low pulse with a fixed duration }; // end of MODE Register // GAIN1 Register enum ADS131M08_GAIN1_CHANNEL_PGA : uint16_t { PGAGAIN0_1 = 0x0000, // default PGAGAIN0_2 = 0x0001, PGAGAIN0_4 = 0x0002, PGAGAIN0_8 = 0x0003, PGAGAIN0_16 = 0x0004, PGAGAIN0_32 = 0x0005, PGAGAIN0_64 = 0x0006, PGAGAIN0_128 = 0x0007, PGAGAIN1_1 = 0x0000, // default PGAGAIN1_2 = 0x0010, PGAGAIN1_4 = 0x0020, PGAGAIN1_8 = 0x0030, PGAGAIN1_16 = 0x0040, PGAGAIN1_32 = 0x0050, PGAGAIN1_64 = 0x0060, PGAGAIN1_128 = 0x0070, PGAGAIN2_1 = 0x0000, // default PGAGAIN2_2 = 0x0100, PGAGAIN2_4 = 0x0200, PGAGAIN2_8 = 0x0300, PGAGAIN2_16 = 0x0400, PGAGAIN2_32 = 0x0500, PGAGAIN2_64 = 0x0600, PGAGAIN2_128 = 0x0700, PGAGAIN3_1 = 0x0000, // default PGAGAIN3_2 = 0x1000, PGAGAIN3_4 = 0x2000, PGAGAIN3_8 = 0x3000, PGAGAIN3_16 = 0x4000, PGAGAIN3_32 = 0x5000, // Set PGA gain to 32 for channel PGAGAIN3_64 = 0x6000, PGAGAIN3_128 = 0x7000 }; // end of GAIN1 Register // GAIN2 Register enum ADS131M08_GAIN2_CHANNEL_PGA : uint16_t { PGAGAIN4_1 = 0x0000, // default PGAGAIN4_2 = 0x0001, PGAGAIN4_4 = 0x0002, PGAGAIN4_8 = 0x0003, PGAGAIN4_16 = 0x0004, PGAGAIN4_32 = 0x0005, PGAGAIN4_64 = 0x0006, PGAGAIN4_128 = 0x0007, PGAGAIN5_1 = 0x0000, // default PGAGAIN5_2 = 0x0010, PGAGAIN5_4 = 0x0020, PGAGAIN5_8 = 0x0030, PGAGAIN5_16 = 0x0040, PGAGAIN5_32 = 0x0050, PGAGAIN5_64 = 0x0060, PGAGAIN5_128 = 0x0070, PGAGAIN6_1 = 0x0000, // default PGAGAIN6_2 = 0x0100, PGAGAIN6_4 = 0x0200, PGAGAIN6_8 = 0x0300, PGAGAIN6_16 = 0x0400, PGAGAIN6_32 = 0x0500, PGAGAIN6_64 = 0x0600, PGAGAIN6_128 = 0x0700, PGAGAIN7_1 = 0x0000, // default PGAGAIN7_2 = 0x1000, PGAGAIN7_4 = 0x2000, PGAGAIN7_8 = 0x3000, PGAGAIN7_16 = 0x4000, PGAGAIN7_32 = 0x5000, PGAGAIN7_64 = 0x6000, PGAGAIN7_128 = 0x7000 }; // end of GAIN2 Register // Commands enum ADS131M08_COMMANDS : uint16_t { CMD_NULL = 0x0000, // No operation; used to read STATUS register CMD_RESET = 0x0011, // RESET the device CMD_STANDBY = 0x0022, // Place the device into standby mode CMD_WAKEUP = 0x0033, // Wake up device from standby mode to conversion mode CMD_LOCK = 0x0555, // Lock the interface such that only the NULL, UNLOCK, and RREG commands are valid CMD_UNLOCK = 0x0655, // Unlock the interface after the interface is locked CMD_RREG = 0xA000, // Read register command base; number of registers to read added to lower byte; register address to upper byte CMD_WREG = 0x6000, // Write register command base; number of registers to write added to lower byte; register address to upper byte }; // Responses enum ADS131M08_RESPONSES : uint16_t { RSP_RESET_OK = 0xFF28, RSP_RESET_NOK = 0x0011 }; enum ADS131M08_REG { REG_ID = 0x00, REG_STATUS = 0x01, REG_MODE = 0x02, REG_CLOCK = 0x03, REG_GAIN1 = 0x04, REG_GAIN2 = 0x05, REG_CFG = 0x06, REG_THRSHLD_MSB = 0x07, REG_THRSHLD_LSB = 0x08, REG_CH0_CFG = 0x09, REG_CH0_OCAL_MSB = 0x0A, REG_CH0_OCAL_LSB = 0x0B, REG_CH0_GCAL_MSB = 0x0C, REG_CH0_GCAL_LSB = 0x0D, REG_CH1_CFG = 0x0E, REG_CH1_OCAL_MSB = 0x0F, REG_CH1_OCAL_LSB = 0x10, REG_CH1_GCAL_MSB = 0x11, REG_CH1_GCAL_LSB = 0x12, REG_CH2_CFG = 0x13, REG_CH2_OCAL_MSB= 0x14, REG_CH2_OCAL_LSB= 0x15, REG_CH2_GCAL_MSB= 0x16, REG_CH2_GCAL_LSB= 0x17, REG_CH3_CFG = 0x18, REG_CH3_OCAL_MSB= 0x19, REG_CH3_OCAL_LSB= 0x1A, REG_CH3_GCAL_MSB= 0x1B, REG_CH3_GCAL_LSB= 0x1C, REG_CH4_CFG = 0x1D, REG_CH4_OCAL_MSB= 0x1E, REG_CH4_OCAL_LSB= 0x1F, REG_CH4_GCAL_MSB= 0x20, REG_CH4_GCAL_LSB= 0x21, REG_CH5_CFG = 0x22, REG_CH5_OCAL_MSB= 0x23, REG_CH5_OCAL_LSB= 0x24, REG_CH5_GCAL_MSB= 0x25, REG_CH5_GCAL_LSB= 0x26, REG_CH6_CFG = 0x27, REG_CH6_OCAL_MSB= 0x28, REG_CH6_OCAL_LSB= 0x29, REG_CH6_GCAL_MSB= 0x2A, REG_CH6_GCAL_LSB= 0x2B, REG_CH7_CFG = 0x2C, REG_CH7_OCAL_MSB= 0x2D, REG_CH7_OCAL_LSB= 0x2E, REG_CH7_GCAL_MSB= 0x2F, REG_CH7_GCAL_LSB= 0x30, REGMAP_CRC = 0x3E, }; // Mask READ_REG static constexpr uint16_t MASK_CMD_READ_REG_ADDRESS = 0x1F80; static constexpr uint16_t MASK_CMD_READ_REG_BYTES = 0x007F; // Mask Register STATUS static constexpr uint16_t MASK_STATUS_LOCK = 0x8000; static constexpr uint16_t MASK_STATUS_RESYNC = 0x4000; static constexpr uint16_t MASK_STATUS_REGMAP = 0x2000; static constexpr uint16_t MASK_STATUS_CRC_ERR = 0x1000; static constexpr uint16_t MASK_STATUS_CRC_TYPE = 0x0800; static constexpr uint16_t MASK_STATUS_RESET = 0x0400; static constexpr uint16_t MASK_STATUS_WLENGTH = 0x0300; static constexpr uint16_t MASK_STATUS_DRDY7 = 0x0080; static constexpr uint16_t MASK_STATUS_DRDY6 = 0x0040; static constexpr uint16_t MASK_STATUS_DRDY5 = 0x0020; static constexpr uint16_t MASK_STATUS_DRDY4 = 0x0010; static constexpr uint16_t MASK_STATUS_DRDY3 = 0x0008; static constexpr uint16_t MASK_STATUS_DRDY2 = 0x0004; static constexpr uint16_t MASK_STATUS_DRDY1 = 0x0002; static constexpr uint16_t MASK_STATUS_DRDY0 = 0x0001; // Mask Register MODE static constexpr uint16_t MASK_MODE_REG_CRC_EN = 0x2000; static constexpr uint16_t MASK_MODE_RX_CRC_EN = 0x1000; static constexpr uint16_t MASK_MODE_CRC_TYPE = 0x0800; static constexpr uint16_t MASK_MODE_RESET = 0x0400; static constexpr uint16_t MASK_MODE_WLENGTH = 0x0300; static constexpr uint16_t MASK_MODE_TIMEOUT = 0x0010; static constexpr uint16_t MASK_MODE_DRDY_SEL = 0x000C; static constexpr uint16_t MASK_MODE_DRDY_HiZ = 0x0002; static constexpr uint16_t MASK_MODE_DRDY_FMT = 0x0001; // Mask Register CLOCK static constexpr uint16_t MASK_CLOCK_CH7_EN = 0x8000; static constexpr uint16_t MASK_CLOCK_CH6_EN = 0x4000; static constexpr uint16_t MASK_CLOCK_CH5_EN = 0x2000; static constexpr uint16_t MASK_CLOCK_CH4_EN = 0x1000; static constexpr uint16_t MASK_CLOCK_CH3_EN = 0x0800; static constexpr uint16_t MASK_CLOCK_CH2_EN = 0x0400; static constexpr uint16_t MASK_CLOCK_CH1_EN = 0x0200; static constexpr uint16_t MASK_CLOCK_CH0_EN = 0x0100; static constexpr uint16_t MASK_CLOCK_OSR = 0x001C; static constexpr uint16_t MASK_CLOCK_PWR = 0x0003; static constexpr uint32_t MASK_CLOCK_ALL_CH_DISABLE = 0x0000; static constexpr uint32_t MASK_CLOCK_ALL_CH_ENABLE = 0xFF00; // Mask Register GAIN static constexpr uint16_t MASK_GAIN_PGAGAIN7 = 0x7000; static constexpr uint16_t MASK_GAIN_PGAGAIN6 = 0x0700; static constexpr uint16_t MASK_GAIN_PGAGAIN5 = 0x0070; static constexpr uint16_t MASK_GAIN_PGAGAIN4 = 0x0007; static constexpr uint16_t MASK_GAIN_PGAGAIN3 = 0x7000; static constexpr uint16_t MASK_GAIN_PGAGAIN2 = 0x0700; static constexpr uint16_t MASK_GAIN_PGAGAIN1 = 0x0070; static constexpr uint16_t MASK_GAIN_PGAGAIN0 = 0x0007; // Mask Register CFG static constexpr uint16_t MASK_CFG_GC_DLY = 0x1E00; static constexpr uint16_t MASK_CFG_GC_EN = 0x0100; static constexpr uint16_t MASK_CFG_CD_ALLCH = 0x0080; static constexpr uint16_t MASK_CFG_CD_NUM = 0x0070; static constexpr uint16_t MASK_CFG_CD_LEN = 0x000E; static constexpr uint16_t MASK_CFG_CD_EN = 0x0001; // Mask Register THRSHLD_MSB - dummy, for completeness static constexpr uint16_t MASK_THRSHLD_MSB_CD_TH_MSB = 0xFFFF; // Mask Register THRSHLD_LSB static constexpr uint16_t MASK_THRSHLD_LSB_CD_TH_LSB = 0xFF00; static constexpr uint16_t MASK_THRSHLD_LSB_DCBLOCK = 0x000F; // Mask Register CHX_CFG static constexpr uint16_t MASK_CHX_CFG_PHASE = 0xFFC0; static constexpr uint16_t MASK_CHX_CFG_DCBLKX_DIS = 0x0004; static constexpr uint16_t MASK_CHX_CFG_MUX = 0x0003; // Mask Register CHX_OCAL_MSB - dummy, for completeness static constexpr uint16_t MASK_CHX_OCAL_MSB = 0xFFFF; // Mask Register CHX_OCAL_LSB static constexpr uint16_t MASK_CHX_OCAL_LSB = 0xFF00; // Mask Register CHX_GCAL_MSB - dummy, for completeness static constexpr uint16_t MASK_CHX_GCAL_MSB = 0xFFFF; // Mask Register CHX_GCAL_LSB static constexpr uint16_t MASK_CHX_GCAL_LSB = 0xFF00; // -------------------------------------------------------------------- // Conversion modes static constexpr uint16_t CONVERSION_MODE_CONT = 0; static constexpr uint16_t CONVERSION_MODE_SINGLE = 1; // Data Format static constexpr uint16_t DATA_FORMAT_TWO_COMPLEMENT = 0; static constexpr uint16_t DATA_FORMAT_BINARY = 1; // Measure Mode static constexpr uint8_t MEASURE_UNIPOLAR = 1; static constexpr uint8_t MEASURE_BIPOLAR = 0; // Clock Type static constexpr uint8_t CLOCK_EXTERNAL = 1; static constexpr uint8_t CLOCK_INTERNAL = 0; // PGA Gain // static constexpr uint16_t PGA_GAIN_1 = 0; // static constexpr uint16_t PGA_GAIN_2 = 1; // static constexpr uint16_t PGA_GAIN_4 = 2; // static constexpr uint16_t PGA_GAIN_8 = 3; // static constexpr uint16_t PGA_GAIN_16 = 4; // static constexpr uint16_t PGA_GAIN_32 = 5; // static constexpr uint16_t PGA_GAIN_64 = 6; // static constexpr uint16_t PGA_GAIN_128 = 7; // Input Filter static constexpr uint16_t FILTER_SYNC = 0; static constexpr uint16_t FILTER_FIR = 2; static constexpr uint16_t FILTER_FIR_IIR = 3; // Data Mode static constexpr uint8_t DATA_MODE_24BITS = 0; static constexpr uint8_t DATA_MODE_32BITS = 1; // Data Rate static constexpr uint8_t DATA_RATE_0 = 0; static constexpr uint8_t DATA_RATE_1 = 1; static constexpr uint8_t DATA_RATE_2 = 2; static constexpr uint8_t DATA_RATE_3 = 3; static constexpr uint8_t DATA_RATE_4 = 4; static constexpr uint8_t DATA_RATE_5 = 5; static constexpr uint8_t DATA_RATE_6 = 6; static constexpr uint8_t DATA_RATE_7 = 7; static constexpr uint8_t DATA_RATE_8 = 8; static constexpr uint8_t DATA_RATE_9 = 9; static constexpr uint8_t DATA_RATE_10 = 10; static constexpr uint8_t DATA_RATE_11 = 11; static constexpr uint8_t DATA_RATE_12 = 12; static constexpr uint8_t DATA_RATE_13 = 13; static constexpr uint8_t DATA_RATE_14 = 14; static constexpr uint8_t DATA_RATE_15 = 15; // Sync Mpdes static constexpr uint16_t SYNC_CONTINUOUS = 1; static constexpr uint16_t SYNC_PULSE = 0; // DIO Config Mode static constexpr uint8_t DIO_OUTPUT = 1; static constexpr uint8_t DIO_INPUT = 0; static constexpr uint8_t SPI_MASTER_DUMMY = 0xFF; static constexpr uint16_t SPI_MASTER_DUMMY16 = 0xFFFF; static constexpr uint32_t SPI_MASTER_DUMMY32 = 0xFFFFFFFF; // end of from datasheet class ADS131M08Sensor : public sensor::Sensor, public Component { }; class ADS131M08Hub : public Component, public spi::SPIDevice { public: // from datasheet pg. 93: const int numFrameWords = 10; // Number of words in a full ADS131M08 SPI frame unsigned long spiDummyWord[10 /*numFrameWords*/] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; // Dummy word frame to write ADC during ADC data reads bool firstRead = true; // Flag to tell us if we are reading ADC data for the first time signed long adcData; // Location where DMA will store ADC data in memory, length defined elsewhere void txf_init(); bool adcRegisterWrite(unsigned short addrMask, unsigned short data, unsigned char adcWordLength); void initialize_ads131m08_datasheet(); // end of from datasheet bool setChannelPGA(uint8_t channel, uint8_t pga); void setup() override; void loop() override; void set_drdy_pin(InternalGPIOPin *pin) { drdy_pin_ = pin; } void register_sensor(int channel, ADS131M08Sensor *s) { sensors_[channel] = s; } void set_reference_voltage(float reference_voltage) { this->reference_voltage_ = reference_voltage; } void dump_config() override; // from tpcorrea void begin(uint8_t clk_pin, uint8_t miso_pin, uint8_t mosi_pin, uint8_t cs_pin, uint8_t drdy_pin, uint8_t reset_pin); int8_t isDataReadySoft(uint8_t channel); bool isDataReady(void); bool isResetStatus(void); bool isLockSPI(void); bool setDrdyFormat(uint8_t drdyFormat); bool setDrdyStateWhenUnavailable(uint8_t drdyState); bool setPowerMode(uint8_t powerMode); bool setChannelEnable(uint8_t channel, uint16_t enable); bool setChannelPGA(uint8_t channel, ADS131M08_PGA_GAIN pga); ADS131M08_PGA_GAIN getChannelPGA(uint8_t channel); void setGlobalChop(uint16_t global_chop); void setGlobalChopDelay(uint16_t delay); bool setInputChannelSelection(uint8_t channel, uint8_t input); bool setChannelOffsetCalibration(uint8_t channel, int32_t offset); bool setChannelGainCalibration(uint8_t channel, uint32_t gain); bool setOsr(uint16_t osr); void setFullScale(uint8_t channel, float scale); float getFullScale(uint8_t channel); void reset(); uint16_t getId(); uint16_t getModeReg(); uint16_t getClockReg(); uint16_t getCfgReg(); AdcOutput readAdcRaw(void); AdcOutput readAdcFloat(void); protected: float reference_voltage_; InternalGPIOPin *drdy_pin_; ADS131M08Sensor *sensors_[8] = {nullptr}; volatile bool data_ready_{false}; static void isr(ADS131M08Hub *arg); void read_data_(); void write_register(uint8_t reg, uint16_t value); }; } // namespace ads131m08 } // namespace esphome