KTS1622 I/O Expander

The KTS1622 I/O expander component allows the user to configure inputs, outputs, interrupts, etc. via a serial interface such as I2C.

API Reference

Header File

Classes

class Kts1622 : public espp::BasePeripheral<>

Class for communicating with and controlling a KTS1622 GPIO expander including interrupt configuration. It supports 16 GPIO pins, 8 on each port, and can support optional input debounce timing (only P0_1-P0_7 and P1_0-P1_7, with P0_0 as clock input) and interrupt memory with trigger/mask/clear/status features. It supports up to 1MHz Fast-mode Plus I2C and can operate [1.65, 5.5]V on the I2C bus and I/O pins (with separate power pins for each).

KTS1622 Example

  // make the I2C that we'll use to communicate
  espp::I2c i2c({
      .port = I2C_NUM_1,
      .sda_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SDA_GPIO,
      .scl_io_num = (gpio_num_t)CONFIG_EXAMPLE_I2C_SCL_GPIO,
      .sda_pullup_en = GPIO_PULLUP_ENABLE,
      .scl_pullup_en = GPIO_PULLUP_ENABLE,
      .clk_speed = 1000 * 1000, // 1MHz
  });

  // now make the kts1622 which handles GPIO
  espp::Kts1622 kts1622(
      {.device_address = espp::Kts1622::DEFAULT_ADDRESS,
       // set P0_0 - P0_7 to be inputs
       .port_0_direction_mask = 0b11111111,
       // set P1_0 - P1_7 to be inputs
       .port_1_direction_mask = 0b11111111,
       .write = std::bind(&espp::I2c::write, &i2c, std::placeholders::_1, std::placeholders::_2,
                          std::placeholders::_3),
       .write_then_read =
           std::bind(&espp::I2c::write_read, &i2c, std::placeholders::_1, std::placeholders::_2,
                     std::placeholders::_3, std::placeholders::_4, std::placeholders::_5),
       .auto_init = false,
       .log_level = espp::Logger::Verbosity::INFO});
  std::error_code ec;
  kts1622.initialize(
      ec); // Initialized separately from the constructor since we set auto_init to false
  if (ec) {
    logger.error("kts1622 initialization failed: {}", ec.message());
    return;
  }

  // and finally, make the task to periodically poll the kts1622 and print
  // the state. NOTE: the Kts1622 does not internally manage its own state
  // update, so whatever rate we use here is the rate at which the state will
  // update.
  auto task_fn = [&](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 seconds = std::chrono::duration<float>(now - start).count();
    // returns the pins as P0_0 lsb, P1_7 msb
    auto pins = kts1622.get_pins(ec);
    if (ec) {
      logger.error("kts1622 get pins failed: {}", ec.message());
      return true; // stop the task
    }
    // equivalent to:
    // auto pins = (kts1622.get_pins(espp::Kts1622::Port::PORT1, ec) << 8) |
    // kts1622.get_pins(espp::Kts1622::Port::PORT0, ec);
    fmt::print("{:.3f}, {:#x}\n", seconds, pins);
    // NOTE: sleeping in this way allows the sleep to exit early when the
    // task is being stopped / destroyed
    {
      std::unique_lock<std::mutex> lk(m);
      cv.wait_for(lk, 50ms);
    }
    // don't want to stop the task
    return false;
  };
  auto task = espp::Task({.callback = task_fn,
                          .task_config =
                              {
                                  .name = "Kts1622 Task",
                                  .stack_size_bytes = 5 * 1024,
                              },
                          .log_level = espp::Logger::Verbosity::WARN});
  fmt::print("% time(s), pin values\n");
  task.start();

Public Types

enum class Port

The two GPIO ports the Kts1622 has.

Values:

enumerator PORT0

Port 0.

enumerator PORT1

Port 1.

enum class OutputDriveMode : int

The output drive mode configuration.

Values:

enumerator PUSH_PULL

In this mode it needs no pull-up resistor.

enumerator OPEN_DRAIN

In this mode it needs a pull-up reistor. This is the default mode.

