SensorLib 0.5.0
Multi-platform sensor driver library for Arduino, PlatformIO, and ESP-IDF
Loading...
Searching...
No Matches
SensorCommEspIDF_I2C.hpp
Go to the documentation of this file.
1
30#pragma once
31
32#include "../SensorCommBase.hpp"
33
34#if !defined(ARDUINO) && defined(ESP_PLATFORM)
35
36#include "sdkconfig.h"
37#include "freertos/FreeRTOS.h"
38#include "esp_idf_version.h"
39#include "esp_err.h"
40#if ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,0,0)) && defined(CONFIG_SENSORLIB_ESP_IDF_NEW_API))
41#include "driver/i2c_master.h"
42#else
43#include "driver/i2c.h"
44#define SENSORLIB_USE_I2C_LEGACY 1
45#endif //ESP_IDF_VERSION
46
47#define SENSORLIB_I2C_MASTER_TIMEOUT_MS 1000
48#define SENSORLIB_I2C_MASTER_SPEED 400000
49
50class SensorCommI2C : public SensorCommBase
51{
52public:
53
54#if defined(SENSORLIB_USE_I2C_LEGACY)
55 SensorCommI2C(i2c_port_t i2c_num, uint8_t addr, int sda, int scl, SensorHal *ptr = nullptr) :
56 addr(addr), sda(sda), scl(scl), _i2cNum(i2c_num), sendStopFlag(true)
57 {}
58#else
59 SensorCommI2C(i2c_master_bus_handle_t handle, uint8_t addr, SensorHal *ptr = nullptr) :
60 addr(addr), _busHandle(handle), _i2cDevice(nullptr), sendStopFlag(true) {}
61#endif
62
63 bool init() override
64 {
65#if defined(SENSORLIB_USE_I2C_LEGACY)
66 return init_legacy();
67#else
68 return init_ll_hal();
69#endif
70 }
71
72 void deinit() override
73 {
74#ifndef SENSORLIB_USE_I2C_LEGACY
75 if (_i2cDevice) {
76 // Initialization failed, delete device
77 i2c_master_bus_rm_device(_i2cDevice);
78 }
79#endif
80 }
81
82 int writeRegister(const uint8_t reg, uint8_t *buf, size_t len) override
83 {
84 size_t totalLength = sizeof(uint8_t) + len;
85 uint8_t *write_buffer = (uint8_t *)malloc(totalLength);
86 if (!write_buffer) {
88 }
89 write_buffer[0] = reg;
90 if (buf && len > 0) {
91 memcpy(write_buffer + 1, buf, len);
92 }
93 int ret = writeBuffer(write_buffer, totalLength);
94 free(write_buffer);
95 return ret;
96 }
97
98 int writeBuffer(uint8_t *buffer, size_t len)
99 {
100
101#if defined(SENSORLIB_USE_I2C_LEGACY)
102 if (ESP_OK == i2c_master_write_to_device(_i2cNum, addr, buffer, len,
103 SENSORLIB_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS)) {
104 return SENSOR_OK;
105 }
106#else //ESP_IDF_VERSION
107 if (ESP_OK == i2c_master_transmit(_i2cDevice, buffer, len, -1)) {
108 return SENSOR_OK;
109 }
110
111#endif //ESP_IDF_VERSION
113 }
114
115 int readBuffer(uint8_t *buf, size_t len) override
116 {
117#if defined(SENSORLIB_USE_I2C_LEGACY)
118 if (ESP_OK == i2c_master_write_read_device(_i2cNum, addr, NULL, 0, buf, len,
119 SENSORLIB_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS)) {
120 return SENSOR_OK;
121 }
122#else //ESP_IDF_VERSION
123 if (ESP_OK == i2c_master_transmit_receive(_i2cDevice, NULL, 0, buf, len, -1)) {
124 return SENSOR_OK;
125 }
126#endif //ESP_IDF_VERSION
128 }
129
130 int readRegister(const uint8_t reg, uint8_t *buf, size_t len) override
131 {
132#if defined(SENSORLIB_USE_I2C_LEGACY)
133 if (ESP_OK == i2c_master_write_read_device(_i2cNum, addr, (uint8_t *)&reg, 1, buf, len,
134 SENSORLIB_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS)) {
135 return SENSOR_OK;
136 }
137#else //ESP_IDF_VERSION
138 if (ESP_OK == i2c_master_transmit_receive(_i2cDevice, (const uint8_t *)&reg, 1, buf, len, -1)) {
139 return SENSOR_OK;
140 }
141#endif //ESP_IDF_VERSION
143 }
144
145 int writeThenRead(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len) override
146 {
147#if defined(SENSORLIB_USE_I2C_LEGACY)
148 if (ESP_OK == i2c_master_write_read_device(
149 _i2cNum,
150 addr,
151 write_buffer,
152 write_len,
153 read_buffer,
154 read_len,
155 SENSORLIB_I2C_MASTER_TIMEOUT_MS / portTICK_PERIOD_MS)) {
156 return SENSOR_OK;
157 }
158#else //ESP_IDF_VERSION
159 if (ESP_OK == i2c_master_transmit_receive(
160 _i2cDevice,
161 write_buffer,
162 write_len,
163 read_buffer,
164 read_len,
165 -1)) {
166 return SENSOR_OK;
167 }
168#endif //ESP_IDF_VERSION
170 }
171
172 void setParams(const CommParamsBase &params) override
173 {
174#if defined(__cpp_rtti)
175 const auto pdat = dynamic_cast<const I2CParam *>(&params);
176#else
177 const auto pdat = static_cast<const I2CParam *>(&params);
178#endif
179 uint8_t type = pdat->getType();
180 switch (type) {
182 addr = pdat->getParams();
183 break;
185 sendStopFlag = pdat->getParams();
186 break;
187 default:
188 break;
189 }
190
191#if !defined(SENSORLIB_USE_I2C_LEGACY)
192 deinit();
193 init_ll_hal();
194#endif
195 }
196
197private:
198
199
200
201#if defined(SENSORLIB_USE_I2C_LEGACY)
202
203 bool init_legacy()
204 {
205 if (sda == -1 || scl == -1) {
206 return true;
207 }
208 i2c_config_t i2c_conf;
209 memset(&i2c_conf, 0, sizeof(i2c_conf));
210 i2c_conf.mode = I2C_MODE_MASTER;
211 i2c_conf.sda_io_num = sda;
212 i2c_conf.scl_io_num = scl;
213 i2c_conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
214 i2c_conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
215 i2c_conf.master.clk_speed = SENSORLIB_I2C_MASTER_SPEED;
216
222 // static const IDF_TX_BUF_DISABLE = 0; /*!< I2C master doesn't need buffer */
223 // static const IDF_RX_BUF_DISABLE = 0; /*!< I2C master doesn't need buffer */
224
225 i2c_param_config(_i2cNum, &i2c_conf);
226 if (ESP_OK != i2c_driver_install(_i2cNum, i2c_conf.mode, 0, 0, 0)) {
228 return false;
229 }
230 return true;
231 }
232
233#else //SENSORLIB_USE_I2C_LEGACY
234
235 // * Using the new API of esp-idf 5.x, need to pass the I2C BUS handle,
236 // * which is useful when the bus shares multiple devices.
237 bool init_ll_hal()
238 {
239 SENSORLIB_LOG_I("Using ESP-IDF Driver interface.");
240
241 i2c_device_config_t devConf;
242 if (_busHandle == NULL) return false;
243 devConf.dev_addr_length = I2C_ADDR_BIT_LEN_7;
244 devConf.device_address = addr;
245 devConf.scl_speed_hz = SENSORLIB_I2C_MASTER_SPEED;
246
247#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,3,0))
248#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5,4,0))
249 // New fields since esp-idf-v5.3-beta1
250 devConf.scl_wait_us = 0;
251#endif
252 devConf.flags.disable_ack_check = 0;
253#endif
254
255 if (ESP_OK != i2c_master_bus_add_device(_busHandle, &devConf, &_i2cDevice)) {
256 SENSORLIB_LOG_I("i2c_master_bus_add_device failed !");
258 return false;
259 }
260 SENSORLIB_LOG_I("Added Device Address : 0x%X New Dev Address: %p Speed :%" PRIu32 " ", addr, _i2cDevice, devConf.scl_speed_hz);
261 return true;
262 }
263#endif //ESP 5.X
264
265 uint8_t addr;
266#if defined(SENSORLIB_USE_I2C_LEGACY)
267 int sda;
268 int scl;
269 i2c_port_t _i2cNum;
270#else
271 i2c_master_bus_handle_t _busHandle;
272 i2c_master_dev_handle_t _i2cDevice;
273#endif
274 bool sendStopFlag;
275};
276
277#endif //*ESP_PLATFORM
@ SENSOR_ERR_NO_MEMORY
@ SENSOR_OK
Definition SensorErr.hpp:37
@ SENSOR_ERR_COMM_NACK
Definition SensorErr.hpp:55
@ SENSOR_ERR_COMM_INIT
Definition SensorErr.hpp:53
#define SENSORLIB_LOG_I(...)
Abstract base for all communication parameter objects.
I2C communication parameters.
uint8_t getType() const
Retrieve the parameter type.
@ I2C_SET_ADDR
Set device address.
@ I2C_SET_FLAG
Set a generic flag (interpretation depends on driver)
Abstract base class for low‑level sensor communication.
virtual int writeThenRead(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len)=0
Perform a write followed by a read (e.g., for register‑based sensors).
virtual int readBuffer(uint8_t *buf, size_t len)=0
Read bytes directly from the device (no register address sent).
virtual int writeBuffer(uint8_t *buffer, size_t len)=0
Write a buffer directly to the device (no register address).
virtual void setParams(const CommParamsBase &params)=0
Apply communication parameters (e.g., I2C address, SPI settings).
virtual int readRegister(const uint8_t reg)
Read a single byte from a register.
virtual void deinit()=0
Deinitialise the communication interface (close device, etc.).
virtual bool init()=0
Initialise the communication interface (open device, etc.).
virtual int writeRegister(const uint8_t reg, uint8_t val)
Write a single byte to a register.
void setError(SENSOR_ERROR_CODE e)
Abstract hardware abstraction layer.
char buf[64]