TLA2528 I2C ADC

The Tla2528 class implements support for the Texas Instruments TLA2528 12-bit 8-channel ADC. The TLA2528 is a 12-bit, 8-channel, low-power, successive approximation register (SAR) analog-to-digital converter (ADC) which can configure any of its 8 channels as single-ended analog inputs, digital inputs, or digital outputs. It has an operating mode that allows the user to configure the device for a single conversion, or to automatically convert on a sequenced basis.

API Reference

Header File

Classes

class Tla2528 : public espp::BasePeripheral<>

Class for reading values from the TLA2528 family of ADC chips.

The TLA2528 is a 16-bit, 8-channel ADC with 8 digital I/O pins. It supports a variety of sampling modes, including manual sampling, and auto sequence sampling. It also supports oversampling ratios of 2, 4, 8, 16, 32, 64, and 128. It additionally allows the user to configure the analog or digital inputs to trigger an alert when the value goes above or below a threshold (enter or leave a region of voltage).

TLA2528 Example

    // make the I2C that we'll use to communicate
    espp::I2c i2c({
        .port = I2C_NUM_0,
        .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
        .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
    });

    static std::vector<espp::Tla2528::Channel> channels = {
        espp::Tla2528::Channel::CH0, espp::Tla2528::Channel::CH1, espp::Tla2528::Channel::CH2,
        espp::Tla2528::Channel::CH3, espp::Tla2528::Channel::CH4, espp::Tla2528::Channel::CH5,
        espp::Tla2528::Channel::CH6, espp::Tla2528::Channel::CH7};

    // make the actual tla class
    espp::Tla2528 tla(espp::Tla2528::Config{
        // Address pin is connected via 11k to ADC_DECAP, so the default address
        // of 0x10 becomes 0x16
        .device_address = espp::Tla2528::DEFAULT_ADDRESS | 0x06,
        .mode = espp::Tla2528::Mode::AUTO_SEQ,
        .analog_inputs = channels,
        .digital_inputs = {},
        .digital_outputs = {},
        // enable oversampling / averaging
        .oversampling_ratio = espp::Tla2528::OversamplingRatio::NONE,
        .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
                           std::placeholders::_3),
        .read = std::bind(&espp::I2c::read, &i2c, std::placeholders::_1, std::placeholders::_2,
                          std::placeholders::_3),
        .log_level = espp::Logger::Verbosity::WARN,
    });

    // make the task which will get the raw data from the I2C ADC
    fmt::print("%time (s), ntc (mV), x (mV), y (mV)\n");
    auto tla_read_task_fn = [&tla](std::mutex &m, std::condition_variable &cv) {
      static auto start = std::chrono::high_resolution_clock::now();
      auto now = std::chrono::high_resolution_clock::now();
      auto elapsed = std::chrono::duration<float>(now - start).count();

      // get the analog input data individually; NOTE: this only works if you have configured the
      // TLA2528 to use MANUAL mode
      // auto ch0_mv = tla.get_mv(channels[0]);
      // auto ch1_mv = tla.get_mv(channels[1]);
      // auto ch2_mv = tla.get_mv(channels[2]);

      // Could also read them all at once; NOTE: this only works if you have configured the
      // TLA2528 to use AUTO_SEQ mode (which is more efficient)
      // auto all_mv = tla.get_all_mv();
      // auto ch0_mv = all_mv[0];
      // auto ch1_mv = all_mv[1];
      // auto ch2_mv = all_mv[2];

      // Could also use the mapped version; NOTE: this only works if you have configured the
      // TLA2528 to use AUTO_SEQ mode (which is more efficient)
      std::error_code ec;
      auto all_mv_map = tla.get_all_mv_map(ec);
      if (ec) {
        logger.error("error reading TLA2528: {}", ec.message());
        return false;
      }

      // use fmt to print so it doesn't have the prefix and can be used more
      // easily as CSV (for plotting using uart_serial_plotter)
      fmt::print("{:.3f}", elapsed);
      for (auto &[ch, mv] : all_mv_map) {
        fmt::print(", {:.1f}", mv);
      }
      fmt::print("\n");

      // NOTE: sleeping in this way allows the sleep to exit early when the
      // task is being stopped / destroyed
      {
        using namespace std::chrono_literals;
        std::unique_lock<std::mutex> lk(m);
        cv.wait_until(lk, now + 10ms);
      }
      // we don't want to stop, so return false
      return false;
    };

    auto tla_task = espp::Task::make_unique({.callback = tla_read_task_fn,
                                             .task_config =
                                                 {
                                                     .name = "TLA",
                                                     .stack_size_bytes{8 * 1024},
                                                 },
                                             .log_level = espp::Logger::Verbosity::INFO});
    tla_task->start();