enum class OutputDriveStrength : uint8_t

The output drive mode configuration.

Values:

enumerator F_0_25

0.25x drive capability of the I/O pins

enumerator F_0_5

0.5x drive capability of the I/O pins

enumerator F_0_75

0.75x drive capability of the I/O pins

enumerator F_1

1x drive capability of the I/O pins

enum class PullResistor : uint8_t

The Pull Resistor configuration.

Values:

enumerator NO_PULL

No pull resistor enabled.

enumerator PULL_UP

Pull-up resistor enabled.

enumerator PULL_DOWN

Pull-down resistor enabled.

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 Kts1622(const Config &config)

Construct the Kts1622. Will call initialize() if auto_init is true.

Parameters

configConfig structure for configuring the KTS1622

inline void initialize(std::error_code &ec)

Initialize the component class.

Parameters

ec – Error code to set if an error occurs.

inline uint8_t get_pins(Port port, std::error_code &ec)

Read the pin values on the provided port.

Parameters
  • port – The Port for which to read the pins

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

Returns

The pin values as an 8 bit mask.

inline uint16_t get_pins(std::error_code &ec)

Read the pin values on both Port 0 and Port 1.

Parameters

ec – Error code to set if an error occurs.

Returns

The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).

inline void output(Port port, uint8_t value, std::error_code &ec)

Write the pin values on the provided port.

Note

This will overwrite any previous pin values on the port for all output pins on the port.

Parameters
  • port – The Port for which to write the pins

  • value – The pin values to apply.

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

inline void output(uint8_t p0, uint8_t p1, std::error_code &ec)

Write the pin values on both Port 0 and Port 1.

Note

This will overwrite any previous pin values on the port for all output pins on the ports.

Parameters
  • p0 – The pin values to apply to Port 0.

  • p1 – The pin values to apply to Port 1.

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

inline void output(uint16_t value, std::error_code &ec)

Write the pin values on both Port 0 and Port 1.

Note

This will overwrite any previous pin values on the port for all output pins on the ports.

Parameters
  • value – The pin values to apply as a 16 bit value (P0_0 lsb, P1_7 msb).

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

inline void clear_pins(Port port, uint8_t mask, std::error_code &ec)

Clear the pin values on the provided port according to the provided mask.

Reads the current pin values and clears any bits set in the mask.

Parameters
  • port – The Port for which to clear the pin outputs.

  • mask – The pin values as an 8 bit mask to clear.

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

inline void clear_pins(uint8_t p0, uint8_t p1, std::error_code &ec)

Clear the pin values for Port 0 and Port 1 according to the provided masks.

Reads the current pin values and clears any bits set in the masks.

Parameters
  • p0 – The pin values as an 8 bit mask for Port 0 to clear.

  • p1 – The pin values as an 8 bit mask for Port 1 to clear.

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

inline void clear_pins(uint16_t mask, std::error_code &ec)

Clear the pin values for Port 0 and Port 1 according to the provided mask.

Reads the current pin values and clears any bits set in the mask.

Parameters
  • mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to clear.

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

inline void set_pins(Port port, uint8_t mask, std::error_code &ec)

Set the pin values on the provided port according to the provided mask.

Reads the current pin values and sets any bits set in the mask.

Parameters
  • port – The Port for which to set the pin outputs.

  • mask – The pin values as an 8 bit mask to set.

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

inline void set_pins(uint8_t p0, uint8_t p1, std::error_code &ec)

Set the pin values for Port 0 and Port 1 according to the provided masks.

Reads the current pin values and sets any bits set in the masks.

Parameters
  • p0 – The pin values for Port 0 as an 8 bit mask to set.

  • p1 – The pin values for Port 1 as an 8 bit mask to set.

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

inline void set_pins(uint16_t mask, std::error_code &ec)

Set the pin values for Port 0 and Port 1 according to the provided mask.

Reads the current pin values and sets any bits set in the mask.

Parameters
  • mask – The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb) to set.

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

inline uint8_t get_output(Port port, std::error_code &ec)

Read the output pin values on the provided port.

