CDC Badge OS
Firmware for the CDC Badge v1.0 hardware security key
Loading...
Searching...
No Matches
I2cBus.cpp
Go to the documentation of this file.
1
5
6#include "cdc_hal/II2cBus.h"
7#include "cdc_hal/hw_config.h"
8#include "driver/i2c.h"
9#include "freertos/FreeRTOS.h"
10#include "freertos/task.h"
11#include "cdc_log.h"
12
13static const char* TAG = "I2cBus";
14
15namespace cdc::hal {
16
18static constexpr uint32_t I2C_FREQ_HZ = 100000; // 100kHz standard mode
19static constexpr uint32_t I2C_TIMEOUT_MS = 100;
20
24struct I2cDevice {
25 i2c_port_t port;
26 uint8_t addr;
27};
28
32class I2cBusImpl : public II2cBus {
33public:
34 I2cBusImpl(i2c_port_t port, gpio_num_t sda, gpio_num_t scl, const char* name)
35 : port_(port), sda_(sda), scl_(scl), name_(name) {}
36
37 // IService implementation
38 bool init() override;
39 bool start() override { return state_ == core::ServiceState::INITIALIZED; }
40 void stop() override {}
41 core::ServiceState getState() const override { return state_; }
42 const char* getName() const override { return name_; }
43
44 // II2cBus implementation
45 esp_err_t addDevice(uint8_t addr, I2cDeviceHandle* out_dev) override;
46 esp_err_t writeReg(I2cDeviceHandle dev, uint8_t reg,
47 const uint8_t* data, size_t len) override;
48 esp_err_t readReg(I2cDeviceHandle dev, uint8_t reg,
49 uint8_t* data, size_t len) override;
50 esp_err_t writeRaw(uint8_t addr, const uint8_t* data, size_t len) override;
51 esp_err_t readRaw(uint8_t addr, uint8_t* data, size_t len) override;
52 esp_err_t writeReadRaw(uint8_t addr, const uint8_t* wr, size_t wr_len,
53 uint8_t* rd, size_t rd_len) override;
54 bool probe(uint8_t addr) override;
55 esp_err_t eepromRead(uint8_t addr, uint16_t offset, uint8_t* buf, size_t len) override;
56 esp_err_t eepromWrite(uint8_t addr, uint16_t offset, const uint8_t* buf, size_t len) override;
57
58private:
59 i2c_port_t port_;
60 gpio_num_t sda_;
61 gpio_num_t scl_;
62 const char* name_;
64
65 // Static device pool (avoid heap allocation)
66 static constexpr size_t MAX_DEVICES = 4;
67 I2cDevice devices_[MAX_DEVICES] = {};
68 size_t deviceCount_ = 0;
69};
70
77 return state_ == core::ServiceState::INITIALIZED;
78 }
79
80 i2c_config_t conf = {};
81 conf.mode = I2C_MODE_MASTER;
82 conf.sda_io_num = sda_;
83 conf.scl_io_num = scl_;
84 conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
85 conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
86 conf.master.clk_speed = I2C_FREQ_HZ;
87 conf.clk_flags = 0;
88
89 esp_err_t err = i2c_param_config(port_, &conf);
90 if (err != ESP_OK) {
91 LOG_E(TAG, "%s: i2c_param_config failed: %d", name_, err);
93 return false;
94 }
95
96 err = i2c_driver_install(port_, I2C_MODE_MASTER, 0, 0, 0);
97 if (err != ESP_OK) {
98 LOG_E(TAG, "%s: i2c_driver_install failed: %d", name_, err);
100 return false;
101 }
102
104 LOG_I(TAG, "%s initialized (SDA=%d, SCL=%d)", name_, sda_, scl_);
105 return true;
106}
107
114esp_err_t I2cBusImpl::addDevice(uint8_t addr, I2cDeviceHandle* out_dev) {
115 if (deviceCount_ >= MAX_DEVICES) {
116 LOG_E(TAG, "%s: device pool full", name_);
117 return ESP_ERR_NO_MEM;
118 }
119
120 I2cDevice* dev = &devices_[deviceCount_++];
121 dev->port = port_;
122 dev->addr = addr;
123 *out_dev = dev;
124
125 LOG_I(TAG, "%s: added device at 0x%02X", name_, addr);
126 return ESP_OK;
127}
128
137esp_err_t I2cBusImpl::writeReg(I2cDeviceHandle handle, uint8_t reg,
138 const uint8_t* data, size_t len) {
139 auto* dev = static_cast<I2cDevice*>(handle);
140 if (!dev) return ESP_ERR_INVALID_ARG;
141
142 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
143 i2c_master_start(cmd);
144 i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true);
145 i2c_master_write_byte(cmd, reg, true);
146 if (data && len > 0) {
147 i2c_master_write(cmd, data, len, true);
148 }
149 i2c_master_stop(cmd);
150
151 esp_err_t err = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(I2C_TIMEOUT_MS));
152 i2c_cmd_link_delete(cmd);
153
154 return err;
155}
156
165esp_err_t I2cBusImpl::readReg(I2cDeviceHandle handle, uint8_t reg,
166 uint8_t* data, size_t len) {
167 auto* dev = static_cast<I2cDevice*>(handle);
168 if (!dev || !data || len == 0) return ESP_ERR_INVALID_ARG;
169
170 // Write register address
171 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
172 i2c_master_start(cmd);
173 i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_WRITE, true);
174 i2c_master_write_byte(cmd, reg, true);
175
176 // Repeated start and read
177 i2c_master_start(cmd);
178 i2c_master_write_byte(cmd, (dev->addr << 1) | I2C_MASTER_READ, true);
179 if (len > 1) {
180 i2c_master_read(cmd, data, len - 1, I2C_MASTER_ACK);
181 }
182 i2c_master_read_byte(cmd, data + len - 1, I2C_MASTER_NACK);
183 i2c_master_stop(cmd);
184
185 esp_err_t err = i2c_master_cmd_begin(dev->port, cmd, pdMS_TO_TICKS(I2C_TIMEOUT_MS));
186 i2c_cmd_link_delete(cmd);
187
188 return err;
189}
190
191esp_err_t I2cBusImpl::writeRaw(uint8_t addr, const uint8_t* data, size_t len) {
192 if (!data && len > 0) return ESP_ERR_INVALID_ARG;
193 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
194 i2c_master_start(cmd);
195 i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
196 if (len > 0) i2c_master_write(cmd, data, len, true);
197 i2c_master_stop(cmd);
198 esp_err_t err = i2c_master_cmd_begin(port_, cmd, pdMS_TO_TICKS(I2C_TIMEOUT_MS));
199 i2c_cmd_link_delete(cmd);
200 return err;
201}
202
203esp_err_t I2cBusImpl::readRaw(uint8_t addr, uint8_t* data, size_t len) {
204 if (!data || len == 0) return ESP_ERR_INVALID_ARG;
205 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
206 i2c_master_start(cmd);
207 i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, true);
208 i2c_master_read(cmd, data, len, I2C_MASTER_LAST_NACK);
209 i2c_master_stop(cmd);
210 esp_err_t err = i2c_master_cmd_begin(port_, cmd, pdMS_TO_TICKS(I2C_TIMEOUT_MS));
211 i2c_cmd_link_delete(cmd);
212 return err;
213}
214
215esp_err_t I2cBusImpl::writeReadRaw(uint8_t addr, const uint8_t* wr, size_t wr_len,
216 uint8_t* rd, size_t rd_len) {
217 if ((!wr && wr_len > 0) || !rd || rd_len == 0) return ESP_ERR_INVALID_ARG;
218 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
219 i2c_master_start(cmd);
220 i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
221 if (wr_len > 0) i2c_master_write(cmd, wr, wr_len, true);
222 i2c_master_start(cmd);
223 i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_READ, true);
224 i2c_master_read(cmd, rd, rd_len, I2C_MASTER_LAST_NACK);
225 i2c_master_stop(cmd);
226 esp_err_t err = i2c_master_cmd_begin(port_, cmd, pdMS_TO_TICKS(I2C_TIMEOUT_MS));
227 i2c_cmd_link_delete(cmd);
228 return err;
229}
230
231bool I2cBusImpl::probe(uint8_t addr) {
232 i2c_cmd_handle_t cmd = i2c_cmd_link_create();
233 i2c_master_start(cmd);
234 i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true);
235 i2c_master_stop(cmd);
236 esp_err_t err = i2c_master_cmd_begin(port_, cmd, pdMS_TO_TICKS(20));
237 i2c_cmd_link_delete(cmd);
238 return err == ESP_OK;
239}
240
241esp_err_t I2cBusImpl::eepromRead(uint8_t addr, uint16_t offset, uint8_t* buf, size_t len) {
242 if (!buf || len == 0) return ESP_ERR_INVALID_ARG;
243 uint8_t reg[2] = { static_cast<uint8_t>(offset >> 8), static_cast<uint8_t>(offset & 0xff) };
244 return writeReadRaw(addr, reg, sizeof(reg), buf, len);
245}
246
247esp_err_t I2cBusImpl::eepromWrite(uint8_t addr, uint16_t offset, const uint8_t* buf, size_t len) {
248 if (!buf || len == 0) return ESP_ERR_INVALID_ARG;
249 constexpr size_t PAGE = 16; // 24Cxx page; a write must not cross a page boundary
250 size_t written = 0;
251 while (written < len) {
252 uint16_t cur = static_cast<uint16_t>(offset + written);
253 size_t room = PAGE - (cur % PAGE);
254 size_t chunk = (len - written < room) ? (len - written) : room;
255 uint8_t frame[2 + PAGE];
256 frame[0] = static_cast<uint8_t>(cur >> 8);
257 frame[1] = static_cast<uint8_t>(cur & 0xff);
258 for (size_t i = 0; i < chunk; ++i) frame[2 + i] = buf[written + i];
259 esp_err_t err = writeRaw(addr, frame, 2 + chunk);
260 if (err != ESP_OK) return err;
261 vTaskDelay(pdMS_TO_TICKS(5)); // EEPROM self-timed write cycle
262 written += chunk;
263 }
264 return ESP_OK;
265}
266
268static I2cBusImpl g_i2c0(I2C_NUM_0, I2C0_SDA_PIN, I2C0_SCL_PIN, "i2c0");
269static I2cBusImpl g_i2c1(I2C_NUM_1, I2C1_SDA_PIN, I2C1_SCL_PIN, "i2c1");
270
275II2cBus* getI2cBus0() { return &g_i2c0; }
280II2cBus* getI2cBus1() { return &g_i2c1; }
281
282} // namespace cdc::hal
static const char * TAG
char name[cdc::hal::ISecureElement::RMEM_NAME_LEN]
CDC Log: logging over TinyUSB CDC and UART.
#define LOG_I(tag, fmt,...)
Definition cdc_log.h:147
#define LOG_E(tag, fmt,...)
Definition cdc_log.h:145
core::ServiceState getState() const override
Definition I2cBus.cpp:41
esp_err_t writeReadRaw(uint8_t addr, const uint8_t *wr, size_t wr_len, uint8_t *rd, size_t rd_len) override
Definition I2cBus.cpp:215
bool init() override
Initializes hardware I2C controller and driver.
Definition I2cBus.cpp:75
esp_err_t readRaw(uint8_t addr, uint8_t *data, size_t len) override
Definition I2cBus.cpp:203
bool probe(uint8_t addr) override
Definition I2cBus.cpp:231
void stop() override
Definition I2cBus.cpp:40
esp_err_t addDevice(uint8_t addr, I2cDeviceHandle *out_dev) override
Registers an I2C target device in static device pool.
Definition I2cBus.cpp:114
const char * getName() const override
Definition I2cBus.cpp:42
esp_err_t eepromRead(uint8_t addr, uint16_t offset, uint8_t *buf, size_t len) override
Definition I2cBus.cpp:241
esp_err_t writeRaw(uint8_t addr, const uint8_t *data, size_t len) override
Definition I2cBus.cpp:191
bool start() override
Definition I2cBus.cpp:39
I2cBusImpl(i2c_port_t port, gpio_num_t sda, gpio_num_t scl, const char *name)
Definition I2cBus.cpp:34
esp_err_t eepromWrite(uint8_t addr, uint16_t offset, const uint8_t *buf, size_t len) override
Definition I2cBus.cpp:247
esp_err_t writeReg(I2cDeviceHandle dev, uint8_t reg, const uint8_t *data, size_t len) override
Writes bytes to a register of an I2C device.
Definition I2cBus.cpp:137
esp_err_t readReg(I2cDeviceHandle dev, uint8_t reg, uint8_t *data, size_t len) override
Reads bytes from a register of an I2C device.
Definition I2cBus.cpp:165
#define I2C0_SDA_PIN
Definition hw_config.h:10
#define I2C0_SCL_PIN
Definition hw_config.h:11
#define I2C1_SDA_PIN
Definition hw_config.h:14
#define I2C1_SCL_PIN
Definition hw_config.h:15
II2cBus * getI2cBus1()
Returns singleton instance of I2C bus 1.
Definition I2cBus.cpp:280
II2cBus * getI2cBus0()
Returns singleton instance of I2C bus 0.
Definition I2cBus.cpp:275
void * I2cDeviceHandle
Definition II2cBus.h:10
static constexpr uint32_t I2C_TIMEOUT_MS
Definition I2cBus.cpp:19
static I2cBusImpl g_i2c0(I2C_NUM_0, I2C0_SDA_PIN, I2C0_SCL_PIN, "i2c0")
Singleton instances for both hardware I2C ports.
static constexpr uint32_t I2C_FREQ_HZ
I2C bus timing configuration constants.
Definition I2cBus.cpp:18
static I2cBusImpl g_i2c1(I2C_NUM_1, I2C1_SDA_PIN, I2C1_SCL_PIN, "i2c1")
i2c_port_t port
Definition I2cBus.cpp:25