Public Types

enum class OversamplingRatio : uint8_t

Possible oversampling ratios, see data sheet Table 15 (p. 34)

Values:

enumerator NONE

No oversampling.

enumerator OSR_2

2x oversampling

enumerator OSR_4

4x oversampling

enumerator OSR_8

8x oversampling

enumerator OSR_16

16x oversampling

enumerator OSR_32

32x oversampling

enumerator OSR_64

64x oversampling

enumerator OSR_128

128x oversampling

enum class Channel : uint8_t

Possible channel numbers.

The TLA2528 has 8 channels, see data sheet Table 1 (p. 4)

Note

The channel numbers are 0-indexed.

Note

The channel may be configured as digital input, digital output, or analog input.

Values:

enumerator CH0

Channel 0.

enumerator CH1

Channel 1.

enumerator CH2

Channel 2.

enumerator CH3

Channel 3.

enumerator CH4

Channel 4.

enumerator CH5

Channel 5.

enumerator CH6

Channel 6.

enumerator CH7

Channel 7.

enum class Mode : uint8_t

Possible modes for analog input conversion.

The ADS7128 device has the following sampling modes:

  • Manual Mode: Allows the external host processor to directly request and control when the data are sampled. The host provides I2C frames to control conversions and the captured data are returned overthe I2C bus after each conversion.

  • Auto-Sequence Mode: The host can configure the device to scan through the enabled analog input channels. The host must provide continuous clocks (SCL) to the device to scan through the channels and to read the data from the device. The mux automatically switches through the predetermined channel sequence, and the data conversion results are sent through the data bus.

Values:

enumerator MANUAL

Manual mode (9th falling edge of SCL (ACK) triggers conversion) and the MUX is controlled by register write to MANUAL_CHID field of the CHANNEL_SEL register.

enumerator AUTO_SEQ

Auto sequence mode (9th falling edge of SCL (ACK) triggers conversion) and the MUX is incremented after each conversion.

enum class OutputMode : uint8_t

Output mode for digital output channels and ALERT pin.

Values:

enumerator OPEN_DRAIN

Open drain output mode.

enumerator PUSH_PULL

Push-pull output mode.

enum class DataFormat : uint8_t

Enum for the data format that can be read from the ADC.

Values:

enumerator RAW

Raw data format, 12 bit ADC data.

enumerator AVERAGED

Averaged data format, 16 bit ADC data.

enum class Append : uint8_t

Enum for the different configurations of bits that can be appended to the data when reading from the ADC.

Values:

enumerator NONE

No append.

enumerator CHANNEL_ID

Append Channel ID.

enum class AlertLogic : uint8_t

Alert logic for ALERT pin.

Values:

enumerator ACTIVE_LOW

ALERT pin is active low.

enumerator ACTIVE_HIGH

ALERT pin is active high.

enumerator PULSED_LOW

ALERT pin is pulsed low per alert flag.

enumerator PULSED_HIGH

ALERT pin is pulsed high per alert flag.

typedef std::function<bool(uint8_t)> probe_fn

Function to probe the peripheral

Param address

The address to probe

Return

True if the peripheral is found at the given address

Public Functions

inline explicit Tla2528(const Config &config)

Construct Tla2528.

Parameters

config – Configuration structure.

inline void initialize(std::error_code &ec)

Initialize the ADC This function uses the configuration structure passed to the constructor to configure the ADC.

Note

This function must be called before any other functions as it configures the ADC pins and sets the mode.

Parameters

ec – Error code to set if an error occurs.

inline float get_mv(Channel channel, std::error_code &ec)