Parameters
  • port – The Port for which to read the pins

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

Returns

The pin values as an 8 bit mask.

inline uint16_t get_output(std::error_code &ec)

Read the output pin values on both Port 0 and Port 1.

Parameters

ec – Error code to set if an error occurs.

Returns

The pin values as a 16 bit mask (P0_0 lsb, P1_7 msb).

inline void set_port_output_drive_mode(Port port, OutputDriveMode mode, std::error_code &ec)

Set the output drive mode for the provided pins on the provided port.

Parameters
  • port – The port to set the output drive mode for.

  • mode – The output drive mode to set for the port.

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

inline void enable_interrupt(Port port, uint8_t mask, std::error_code &ec)

Configure the provided pins to interrupt.

Note

You should also call configure_interrupt to configure the interrupt type for the pins.

Parameters
  • port – The port associated with the provided pin mask.

  • mask – The pin mask to configure for interrupt (0=interrupt).

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

inline void enable_interrupt(uint8_t p0, uint8_t p1, std::error_code &ec)

Configure the provided pins to interrupt on change.

Note

You should also call configure_interrupt to configure the interrupt type for the pins.

Parameters
  • p0 – The pin mask for Port 0 to configure for interrupt (0=interrupt).

  • p1 – The pin mask for Port 1 to configure for interrupt (0=interrupt).

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

inline void enable_interrupt(uint16_t mask, std::error_code &ec)

Configure the provided pins to interrupt on change.

Note

You should also call configure_interrupt to configure the interrupt type for the pins.

Parameters
  • mask – The pin mask to configure for interrupt (0=interrupt).

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

inline void configure_interrupt(Port port, uint8_t mask, InterruptType type, std::error_code &ec)

Configure the provided pins to interrupt on the provided type.

See also

enable_interrupt

Note

You should also call enable_interrupt to enable the interrupt for the pins.

Note

This will overwrite any previous interrupt configuration on the port for all pins on the port.

Parameters
  • port – The port associated with the provided pin mask.

  • mask – The pin mask to configure for interrupt.

  • type – The type of interrupt to configure.

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

inline void configure_interrupt(uint8_t p0, uint8_t p1, InterruptType type, std::error_code &ec)

Configure the provided pins to interrupt on the provided type.

See also

enable_interrupt

Note

You should also call enable_interrupt to enable the interrupt for the pins.

Note

This will overwrite any previous interrupt configuration on the port for all pins on the port.

Parameters
  • p0 – The pin mask for Port 0 to configure for interrupt.

  • p1 – The pin mask for Port 1 to configure for interrupt.

  • type – The type of interrupt to configure.

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

inline void clear_interrupt(Port port, uint8_t mask, std::error_code &ec)

Clear the interrupt for the provided pins.

Parameters
  • port – The port associated with the provided pin mask.

  • mask – The pin mask to clear the interrupt for.

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

inline void clear_interrupt(uint8_t p0, uint8_t p1, std::error_code &ec)

Clear the interrupt for the provided pins.

Parameters
  • p0 – The pin mask for Port 0 to clear the interrupt for.

  • p1 – The pin mask for Port 1 to clear the interrupt for.

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

inline void clear_interrupt(uint16_t mask, std::error_code &ec)

Clear the interrupt for the provided pins.

Parameters
  • mask – The pin mask to clear the interrupt for.

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

inline void clear_interrupts(std::error_code &ec)

Clear all interrupts.

Parameters

ec – Error code to set if an error occurs.

inline void set_direction(Port port, uint8_t mask, std::error_code &ec)

Set the i/o direction for the pins according to mask.

Parameters
  • port – The port associated with the provided pin mask.

  • mask – The mask indicating direction (1 = input, 0 = output)

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

inline void set_direction(uint8_t p0, uint8_t p1, std::error_code &ec)

Set the i/o direction for the pins on Port 0 and Port 1.

Parameters
  • p0 – The mask for Port 0 indicating direction (1 = input, 0 = output)

  • p1 – The mask for Port 1 indicating direction (1 = input, 0 = output)

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

