This commit is contained in:
2026-05-22 21:52:50 +03:00
commit be7c60e4dd
1854 changed files with 583428 additions and 0 deletions
@@ -0,0 +1,30 @@
#include "Wire.h"
#define I2C_DEV_ADDR 0x55
uint32_t i = 0;
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.begin();
}
void loop() {
delay(5000);
//Write message to the slave
Wire.beginTransmission(I2C_DEV_ADDR);
Wire.printf("Hello World! %lu", i++);
uint8_t error = Wire.endTransmission(true);
Serial.printf("endTransmission: %u\n", error);
//Read 16 bytes from the slave
uint8_t bytesReceived = Wire.requestFrom(I2C_DEV_ADDR, 16);
Serial.printf("requestFrom: %u\n", bytesReceived);
if ((bool)bytesReceived) { //If received more than zero bytes
uint8_t temp[bytesReceived];
Wire.readBytes(temp, bytesReceived);
log_print_buf(temp, bytesReceived);
}
}
@@ -0,0 +1,2 @@
requires:
- CONFIG_SOC_I2C_SUPPORTED=y
@@ -0,0 +1,28 @@
#include "Wire.h"
void setup() {
Serial.begin(115200);
Wire.begin();
}
void loop() {
byte error, address;
int nDevices = 0;
delay(5000);
Serial.println("Scanning for I2C devices ...");
for (address = 0x01; address < 0x7f; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.printf("I2C device found at address 0x%02X\n", address);
nDevices++;
} else if (error != 2) {
Serial.printf("Error %d at address 0x%02X\n", error, address);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found");
}
}
+2
View File
@@ -0,0 +1,2 @@
requires:
- CONFIG_SOC_I2C_SUPPORTED=y
@@ -0,0 +1,35 @@
#include "Wire.h"
#define I2C_DEV_ADDR 0x55
uint32_t i = 0;
void onRequest() {
Wire.print(i++);
Wire.print(" Packets.");
Serial.println("onRequest");
}
void onReceive(int len) {
Serial.printf("onReceive[%d]: ", len);
while (Wire.available()) {
Serial.write(Wire.read());
}
Serial.println();
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.onReceive(onReceive);
Wire.onRequest(onRequest);
Wire.begin((uint8_t)I2C_DEV_ADDR);
#if CONFIG_IDF_TARGET_ESP32
char message[64];
snprintf(message, 64, "%lu Packets.", i++);
Wire.slaveWrite((uint8_t *)message, strlen(message));
#endif
}
void loop() {}
+2
View File
@@ -0,0 +1,2 @@
requires:
- CONFIG_SOC_I2C_SUPPORT_SLAVE=y
@@ -0,0 +1,37 @@
// This example demonstrates the use of functional callbacks with the Wire library
// for I2C slave communication. It shows how to handle requests and data reception
#include "Wire.h"
#define I2C_DEV_ADDR 0x55
uint32_t i = 0;
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
Wire.onRequest([]() {
Wire.print(i++);
Wire.print(" Packets.");
Serial.println("onRequest");
});
Wire.onReceive([](int len) {
Serial.printf("onReceive[%d]: ", len);
while (Wire.available()) {
Serial.write(Wire.read());
}
Serial.println();
});
Wire.begin((uint8_t)I2C_DEV_ADDR);
#if CONFIG_IDF_TARGET_ESP32
char message[64];
snprintf(message, 64, "%lu Packets.", i++);
Wire.slaveWrite((uint8_t *)message, strlen(message));
#endif
}
void loop() {}
@@ -0,0 +1,2 @@
requires:
- CONFIG_SOC_I2C_SUPPORT_SLAVE=y
+34
View File
@@ -0,0 +1,34 @@
#######################################
# Syntax Coloring Map For Wire
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
end KEYWORD2
setClock KEYWORD2
getClock KEYWORD2
setTimeOut KEYWORD2
getTimeOut KEYWORD2
beginTransmission KEYWORD2
endTransmission KEYWORD2
requestFrom KEYWORD2
onReceive KEYWORD2
onRequest KEYWORD2
#######################################
# Instances (KEYWORD2)
#######################################
Wire KEYWORD2
TwoWire KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
+9
View File
@@ -0,0 +1,9 @@
name=Wire
version=3.3.7
author=Hristo Gochkov
maintainer=Hristo Gochkov <hristo@espressif.com>
sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For esp8266 boards.
paragraph=
category=Signal Input/Output
url=http://arduino.cc/en/Reference/Wire
architectures=esp32
+666
View File
@@ -0,0 +1,666 @@
/*
TwoWire.cpp - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified Nov 2017 by Chuck Todd (ctodd@cableone.net) - ESP32 ISR Support
Modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
*/
#include "soc/soc_caps.h"
#if SOC_I2C_SUPPORTED
extern "C" {
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
}
#include "esp32-hal-i2c.h"
#if SOC_I2C_SUPPORT_SLAVE
#include "esp32-hal-i2c-slave.h"
#endif /* SOC_I2C_SUPPORT_SLAVE */
#include "Wire.h"
#include "Arduino.h"
TwoWire::TwoWire(uint8_t bus_num)
: num(bus_num), sda(-1), scl(-1), bufferSize(I2C_BUFFER_LENGTH) // default Wire Buffer Size
,
rxBuffer(NULL), rxIndex(0), rxLength(0), txBuffer(NULL), txLength(0), txAddress(0), _timeOutMillis(50), nonStop(false)
#if !CONFIG_DISABLE_HAL_LOCKS
,
currentTaskHandle(NULL), lock(NULL)
#endif
#if SOC_I2C_SUPPORT_SLAVE
,
is_slave(false), user_onRequest(nullptr), user_onReceive(nullptr)
#endif /* SOC_I2C_SUPPORT_SLAVE */
{
}
TwoWire::~TwoWire() {
end();
#if !CONFIG_DISABLE_HAL_LOCKS
if (lock != NULL) {
vSemaphoreDelete(lock);
}
#endif
}
uint8_t TwoWire::getBusNum() {
return num;
}
bool TwoWire::initPins(int sdaPin, int sclPin) {
if (sdaPin < 0) { // default param passed
if (num == 0) {
if (sda == -1) {
sdaPin = SDA; //use Default Pin
} else {
sdaPin = sda; // reuse prior pin
}
} else {
if (sda == -1) {
#ifdef WIRE1_PIN_DEFINED
sdaPin = SDA1;
#else
log_e("no Default SDA Pin for Second Peripheral");
return false; //no Default pin for Second Peripheral
#endif
} else {
sdaPin = sda; // reuse prior pin
}
}
}
if (sclPin < 0) { // default param passed
if (num == 0) {
if (scl == -1) {
sclPin = SCL; // use Default pin
} else {
sclPin = scl; // reuse prior pin
}
} else {
if (scl == -1) {
#ifdef WIRE1_PIN_DEFINED
sclPin = SCL1;
#else
log_e("no Default SCL Pin for Second Peripheral");
return false; //no Default pin for Second Peripheral
#endif
} else {
sclPin = scl; // reuse prior pin
}
}
}
sda = sdaPin;
scl = sclPin;
return true;
}
bool TwoWire::setPins(int sdaPin, int sclPin) {
#if !CONFIG_DISABLE_HAL_LOCKS
if (lock == NULL) {
lock = xSemaphoreCreateMutex();
if (lock == NULL) {
log_e("xSemaphoreCreateMutex failed");
return false;
}
}
//acquire lock
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return false;
}
#endif
if (!i2cIsInit(num)) {
initPins(sdaPin, sclPin);
} else {
log_e("bus already initialized. change pins only when not.");
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
#endif
return !i2cIsInit(num);
}
bool TwoWire::allocateWireBuffer() {
// or both buffer can be allocated or none will be
if (rxBuffer == NULL) {
rxBuffer = (uint8_t *)malloc(bufferSize);
if (rxBuffer == NULL) {
log_e("Can't allocate memory for I2C_%d rxBuffer", num);
return false;
}
}
if (txBuffer == NULL) {
txBuffer = (uint8_t *)malloc(bufferSize);
if (txBuffer == NULL) {
log_e("Can't allocate memory for I2C_%d txBuffer", num);
freeWireBuffer(); // free rxBuffer for safety!
return false;
}
}
// in case both were allocated before, they must have the same size. All good.
return true;
}
void TwoWire::freeWireBuffer() {
if (rxBuffer != NULL) {
free(rxBuffer);
rxBuffer = NULL;
}
if (txBuffer != NULL) {
free(txBuffer);
txBuffer = NULL;
}
}
size_t TwoWire::setBufferSize(size_t bSize) {
// Maximum size .... HEAP limited ;-)
if (bSize < 32) { // 32 bytes is the I2C FIFO Len for ESP32/S2/S3/C3
log_e("Minimum Wire Buffer size is 32 bytes");
return 0;
}
#if !CONFIG_DISABLE_HAL_LOCKS
if (lock == NULL) {
lock = xSemaphoreCreateMutex();
if (lock == NULL) {
log_e("xSemaphoreCreateMutex failed");
return 0;
}
}
//acquire lock
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return 0;
}
#endif
// allocateWireBuffer allocates memory for both pointers or just free them
if (rxBuffer != NULL || txBuffer != NULL) {
// if begin() has been already executed, memory size changes... data may be lost. We don't care! :^)
if (bSize != bufferSize) {
// we want a new buffer size ... just reset buffer pointers and allocate new ones
freeWireBuffer();
bufferSize = bSize;
if (!allocateWireBuffer()) {
// failed! Error message already issued
bSize = 0; // returns error
log_e("Buffer allocation failed");
}
} // else nothing changes, all set!
} else {
// no memory allocated yet, just change the size value - allocation in begin()
bufferSize = bSize;
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
#endif
return bSize;
}
#if SOC_I2C_SUPPORT_SLAVE
// Slave Begin
bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) {
bool started = false;
#if !CONFIG_DISABLE_HAL_LOCKS
if (lock == NULL) {
lock = xSemaphoreCreateMutex();
if (lock == NULL) {
log_e("xSemaphoreCreateMutex failed");
return false;
}
}
//acquire lock
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return false;
}
#endif
if (is_slave) {
log_w("Bus already started in Slave Mode.");
started = true;
goto end;
}
if (i2cIsInit(num)) {
log_e("Bus already started in Master Mode.");
goto end;
}
if (!allocateWireBuffer()) {
// failed! Error Message already issued
goto end;
}
if (!initPins(sdaPin, sclPin)) {
goto end;
}
i2cSlaveAttachCallbacks(num, onRequestService, onReceiveService, this);
if (i2cSlaveInit(num, sda, scl, addr, frequency, bufferSize, bufferSize) != ESP_OK) {
log_e("Slave Init ERROR");
goto end;
}
is_slave = true;
started = true;
end:
if (!started) {
freeWireBuffer();
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
#endif
return started;
}
#endif /* SOC_I2C_SUPPORT_SLAVE */
// Master Begin
bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) {
bool started = false;
esp_err_t err = ESP_OK;
#if !CONFIG_DISABLE_HAL_LOCKS
if (lock == NULL) {
lock = xSemaphoreCreateMutex();
if (lock == NULL) {
log_e("xSemaphoreCreateMutex failed");
return false;
}
}
//acquire lock
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return false;
}
#endif
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
log_e("Bus already started in Slave Mode.");
goto end;
}
#endif /* SOC_I2C_SUPPORT_SLAVE */
if (i2cIsInit(num)) {
log_w("Bus already started in Master Mode.");
started = true;
goto end;
}
if (!allocateWireBuffer()) {
// failed! Error Message already issued
goto end;
}
if (!initPins(sdaPin, sclPin)) {
goto end;
}
err = i2cInit(num, sda, scl, frequency);
started = (err == ESP_OK);
end:
if (!started) {
freeWireBuffer();
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
#endif
return started;
}
bool TwoWire::end() {
esp_err_t err = ESP_OK;
#if !CONFIG_DISABLE_HAL_LOCKS
if (lock != NULL) {
//acquire lock
if (xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return false;
}
#endif
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
err = i2cSlaveDeinit(num);
if (err == ESP_OK) {
is_slave = false;
}
} else
#endif /* SOC_I2C_SUPPORT_SLAVE */
if (i2cIsInit(num)) {
err = i2cDeinit(num);
}
freeWireBuffer();
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
}
#endif
return (err == ESP_OK);
}
uint32_t TwoWire::getClock() {
uint32_t frequency = 0;
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
} else {
#endif
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
log_e("Bus is in Slave Mode");
} else
#endif /* SOC_I2C_SUPPORT_SLAVE */
{
i2cGetClock(num, &frequency);
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
}
#endif
return frequency;
}
bool TwoWire::setClock(uint32_t frequency) {
esp_err_t err = ESP_OK;
#if !CONFIG_DISABLE_HAL_LOCKS
//acquire lock
if (lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return false;
}
#endif
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
log_e("Bus is in Slave Mode");
err = ESP_FAIL;
} else
#endif /* SOC_I2C_SUPPORT_SLAVE */
{
err = i2cSetClock(num, frequency);
}
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
#endif
return (err == ESP_OK);
}
void TwoWire::setTimeOut(uint16_t timeOutMillis) {
_timeOutMillis = timeOutMillis;
}
uint16_t TwoWire::getTimeOut() {
return _timeOutMillis;
}
void TwoWire::beginTransmission(uint8_t address) {
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
log_e("Bus is in Slave Mode");
return;
}
#endif /* SOC_I2C_SUPPORT_SLAVE */
#if !CONFIG_DISABLE_HAL_LOCKS
TaskHandle_t task = xTaskGetCurrentTaskHandle();
if (currentTaskHandle != task) {
//acquire lock
if (lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return;
}
currentTaskHandle = task;
}
#endif
nonStop = false;
txAddress = address;
txLength = 0;
}
/*
https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/
endTransmission() returns:
0: success.
1: data too long to fit in transmit buffer.
2: received NACK on transmit of address.
3: received NACK on transmit of data.
4: other error.
5: timeout
*/
uint8_t TwoWire::endTransmission(bool sendStop) {
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
log_e("Bus is in Slave Mode");
return 4;
}
#endif /* SOC_I2C_SUPPORT_SLAVE */
if (txBuffer == NULL) {
log_e("NULL TX buffer pointer");
return 4;
}
esp_err_t err = ESP_OK;
if (sendStop) {
err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis);
#if !CONFIG_DISABLE_HAL_LOCKS
currentTaskHandle = NULL;
//release lock
xSemaphoreGive(lock);
#endif
} else {
//mark as non-stop
nonStop = true;
}
switch (err) {
case ESP_OK: return 0;
case ESP_FAIL: return 2;
case ESP_ERR_NOT_FOUND: return 2;
case ESP_ERR_TIMEOUT: return 5;
default: break;
}
return 4;
}
uint8_t TwoWire::endTransmission() {
return endTransmission(true);
}
size_t TwoWire::requestFrom(uint8_t address, size_t size, bool sendStop) {
#if SOC_I2C_SUPPORT_SLAVE
if (is_slave) {
log_e("Bus is in Slave Mode");
return 0;
}
#endif /* SOC_I2C_SUPPORT_SLAVE */
if (rxBuffer == NULL || txBuffer == NULL) {
log_e("NULL buffer pointer");
return 0;
}
esp_err_t err = ESP_OK;
#if !CONFIG_DISABLE_HAL_LOCKS
TaskHandle_t task = xTaskGetCurrentTaskHandle();
if (currentTaskHandle != task) {
//acquire lock
if (lock == NULL || xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE) {
log_e("could not acquire lock");
return 0;
}
currentTaskHandle = task;
}
#endif
if (nonStop) {
if (address != txAddress) {
log_e("Unfinished Repeated Start transaction! Expected address do not match! %u != %u", address, txAddress);
#if !CONFIG_DISABLE_HAL_LOCKS
currentTaskHandle = NULL;
//release lock
xSemaphoreGive(lock);
#endif
return 0;
}
nonStop = false;
rxIndex = 0;
rxLength = 0;
err = i2cWriteReadNonStop(num, address, txBuffer, txLength, rxBuffer, size, _timeOutMillis, &rxLength);
if (err) {
log_e("i2cWriteReadNonStop returned Error %d", err);
}
} else {
rxIndex = 0;
rxLength = 0;
err = i2cRead(num, address, rxBuffer, size, _timeOutMillis, &rxLength);
if (err) {
log_e("i2cRead returned Error %d", err);
}
}
#if !CONFIG_DISABLE_HAL_LOCKS
currentTaskHandle = NULL;
//release lock
xSemaphoreGive(lock);
#endif
return rxLength;
}
size_t TwoWire::requestFrom(uint8_t address, size_t size) {
return requestFrom(address, size, true);
}
size_t TwoWire::write(uint8_t data) {
if (txBuffer == NULL) {
log_e("NULL TX buffer pointer");
return 0;
}
if (txLength >= bufferSize) {
return 0;
}
txBuffer[txLength++] = data;
return 1;
}
size_t TwoWire::write(const uint8_t *data, size_t quantity) {
for (size_t i = 0; i < quantity; ++i) {
if (!write(data[i])) {
return i;
}
}
return quantity;
}
int TwoWire::available() {
int result = rxLength - rxIndex;
return result;
}
int TwoWire::read() {
int value = -1;
if (rxBuffer == NULL) {
log_e("NULL RX buffer pointer");
return value;
}
if (rxIndex < rxLength) {
value = rxBuffer[rxIndex++];
}
return value;
}
int TwoWire::peek() {
int value = -1;
if (rxBuffer == NULL) {
log_e("NULL RX buffer pointer");
return value;
}
if (rxIndex < rxLength) {
value = rxBuffer[rxIndex];
}
return value;
}
void TwoWire::flush() {
rxIndex = 0;
rxLength = 0;
txLength = 0;
//i2cFlush(num); // cleanup
}
void TwoWire::onReceive(const std::function<void(int)> &function) {
#if SOC_I2C_SUPPORT_SLAVE
user_onReceive = function;
#endif
}
// sets function called on slave read
void TwoWire::onRequest(const std::function<void()> &function) {
#if SOC_I2C_SUPPORT_SLAVE
user_onRequest = function;
#endif
}
#if SOC_I2C_SUPPORT_SLAVE
size_t TwoWire::slaveWrite(const uint8_t *buffer, size_t len) {
return i2cSlaveWrite(num, buffer, len, _timeOutMillis);
}
void TwoWire::onReceiveService(uint8_t num, uint8_t *inBytes, size_t numBytes, bool stop, void *arg) {
TwoWire *wire = (TwoWire *)arg;
if (!wire->user_onReceive) {
return;
}
if (wire->rxBuffer == NULL) {
log_e("NULL RX buffer pointer");
return;
}
for (uint8_t i = 0; i < numBytes; ++i) {
wire->rxBuffer[i] = inBytes[i];
}
wire->rxIndex = 0;
wire->rxLength = numBytes;
wire->user_onReceive(numBytes);
}
void TwoWire::onRequestService(uint8_t num, void *arg) {
TwoWire *wire = (TwoWire *)arg;
if (!wire->user_onRequest) {
return;
}
if (wire->txBuffer == NULL) {
log_e("NULL TX buffer pointer");
return;
}
wire->txLength = 0;
wire->user_onRequest();
if (wire->txLength) {
wire->slaveWrite((uint8_t *)wire->txBuffer, wire->txLength);
}
}
#endif /* SOC_I2C_SUPPORT_SLAVE */
TwoWire Wire = TwoWire(0);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
#if SOC_I2C_NUM > 1
TwoWire Wire1 = TwoWire(1);
#elif SOC_I2C_NUM > 2
TwoWire Wire2 = TwoWire(2);
#endif /* SOC_I2C_NUM */
#else
#if SOC_HP_I2C_NUM > 1
TwoWire Wire1 = TwoWire(1);
#endif /* SOC_HP_I2C_NUM */
#endif
#endif /* SOC_I2C_SUPPORTED */
+161
View File
@@ -0,0 +1,161 @@
/*
TwoWire.h - TWI/I2C library for Arduino & Wiring
Copyright (c) 2006 Nicholas Zambetti. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
Modified November 2017 by Chuck Todd <stickbreaker on GitHub> to use ISR and increase stability.
Modified Nov 2021 by Hristo Gochkov <Me-No-Dev> to support ESP-IDF API
*/
#ifndef TwoWire_h
#define TwoWire_h
#include "soc/soc_caps.h"
#if SOC_I2C_SUPPORTED
#include "esp_idf_version.h"
#include <esp32-hal.h>
#include <esp32-hal-log.h>
#if !CONFIG_DISABLE_HAL_LOCKS
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#endif
#include "HardwareI2C.h"
#include "Stream.h"
// WIRE_HAS_BUFFER_SIZE means Wire has setBufferSize()
#define WIRE_HAS_BUFFER_SIZE 1
// WIRE_HAS_END means Wire has end()
#define WIRE_HAS_END 1
#ifndef I2C_BUFFER_LENGTH
#define I2C_BUFFER_LENGTH 128 // Default size, if none is set using Wire::setBuffersize(size_t)
#endif
class TwoWire : public HardwareI2C {
protected:
uint8_t num;
int8_t sda;
int8_t scl;
size_t bufferSize;
uint8_t *rxBuffer;
size_t rxIndex;
size_t rxLength;
uint8_t *txBuffer;
size_t txLength;
uint16_t txAddress;
uint32_t _timeOutMillis;
bool nonStop;
#if !CONFIG_DISABLE_HAL_LOCKS
TaskHandle_t currentTaskHandle;
SemaphoreHandle_t lock;
#endif
private:
#if SOC_I2C_SUPPORT_SLAVE
bool is_slave;
std::function<void()> user_onRequest;
std::function<void(int)> user_onReceive;
static void onRequestService(uint8_t, void *);
static void onReceiveService(uint8_t, uint8_t *, size_t, bool, void *);
#endif /* SOC_I2C_SUPPORT_SLAVE */
bool initPins(int sdaPin, int sclPin);
bool allocateWireBuffer();
void freeWireBuffer();
public:
TwoWire(uint8_t bus_num);
~TwoWire();
bool begin() override final {
return begin(-1, -1);
}
bool begin(uint8_t address) override final {
#if SOC_I2C_SUPPORT_SLAVE
return begin(address, -1, -1, 0);
#else
log_e("I2C slave is not supported on " CONFIG_IDF_TARGET);
return false;
#endif
}
bool end() override;
uint8_t getBusNum();
bool setClock(uint32_t freq) override;
void beginTransmission(uint8_t address) override;
uint8_t endTransmission(bool stopBit) override;
uint8_t endTransmission() override;
size_t requestFrom(uint8_t address, size_t len, bool stopBit) override;
size_t requestFrom(uint8_t address, size_t len) override;
void onReceive(const std::function<void(int)> &) override;
void onRequest(const std::function<void()> &) override;
//call setPins() first, so that begin() can be called without arguments from libraries
bool setPins(int sda, int scl);
bool begin(int sda, int scl, uint32_t frequency = 0); // returns true, if successful init of i2c bus
#if SOC_I2C_SUPPORT_SLAVE
bool begin(uint8_t slaveAddr, int sda, int scl, uint32_t frequency);
#endif /* SOC_I2C_SUPPORT_SLAVE */
size_t setBufferSize(size_t bSize);
void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms
uint16_t getTimeOut();
uint32_t getClock();
size_t write(uint8_t) override;
size_t write(const uint8_t *, size_t) override;
int available() override;
int read() override;
int peek() override;
void flush() override;
#if SOC_I2C_SUPPORT_SLAVE
size_t slaveWrite(const uint8_t *, size_t);
#endif /* SOC_I2C_SUPPORT_SLAVE */
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_WIRE)
extern TwoWire Wire;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)
#if SOC_I2C_NUM > 1
extern TwoWire Wire1;
#elif SOC_I2C_NUM > 2
extern TwoWire Wire2;
#endif /* SOC_I2C_NUM */
#else
#if SOC_HP_I2C_NUM > 1
extern TwoWire Wire1;
#endif /* SOC_HP_I2C_NUM */
#endif
#endif
#endif /* SOC_I2C_SUPPORTED */
#endif /* TwoWire_h */