Communicate with the ADC to get the analog value for the channel and return it.

Note

The channel must have been configured as an analog input.

Note

If the ADC is in autonomous mode, this function will simply read the value from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the value from the ADC’s buffer (blocking until conversion is complete).

Note

This function will return 0 and log an error if the channel is not configured as an analog input.

Parameters
  • channel – Which channel of the ADC to read

  • ec – Error code to set if an error occurs.

Returns

The voltage (in mV) read from the channel.

inline std::vector<float> get_all_mv(std::error_code &ec)

Communicate with the ADC to get the analog value for all channels and return them.

Note

The channels must have been configured as analog inputs.

Note

The vector will be in the order of the channels configured in the constructor.

Note

The vector will be the same length as the number of channels configured in the constructor.

Note

If the ADC is in autonomous mode, this function will simply read the values from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the values from the ADC’s buffer (blocking until conversion is complete).

Parameters

ec – Error code to set if an error occurs.

Returns

A vector of the voltages (in mV) read from each channel.

inline std::unordered_map<Channel, float> get_all_mv_map(std::error_code &ec)

Communicate with the ADC to get the analog value for all channels and return them.

Note

These are the channels that were configured as analog inputs.

Note

If the ADC is in autonomous mode, this function will simply read the values from the ADC’s buffer. If the ADC is in manual mode, this function will trigger a conversion and then read the values from the ADC’s buffer (blocking until conversion is complete).

Parameters

ec – Error code to set if an error occurs.

Returns

An unordered map of the voltages (in mV) read from each channel.

inline void set_digital_output_mode(Channel channel, OutputMode output_mode, std::error_code &ec)

Configure the digital output mode for the given channel.

Note

The channel must have been configured as a digital output.

Parameters
  • channel – Channel to configure

  • output_mode – Output mode for the channel

  • ec – Error code to set if an error occurs.

inline void set_digital_output_value(Channel channel, bool value, std::error_code &ec)

Set the digital output value for the given channel.

Note

The channel must have been configured as a digital output.

Parameters
  • channel – Which channel to set the digital output value for.

  • value – The value to set the digital output to.

  • ec – Error code to set if an error occurs.

inline bool get_digital_input_value(Channel channel, std::error_code &ec)

Get the digital input value for the given channel.

Note

The channel must have been configured as a digital input.

Parameters
  • channel – Which channel to get the digital input value for.

  • ec – Error code to set if an error occurs.

Returns

The value of the digital input.

inline uint8_t get_digital_input_values(std::error_code &ec)

Get the digital input values for all channels.

Note

The returned value is a bitfield, with each bit corresponding to a channel. The LSB corresponds to channel 0, the MSB to channel 7.

Note

Only channels configured as digital inputs are returned.

Parameters

ec – Error code to set if an error occurs.

Returns

The values of the digital inputs.

inline void reset(std::error_code &ec)

Perform a software reset of the device.

Note

This will reset all registers to their default values (converting all channels to analog inputs and disabling all events).

Parameters

ec – Error code to set if an error occurs.

inline bool probe (std::error_code &ec) requires(UseAddress)

Probe the peripheral

Note

This function is thread safe

Note

If the probe function is not set, this function will return false and set the error code to operation_not_supported

Note

This function is only available if UseAddress is true

Parameters

ec – The error code to set if there is an error

Returns

True if the peripheral is found

inline void set_address (uint8_t address) requires(UseAddress)

Set the address of the peripheral

Note

This function is thread safe

Note

This function is only available if UseAddress is true

Parameters

address – The address of the peripheral

inline void set_probe (const probe_fn &probe) requires(UseAddress)

Set the probe function

Note

This function is thread safe

Note

This should rarely be used, as the probe function is usually set in the constructor. If you need to change the probe function, consider using the set_config function instead.

Note

This function is only available if UseAddress is true

Parameters

probe – The probe function

inline void set_write(const write_fn &write)

Set the write function

Note

This function is thread safe

Note

This should rarely be used, as the write function is usually set in the constructor. If you need to change the write function, consider using the set_config function instead.

Parameters

write – The write function

inline void set_read(const read_fn &read)

Set the read function

Note

This function is thread safe

