23#include <idfxx/intr_alloc>
27#include <frequency/frequency>
28#include <initializer_list>
54#if SOC_HP_I2C_NUM >= 2
57#if SOC_LP_I2C_NUM >= 1
72#if SOC_I2C_SUPPORT_APB
75#if SOC_I2C_SUPPORT_REF_TICK
78#if SOC_I2C_SUPPORT_XTAL
81#if SOC_I2C_SUPPORT_RTC
86#if SOC_LP_I2C_SUPPORTED
132#if SOC_LP_I2C_SUPPORTED
142#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
228 return _mux->try_lock();
266 template<
typename Rep,
typename Period>
268 return _scan_devices(std::chrono::ceil<std::chrono::milliseconds>(
timeout));
271#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
291 template<
typename Rep,
typename Period>
293 unwrap(_probe(address, std::chrono::ceil<std::chrono::milliseconds>(
timeout)));
314 template<
typename Rep,
typename Period>
316 return _probe(address, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
359 freq::hertz scl_speed{0};
361 bool addr_10bit =
false;
362 bool disable_ack_check =
false;
365#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
457#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
474 template<
typename Rep,
typename Period>
494 template<
typename Rep,
typename Period>
496 if (_handle ==
nullptr) {
499 return _bus->try_probe(_address, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
502#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
522 template<
typename Rep,
typename Period>
523 void transmit(std::span<const uint8_t> data,
const std::chrono::duration<Rep, Period>&
timeout) {
548 template<
typename Rep,
typename Period>
573 template<
typename Rep,
typename Period>
576 return try_transmit(data.data(), data.size(),
timeout);
600 template<
typename Rep,
typename Period>
603 return _try_transmit(
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
606#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
630 template<
typename Rep,
typename Period>
656 template<
typename Rep,
typename Period>
680 template<
typename Rep,
typename Period>
703 template<
typename Rep,
typename Period>
706 std::vector<uint8_t>
buf(size);
707 return try_receive(
buf,
timeout).transform([&]() {
return buf; });
731 template<
typename Rep,
typename Period>
734 return _try_receive(
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
754 template<
typename Rep,
typename Period>
759#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
781 template<
typename Rep,
typename Period>
809 template<
typename Rep,
typename Period>
837 template<
typename Rep,
typename Period>
866 template<
typename Rep,
typename Period>
871 const std::chrono::duration<Rep, Period>&
timeout
873 return _try_write_register(
reg,
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
876#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
888 unwrap(try_write_register(high, low,
buf));
902 template<
typename Rep,
typename Period>
906 std::span<const uint8_t>
buf,
907 const std::chrono::duration<Rep, Period>&
timeout
924 unwrap(try_write_register(high, low,
buf, size));
939 template<
typename Rep,
typename Period>
945 const std::chrono::duration<Rep, Period>&
timeout
974 template<
typename Rep,
typename Period>
978 std::span<const uint8_t>
buf,
979 const std::chrono::duration<Rep, Period>&
timeout
981 return try_write_register(high, low,
buf.data(),
buf.size(),
timeout);
1009 template<
typename Rep,
typename Period>
1015 const std::chrono::duration<Rep, Period>&
timeout
1017 return _try_write_register(high, low,
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
1020#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
1044 template<
typename Rep,
typename Period>
1047 std::span<const uint8_t>
buf,
1048 const std::chrono::duration<Rep, Period>&
timeout
1078 template<
typename Rep,
typename Period>
1083 const std::chrono::duration<Rep, Period>&
timeout
1114 template<
typename Rep,
typename Period>
1116 std::initializer_list<uint16_t>
registers,
1117 std::span<const uint8_t>
buf,
1118 const std::chrono::duration<Rep, Period>&
timeout
1148 template<
typename Rep,
typename Period>
1150 std::initializer_list<uint16_t>
registers,
1153 const std::chrono::duration<Rep, Period>&
timeout
1180 template<
typename Rep,
typename Period>
1183 std::span<const uint8_t>
buf,
1184 const std::chrono::duration<Rep, Period>&
timeout
1213 template<
typename Rep,
typename Period>
1218 const std::chrono::duration<Rep, Period>&
timeout
1220 return _try_write_registers(
registers,
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
1248 template<
typename Rep,
typename Period>
1250 std::initializer_list<uint16_t>
registers,
1251 std::span<const uint8_t>
buf,
1252 const std::chrono::duration<Rep, Period>&
timeout
1268 return try_write_registers(std::span<const uint16_t>{
registers.begin(),
registers.size()},
buf, size);
1281 template<
typename Rep,
typename Period>
1283 std::initializer_list<uint16_t>
registers,
1286 const std::chrono::duration<Rep, Period>&
timeout
1291#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
1304 return unwrap(try_read_register(
reg, size));
1319 template<
typename Rep,
typename Period>
1346 template<
typename Rep,
typename Period>
1374 template<
typename Rep,
typename Period>
1401 template<
typename Rep,
typename Period>
1404 std::vector<uint8_t>
buf(size);
1405 return try_read_register(
reg,
buf,
timeout).transform([&]() {
return buf; });
1428 template<
typename Rep,
typename Period>
1457 template<
typename Rep,
typename Period>
1460 return _try_read_register(
reg,
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
1463#ifdef CONFIG_COMPILER_CXX_EXCEPTIONS
1477 return unwrap(try_read_register(high, low, size));
1493 template<
typename Rep,
typename Period>
1511 unwrap(try_read_register(high, low,
buf, size));
1526 template<
typename Rep,
typename Period>
1532 const std::chrono::duration<Rep, Period>&
timeout
1561 template<
typename Rep,
typename Period>
1564 std::vector<uint8_t>
buf(size);
1565 return try_read_register(high, low,
buf,
timeout).transform([&]() {
return buf; });
1591 template<
typename Rep,
typename Period>
1595 std::span<uint8_t>
buf,
1596 const std::chrono::duration<Rep, Period>&
timeout
1598 return try_read_register(high, low,
buf.data(),
buf.size(),
timeout);
1626 template<
typename Rep,
typename Period>
1632 const std::chrono::duration<Rep, Period>&
timeout
1634 return _try_read_register(high, low,
buf, size, std::chrono::ceil<std::chrono::milliseconds>(
timeout));
1682#if SOC_HP_I2C_NUM >= 2
1683 case i2c::port::i2c1:
1686#if SOC_LP_I2C_NUM >= 1
1687 case i2c::port::lp_i2c0:
1691 return "unknown(" + std::to_string(
static_cast<int>(
p)) +
")";
1697#include "sdkconfig.h"
1698#ifdef CONFIG_IDFXX_STD_FORMAT
1704struct formatter<
idfxx::i2c::port> {
1705 constexpr auto parse(format_parse_context& ctx) {
return ctx.begin(); }
1707 template<
typename FormatContext>
1710 return std::copy(s.begin(), s.end(), ctx.out());
static constexpr gpio nc()
Returns a GPIO representing "not connected".
I2C master bus controller with thread-safe device access.
master_bus(enum port port, gpio sda, gpio scl, freq::hertz frequency)
Creates a new I2C master bus with default settings.
result< void > try_probe(uint16_t address) const
Probes for a device at the specified address.
std::vector< uint8_t > scan_devices() const
Scans for devices on the bus.
enum port port() const
Returns the I2C port.
std::vector< uint8_t > scan_devices(const std::chrono::duration< Rep, Period > &timeout) const
Scans for devices on the bus.
void probe(uint16_t address, const std::chrono::duration< Rep, Period > &timeout) const
Probes for a device at the specified address.
master_bus & operator=(const master_bus &)=delete
static result< master_bus > make(enum port port, gpio sda, gpio scl, freq::hertz frequency)
Creates a new I2C master bus with default settings.
result< void > try_probe(uint16_t address, const std::chrono::duration< Rep, Period > &timeout) const
Probes for a device at the specified address.
static result< master_bus > make(enum port port, const struct config &config)
Creates a new I2C master bus.
i2c_master_bus_handle_t handle() const
Returns the underlying ESP-IDF bus handle.
freq::hertz frequency() const
Returns the bus clock frequency in Hz.
void unlock() const
Releases exclusive access to the bus.
master_bus(const master_bus &)=delete
master_bus(master_bus &&other) noexcept
bool try_lock() const noexcept
Tries to acquire exclusive access without blocking.
master_bus(enum port port, const struct config &config)
Creates a new I2C master bus.
void probe(uint16_t address) const
Probes for a device at the specified address.
void lock() const
Acquires exclusive access to the bus.
master_bus & operator=(master_bus &&other) noexcept
I2C device at a specific address with register operations.
void transmit(const uint8_t *buf, size_t size)
Transmits data to the device.
result< void > try_write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
result< void > try_probe() const
Probes the device.
result< void > try_read_register(uint16_t reg, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
void read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size)
Reads data from a register.
void write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
result< void > try_write_register(uint16_t reg, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
result< std::vector< uint8_t > > try_receive(size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
void write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
void write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf)
Writes data to a register.
void write_register(uint16_t reg, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
result< void > try_write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
void write_register(uint16_t reg, const uint8_t *buf, size_t size)
Writes data to a register.
result< void > try_write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
void write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
std::vector< uint8_t > read_register(uint16_t reg, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
master_device(master_bus &bus, uint16_t address)
Creates a new device on the specified bus.
result< std::vector< uint8_t > > try_read_register(uint16_t reg, size_t size)
Reads data from a register.
void write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
result< void > try_write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
void write_register(uint16_t reg, std::span< const uint8_t > buf)
Writes data to a register.
result< void > try_read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
void read_register(uint16_t reg, std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
result< void > try_write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
void write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
result< void > try_write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
result< void > try_write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
result< void > try_read_register(uint16_t reg, std::span< uint8_t > buf)
Reads data from a register.
result< void > try_write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size)
Writes data to a register.
void transmit(std::span< const uint8_t > data, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
void receive(uint8_t *buf, size_t size)
Receives data from the device.
void probe() const
Probes the device.
result< void > try_read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size)
Reads data from a register.
void receive(uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
result< void > try_receive(uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
void probe(const std::chrono::duration< Rep, Period > &timeout) const
Probes the device.
result< std::vector< uint8_t > > try_receive(size_t size)
Receives data from the device.
result< void > try_write_register(uint8_t high, uint8_t low, std::span< const uint8_t > buf)
Writes data to a register.
result< std::vector< uint8_t > > try_read_register(uint8_t high, uint8_t low, size_t size)
Reads data from a register.
result< std::vector< uint8_t > > try_read_register(uint8_t high, uint8_t low, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
void read_register(uint8_t high, uint8_t low, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
result< void > try_read_register(uint8_t high, uint8_t low, std::span< uint8_t > buf)
Reads data from a register.
master_device(const master_device &)=delete
std::vector< uint8_t > read_register(uint8_t high, uint8_t low, size_t size)
Reads data from a register.
result< void > try_write_register(uint16_t reg, std::span< const uint8_t > buf)
Writes data to a register.
result< void > try_write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
result< void > try_write_register(uint16_t reg, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
void transmit(std::span< const uint8_t > data)
Transmits data to the device.
master_device(master_device &&other) noexcept
void write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
static result< master_device > make(master_bus &bus, uint16_t address, const struct config &config)
Creates a new device on the specified bus.
void write_registers(std::initializer_list< uint16_t > registers, const uint8_t *buf, size_t size)
Writes data to multiple registers.
master_device(master_bus &bus, uint16_t address, const struct config &config)
Creates a new device on the specified bus.
void write_register(uint16_t reg, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
result< std::vector< uint8_t > > try_read_register(uint16_t reg, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
uint16_t address() const
Returns the device address.
result< void > try_read_register(uint8_t high, uint8_t low, std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
void read_register(uint16_t reg, uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
result< void > try_transmit(const uint8_t *buf, size_t size)
Transmits data to the device.
void write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to a register.
result< void > try_receive(std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
result< void > try_receive(uint8_t *buf, size_t size)
Receives data from the device.
i2c_master_dev_handle_t handle() const
Returns the underlying ESP-IDF device handle.
void read_register(uint16_t reg, std::span< uint8_t > buf)
Reads data from a register.
void transmit(const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
result< void > try_write_register(uint16_t reg, const uint8_t *buf, size_t size)
Writes data to a register.
result< void > try_receive(std::span< uint8_t > buf)
Receives data from the device.
std::vector< uint8_t > read_register(uint8_t high, uint8_t low, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
result< void > try_read_register(uint16_t reg, uint8_t *buf, size_t size)
Reads data from a register.
result< void > try_transmit(const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
result< void > try_transmit(std::span< const uint8_t > data)
Transmits data to the device.
void write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
std::vector< uint8_t > receive(size_t size)
Receives data from the device.
std::vector< uint8_t > read_register(uint16_t reg, size_t size)
Reads data from a register.
result< void > try_write_registers(std::span< const uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
result< void > try_transmit(std::span< const uint8_t > data, const std::chrono::duration< Rep, Period > &timeout)
Transmits data to the device.
std::vector< uint8_t > receive(size_t size, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
result< void > try_write_registers(std::initializer_list< uint16_t > registers, std::span< const uint8_t > buf)
Writes data to multiple registers.
master_device & operator=(const master_device &)=delete
master_device & operator=(master_device &&other) noexcept
void write_register(uint8_t high, uint8_t low, const uint8_t *buf, size_t size)
Writes data to a register.
result< void > try_probe(const std::chrono::duration< Rep, Period > &timeout) const
Probes the device.
void receive(std::span< uint8_t > buf)
Receives data from the device.
void write_registers(std::span< const uint16_t > registers, const uint8_t *buf, size_t size, const std::chrono::duration< Rep, Period > &timeout)
Writes data to multiple registers.
void read_register(uint16_t reg, uint8_t *buf, size_t size)
Reads data from a register.
master_bus & bus() const
Returns the parent bus.
result< void > try_read_register(uint16_t reg, std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Reads data from a register.
static result< master_device > make(master_bus &bus, uint16_t address)
Creates a new device on the specified bus.
void receive(std::span< uint8_t > buf, const std::chrono::duration< Rep, Period > &timeout)
Receives data from the device.
std::string to_string(core_id c)
Returns a string representation of a CPU core identifier.
struct i2c_master_bus_t * i2c_master_bus_handle_t
struct i2c_master_dev_t * i2c_master_dev_handle_t
clk_source
I2C master bus clock source.
port
I2C port identifiers.
static constexpr auto DEFAULT_TIMEOUT
Default timeout for I2C operations.
@ default_source
Default clock source for the target.
I2C master driver classes.
intr_level
Hardware interrupt priority levels.
constexpr std::unexpected< std::error_code > error(E e) noexcept
Creates an unexpected error from an error code enum.
T unwrap(result< T > result)
Throws a std::system_error if the result is an error.
@ invalid_state
Invalid state.
@ timeout
Operation timed out.
std::expected< T, std::error_code > result
result type wrapping a value or error code.
I2C master bus configuration.
freq::hertz frequency
Clock frequency in Hz.
bool allow_pd
Allow powering down the bus during light sleep.
idfxx::gpio scl
GPIO pin for the SCL line.
idfxx::gpio sda
GPIO pin for the SDA line.
size_t trans_queue_depth
Depth of internal transfer queue for asynchronous transactions.
uint8_t glitch_ignore_cnt
Glitch filter count (0-7). Higher values filter more noise.
bool enable_internal_pullup
Enable internal pull-up resistors on SDA and SCL.
I2C device configuration.