inline void set_direction(uint16_t mask, std::error_code &ec)

Set the i/o direction for the pins according to mask.

Parameters
  • mask – The mask indicating direction (1 = input, 0 = output)

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

inline void set_direction(uint16_t mask, bool direction, std::error_code &ec)

Set the i/o direction for the pins according to mask.

Parameters
  • mask – The mask indicating pin position

  • direction – The direction indicating direction (1 = input, 0 = output)

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

inline void set_polarity_inversion(Port port, uint8_t mask, std::error_code &ec)

Set polarity inversion for the pins according to mask.

Note

This will overwrite any previous polarity inversion on the port for all pins on the port.

Note

This will only affect pins configured as inputs.

Parameters
  • port – The port associated with the provided pin mask.

  • mask – The mask indicating polarity inversion (1 = inverted, 0 = normal)

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

inline void set_polarity_inversion(uint8_t p0, uint8_t p1, std::error_code &ec)

Set polarity inversion for the pins on Port 0 and Port 1.

Note

This will overwrite any previous polarity inversion on the port for all pins on the port.

Note

This will only affect pins configured as inputs.

Parameters
  • p0 – The mask for Port 0 indicating polarity inversion (1 = inverted, 0 = normal)

  • p1 – The mask for Port 1 indicating polarity inversion (1 = inverted, 0 = normal)

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

inline void set_polarity_inversion(uint16_t mask, std::error_code &ec)

Set polarity inversion for the pins according to mask.

Note

This will overwrite any previous polarity inversion on the port for all pins on the port.

Note

This will only affect pins configured as inputs.

Parameters
  • mask – The mask indicating polarity inversion (1 = inverted, 0 = normal)

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

inline void set_input_latch(Port port, uint8_t latch, std::error_code &ec)

Set the input latch for the input pins according to latch.

Parameters
  • port – The port associated with the provided pin mask.

  • latch – The value to set the latch register to. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

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

inline void set_input_latch(uint8_t p0, uint8_t p1, std::error_code &ec)

Set the input latch for the input pins on Port 0 and Port 1.

Note

This will overwrite any previous latch values on the port for all input pins on the port.

Parameters
  • p0 – The value to set the latch register to for Port 0. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

  • p1 – The value to set the latch register to for Port 1. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

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

inline void set_input_latch(uint16_t mask, std::error_code &ec)

Set the input latch for the input pins according to latch.

Note

This will overwrite any previous latch values on the port for all input pins on the port.

Parameters
  • mask – The value to set the latch register to. A value of 0 for a bit indicates that the corresponding input is not latched, meaning that a pin configured as an interrupt input will clear the interrupt if it returns to its original state before the interrupt is read.

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

inline void set_pull_resistor_for_pin(Port port, uint8_t pin_mask, PullResistor pull, std::error_code &ec)

Set the pull resistor for the provided pins.

Parameters
  • port – The port associated with the provided pin mask.

  • pin_mask – The pin mask to configure for pull resistor.

  • pull – The pull resistor to configure.

  • 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 = 0x20

Lower 2 bits are configurable via the ADDR pin (GND, VCC, SCL, SDA -> 00, 01, 02, 03)

struct Config

Configuration information for the Kts1622.

Public Members

uint8_t device_address = DEFAULT_ADDRESS

I2C address to use to talk to this KTS1622B.

uint8_t port_0_direction_mask = 0xFF

Direction mask (1 = input) for port 0.

uint8_t port_0_interrupt_mask = 0xFF

Interrupt mask (1 = disable interrupt) for port 0.

uint8_t port_1_direction_mask = 0xFF

Direction mask (1 = input) for port 1.

uint8_t port_1_interrupt_mask = 0xFF

Interrupt mask (1 = disable interrupt) for port 1.

OutputDriveMode output_drive_mode = OutputDriveMode::PUSH_PULL

Output drive mode for the ports.

BasePeripheral::write_fn write

Function to write to the device.

BasePeripheral::write_then_read_fn write_then_read

Function to write then read from the device.

bool auto_init = true

Automatically initialize the device.

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

Log verbosity for the component.