Note

This should rarely be used, as the read function is usually set in the constructor. If you need to change the read function, consider using the set_config function instead.

Parameters

read – The read function

inline void set_read_register(const read_register_fn &read_register)

Set the read register function

Note

This function is thread safe

Note

This should rarely be used, as the read register function is usually set in the constructor. If you need to change the read register function, consider using the set_config function instead.

Parameters

read_register – The read register function

inline void set_write_then_read(const write_then_read_fn &write_then_read)

Set the write then read function

Note

This function is thread safe

Note

This should rarely be used, as the write then read function is usually set in the constructor. If you need to change the write then

Parameters

write_then_read – The write then read function

inline void set_separate_write_then_read_delay(const std::chrono::milliseconds &delay)

Set the delay between the write and read operations in write_then_read

Note

This function is thread safe

Note

This should rarely be used, as the delay is usually set in the constructor. If you need to change the delay, consider using the set_config function instead.

Note

This delay is only used if the write_then_read function is not set to a custom function and the write and read functions are separate functions.

Parameters

delay – The delay between the write and read operations in write_then_read

inline void set_config(const Config &config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters

config – The configuration for the peripheral

inline void set_config(Config &&config)

Set the configuration for the peripheral

Note

This function is thread safe

Note

The configuration should normally be set in the constructor, but this function can be used to change the configuration after the peripheral has been created - for instance if the peripheral could be found on different communications buses.

Parameters

config – The configuration for the peripheral

inline const std::string &get_name() const

Get the name of the component

Note

This is the tag of the logger

Returns

A const reference to the name of the component

inline void set_log_tag(const std::string_view &tag)

Set the tag for the logger

Parameters

tag – The tag to use for the logger

inline espp::Logger::Verbosity get_log_level() const

Get the log level for the logger

Returns

The verbosity level of the logger

inline void set_log_level(espp::Logger::Verbosity level)

Set the log level for the logger

Parameters

level – The verbosity level to use for the logger

inline void set_log_verbosity(espp::Logger::Verbosity level)

Set the log verbosity for the logger

See also

set_log_level

Note

This is a convenience method that calls set_log_level

Parameters

level – The verbosity level to use for the logger

inline espp::Logger::Verbosity get_log_verbosity() const

Get the log verbosity for the logger

See also

get_log_level

Note

This is a convenience method that calls get_log_level

Returns

The verbosity level of the logger

inline void set_log_rate_limit(std::chrono::duration<float> rate_limit)

Set the rate limit for the logger

Note

Only calls to the logger that have _rate_limit suffix will be rate limited

Parameters

rate_limit – The rate limit to use for the logger

Public Static Attributes

static constexpr uint8_t DEFAULT_ADDRESS = (0x10)

Default I2C address of the device (when both R1 and R2 are DNP) (see data sheet Table 2, p. 16)

struct Config

Configuration structure.

Public Members

uint8_t device_address = DEFAULT_ADDRESS

I2C address of the device.

float avdd_volts = 3.3f

AVDD voltage in Volts. Used for calculating analog input voltage.

Mode mode = Mode::MANUAL

Mode for analog input conversion.

std::vector<Channel> analog_inputs = {}

List of analog input channels to sample.

std::vector<Channel> digital_inputs = {}

List of digital input channels to sample.

std::vector<Channel> digital_outputs = {}

List of digital output channels to sample.

std::unordered_map<Channel, OutputMode> digital_output_modes = {}

Optional output mode for digital output channels. If not specified, the default value is open-drain.

std::unordered_map<Channel, bool> digital_output_values = {}

Optional initial values for digital output channels. If not specified, the default value is false in open-drain mode.

OversamplingRatio oversampling_ratio = OversamplingRatio::NONE

Oversampling ratio to use.

Append append = Append::NONE

What data to append to samples when reading analog inputs.

BasePeripheral::write_fn write

Function to write to the ADC.

BasePeripheral::read_fn read

Function to read from the ADC.

bool auto_init = true

Automatically initialize the ADC on construction. If false, initialize() must be called before any other functions.

espp::Logger::Verbosity log_level = {espp::Logger::Verbosity::WARN}

Verbosity for the logger.