ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
i2c.cpp
Go to the documentation of this file.
1#include "i2c.h"
2
4#include "esphome/core/hal.h"
5#include "esphome/core/log.h"
6
7namespace esphome::i2c {
8
9ESPHOME_LOG_TAG(TAG, "i2c");
10
12 for (uint8_t address = 8; address != 120; address++) {
13 auto err = write_readv(address, nullptr, 0, nullptr, 0);
14 if (err == ERROR_OK) {
15 scan_results_.emplace_back(address, true);
16 } else if (err == ERROR_UNKNOWN) {
17 scan_results_.emplace_back(address, false);
18 }
19 // it takes 16sec to scan on nrf52. It prevents board reset.
21 }
22}
23
24void log_wrong_chip_id(uint8_t id, uint8_t expected) {
25 ESP_LOGE(TAG, "Wrong chip ID 0x%02X, expected 0x%02X", id, expected);
26}
27
28ErrorCode I2CDevice::read_register(uint8_t a_register, uint8_t *data, size_t len) {
29 return bus_->write_readv(this->address_, &a_register, 1, data, len);
30}
31
32ErrorCode I2CDevice::read_register16(uint16_t a_register, uint8_t *data, size_t len) {
33 a_register = convert_big_endian(a_register);
34 return bus_->write_readv(this->address_, reinterpret_cast<const uint8_t *>(&a_register), 2, data, len);
35}
36
37ErrorCode I2CDevice::write_register(uint8_t a_register, const uint8_t *data, size_t len) const {
38 SmallBufferWithHeapFallback<17> buffer_alloc(len + 1); // Most I2C writes are <= 16 bytes
39 uint8_t *buffer = buffer_alloc.get();
40
41 buffer[0] = a_register;
42 std::copy(data, data + len, buffer + 1);
43 return this->bus_->write_readv(this->address_, buffer, len + 1, nullptr, 0);
44}
45
46ErrorCode I2CDevice::write_register16(uint16_t a_register, const uint8_t *data, size_t len) const {
47 SmallBufferWithHeapFallback<18> buffer_alloc(len + 2); // Most I2C writes are <= 16 bytes + 2 for register
48 uint8_t *buffer = buffer_alloc.get();
49
50 buffer[0] = a_register >> 8;
51 buffer[1] = a_register;
52 std::copy(data, data + len, buffer + 2);
53 return this->bus_->write_readv(this->address_, buffer, len + 2, nullptr, 0);
54}
55
56bool I2CDevice::write_registers(const I2CRegValue *table, size_t count) const {
57 for (size_t i = 0; i < count; i++) {
58 I2CRegValue entry;
59 progmem_memcpy(&entry, &table[i], sizeof(entry));
60 if (this->bus_->write_readv(this->address_, reinterpret_cast<const uint8_t *>(&entry), sizeof(entry), nullptr, 0) !=
61 ERROR_OK) {
62 ESP_LOGW(TAG, "Writing register 0x%02X (table entry %u) to 0x%02X failed", entry.reg, static_cast<unsigned>(i),
63 this->address_);
64 return false;
65 }
66 }
67 return true;
68}
69
70bool I2CDevice::read_bytes_16(uint8_t a_register, uint16_t *data, uint8_t len) {
71 if (read_register(a_register, reinterpret_cast<uint8_t *>(data), len * 2) != ERROR_OK)
72 return false;
73 for (size_t i = 0; i < len; i++)
74 data[i] = i2ctohs(data[i]);
75 return true;
76}
77
78bool I2CDevice::update_register(uint8_t a_register, uint8_t mask, uint8_t value) {
79 uint8_t data;
80 if (!this->read_byte(a_register, &data))
81 return false;
82 const uint8_t updated = (data & ~mask) | (value & mask);
83 ESP_LOGV(TAG, "Register 0x%02X: 0x%02X -> 0x%02X", a_register, data, updated);
84 return this->write_byte(a_register, updated);
85}
86
87bool I2CDevice::write_bytes_16(uint8_t a_register, const uint16_t *data, uint8_t len) const {
88 const size_t size = 1 + len * 2;
89 SmallBufferWithHeapFallback<17> buffer_alloc(size); // Register plus up to 8 words
90 uint8_t *buffer = buffer_alloc.get();
91
92 buffer[0] = a_register;
93 for (size_t i = 0; i < len; i++) {
94 const uint16_t word = data[i];
95 buffer[1 + i * 2] = word >> 8;
96 buffer[2 + i * 2] = word;
97 }
98 return this->bus_->write_readv(this->address_, buffer, size, nullptr, 0) == ERROR_OK;
99}
100
101bool I2CDevice::write_byte_16(uint8_t a_register, uint16_t data) const {
102 const uint8_t buffer[3] = {a_register, static_cast<uint8_t>(data >> 8), static_cast<uint8_t>(data)};
103 return this->bus_->write_readv(this->address_, buffer, sizeof(buffer), nullptr, 0) == ERROR_OK;
104}
105
106bool I2CDevice::write_byte_16_le(uint8_t a_register, uint16_t data) const {
107 const uint8_t buffer[3] = {a_register, static_cast<uint8_t>(data), static_cast<uint8_t>(data >> 8)};
108 return this->bus_->write_readv(this->address_, buffer, sizeof(buffer), nullptr, 0) == ERROR_OK;
109}
110
112 this->parent_->write_register(this->register_, &value, 1);
113 return *this;
114}
116 value &= get();
117 this->parent_->write_register(this->register_, &value, 1);
118 return *this;
119}
121 value |= get();
122 this->parent_->write_register(this->register_, &value, 1);
123 return *this;
124}
125
126uint8_t I2CRegister::get() const {
127 uint8_t value = 0x00;
128 this->parent_->read_register(this->register_, &value, 1);
129 return value;
130}
131
133 this->parent_->write_register16(this->register_, &value, 1);
134 return *this;
135}
137 value &= get();
138 this->parent_->write_register16(this->register_, &value, 1);
139 return *this;
140}
142 value |= get();
143 this->parent_->write_register16(this->register_, &value, 1);
144 return *this;
145}
146
147uint8_t I2CRegister16::get() const {
148 uint8_t value = 0x00;
149 this->parent_->read_register16(this->register_, &value, 1);
150 return value;
151}
152
153} // namespace esphome::i2c
uint8_t address
Definition bl0906.h:4
Helper class for efficient buffer allocation - uses stack for small sizes, heap for large This is use...
Definition helpers.h:827
virtual ErrorCode write_readv(uint8_t address, const uint8_t *write_buffer, size_t write_count, uint8_t *read_buffer, size_t read_count)=0
This virtual method writes bytes to an I2CBus from an array, then reads bytes into an array of ReadBu...
std::vector< std::pair< uint8_t, bool > > scan_results_
array containing scan results
Definition i2c_bus.h:70
void i2c_scan_()
Scans the I2C bus for devices.
Definition i2c.cpp:11
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:37
ErrorCode write_register16(uint16_t a_register, const uint8_t *data, size_t len) const
write an array of bytes to a specific register in the I²C device
Definition i2c.cpp:46
bool write_byte_16_le(uint8_t a_register, uint16_t data) const
Write a 16-bit value least significant byte first.
Definition i2c.cpp:106
bool write_bytes_16(uint8_t a_register, const uint16_t *data, uint8_t len) const
Definition i2c.cpp:87
I2CBus * bus_
pointer to I2CBus instance
Definition i2c.h:325
uint8_t address_
store the address of the device on the bus
Definition i2c.h:327
bool write_byte(uint8_t a_register, uint8_t data) const
Definition i2c.h:312
bool read_byte(uint8_t a_register, uint8_t *data)
Definition i2c.h:272
ErrorCode read_register16(uint16_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:32
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:28
bool read_bytes_16(uint8_t a_register, uint16_t *data, uint8_t len)
Definition i2c.cpp:70
bool write_byte_16(uint8_t a_register, uint16_t data) const
Definition i2c.cpp:101
bool update_register(uint8_t a_register, uint8_t mask, uint8_t value)
Read a register, replace the bits in mask with those of value and write it back.
Definition i2c.cpp:78
bool write_registers(const I2CRegValue *table, size_t count) const
Write each register and value of table in order, stopping at the first failure.
Definition i2c.cpp:56
This class is used to create I2CRegister16 objects that act as proxies to read/write internal registe...
Definition i2c.h:99
uint16_t register_
the internal 16 bits address of the register
Definition i2c.h:134
I2CRegister16 & operator&=(uint8_t value)
overloads the compound &= operator.
Definition i2c.cpp:136
I2CRegister16 & operator|=(uint8_t value)
overloads the compound |= operator.
Definition i2c.cpp:141
I2CDevice * parent_
I2CDevice object pointer.
Definition i2c.h:133
uint8_t get() const
returns the register value
Definition i2c.cpp:147
I2CRegister16 & operator=(uint8_t value)
overloads the = operator.
Definition i2c.cpp:132
This class is used to create I2CRegister objects that act as proxies to read/write internal registers...
Definition i2c.h:44
I2CRegister & operator|=(uint8_t value)
overloads the compound |= operator.
Definition i2c.cpp:120
uint8_t get() const
returns the register value
Definition i2c.cpp:126
I2CRegister & operator&=(uint8_t value)
overloads the compound &= operator.
Definition i2c.cpp:115
I2CDevice * parent_
I2CDevice object pointer.
Definition i2c.h:78
uint8_t register_
the internal address of the register
Definition i2c.h:79
I2CRegister & operator=(uint8_t value)
overloads the = operator.
Definition i2c.cpp:111
unsigned count
Definition gif.cpp:51
uint32_t buffer
Definition gif.cpp:50
uint16_t i2ctohs(uint16_t i2cshort)
Definition i2c.h:139
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
Definition i2c_bus.h:13
@ ERROR_OK
No error found during execution of method.
Definition i2c_bus.h:15
@ ERROR_UNKNOWN
miscellaneous I2C error during execution
Definition i2c_bus.h:21
void log_wrong_chip_id(uint8_t id, uint8_t expected)
Out of line so each check_chip_id() caller only pays for a call.
Definition i2c.cpp:24
ESPHOME_LOG_TAG(TAG, "i2c")
constexpr T convert_big_endian(T val)
Convert a value between host byte order and big endian (most significant byte first) order.
Definition helpers.h:1098
void progmem_memcpy(void *dst, const void *src, size_t len)
Definition hal.h:56
const void size_t len
Definition hal.h:68
uint16_t size
Definition helpers.cpp:34
void arch_feed_wdt()
Definition hal.cpp:58
One register write for I2CDevice::write_registers(); tables of these may live in PROGMEM.
Definition i2c.h:18