Unverified Commit ed53b6c8 authored by Me No Dev's avatar Me No Dev Committed by GitHub

Merge pull request #5746 from espressif/i2c-slave

I2C Slave Implementation
parents 2e53300d b145e659
...@@ -7,6 +7,7 @@ set(CORE_SRCS ...@@ -7,6 +7,7 @@ set(CORE_SRCS
cores/esp32/esp32-hal-dac.c cores/esp32/esp32-hal-dac.c
cores/esp32/esp32-hal-gpio.c cores/esp32/esp32-hal-gpio.c
cores/esp32/esp32-hal-i2c.c cores/esp32/esp32-hal-i2c.c
cores/esp32/esp32-hal-i2c-slave.c
cores/esp32/esp32-hal-ledc.c cores/esp32/esp32-hal-ledc.c
cores/esp32/esp32-hal-matrix.c cores/esp32/esp32-hal-matrix.c
cores/esp32/esp32-hal-misc.c cores/esp32/esp32-hal-misc.c
......
This diff is collapsed.
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include "stdint.h"
#include "stddef.h"
#include "esp_err.h"
typedef void (*i2c_slave_request_cb_t) (uint8_t num, void * arg);
typedef void (*i2c_slave_receive_cb_t) (uint8_t num, uint8_t * data, size_t len, bool stop, void * arg);
esp_err_t i2cSlaveAttachCallbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, void * arg);
esp_err_t i2cSlaveInit(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len);
esp_err_t i2cSlaveDeinit(uint8_t num);
size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms);
#ifdef __cplusplus
}
#endif
#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! %u", i++);
uint8_t error = Wire.endTransmission(true);
Serial.printf("endTransmission: %u\n", error);
//Read 16 bytes from the slave
error = Wire.requestFrom(I2C_DEV_ADDR, 16);
Serial.printf("requestFrom: %u\n", error);
if(error){
uint8_t temp[error];
Wire.readBytes(temp, error);
log_print_buf(temp, error);
}
}
#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");
}
}
#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, "%u Packets.", i++);
Wire.slaveWrite((uint8_t *)message, strlen(message));
#endif
}
void loop() {
}
...@@ -30,6 +30,7 @@ extern "C" { ...@@ -30,6 +30,7 @@ extern "C" {
} }
#include "esp32-hal-i2c.h" #include "esp32-hal-i2c.h"
#include "esp32-hal-i2c-slave.h"
#include "Wire.h" #include "Wire.h"
#include "Arduino.h" #include "Arduino.h"
...@@ -47,6 +48,9 @@ TwoWire::TwoWire(uint8_t bus_num) ...@@ -47,6 +48,9 @@ TwoWire::TwoWire(uint8_t bus_num)
,nonStopTask(NULL) ,nonStopTask(NULL)
,lock(NULL) ,lock(NULL)
#endif #endif
,is_slave(false)
,user_onRequest(NULL)
,user_onReceive(NULL)
{} {}
TwoWire::~TwoWire() TwoWire::~TwoWire()
...@@ -59,6 +63,47 @@ TwoWire::~TwoWire() ...@@ -59,6 +63,47 @@ TwoWire::~TwoWire()
#endif #endif
} }
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) {
log_e("no Default SDA Pin for Second Peripheral");
return false; //no Default pin for Second Peripheral
} 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) {
log_e("no Default SCL Pin for Second Peripheral");
return false; //no Default pin for Second Peripheral
} else {
sclPin = scl; // reuse prior pin
}
}
}
sda = sdaPin;
scl = sclPin;
return true;
}
bool TwoWire::setPins(int sdaPin, int sclPin) bool TwoWire::setPins(int sdaPin, int sclPin)
{ {
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
...@@ -76,8 +121,7 @@ bool TwoWire::setPins(int sdaPin, int sclPin) ...@@ -76,8 +121,7 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
} }
#endif #endif
if(!i2cIsInit(num)){ if(!i2cIsInit(num)){
sda = sdaPin; initPins(sdaPin, sclPin);
scl = sclPin;
} else { } else {
log_e("bus already initialized. change pins only when not."); log_e("bus already initialized. change pins only when not.");
} }
...@@ -88,10 +132,10 @@ bool TwoWire::setPins(int sdaPin, int sclPin) ...@@ -88,10 +132,10 @@ bool TwoWire::setPins(int sdaPin, int sclPin)
return !i2cIsInit(num); return !i2cIsInit(num);
} }
bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) // Slave Begin
bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency)
{ {
bool started = false; bool started = false;
esp_err_t err = ESP_OK;
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if(lock == NULL){ if(lock == NULL){
lock = xSemaphoreCreateMutex(); lock = xSemaphoreCreateMutex();
...@@ -106,46 +150,64 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) ...@@ -106,46 +150,64 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
return false; return false;
} }
#endif #endif
if(i2cIsInit(num)){ if(is_slave){
log_w("Bus already started in Slave Mode.");
started = true; started = true;
goto end; goto end;
} }
if(sdaPin < 0) { // default param passed if(i2cIsInit(num)){
if(num == 0) { log_e("Bus already started in Master Mode.");
if(sda==-1) { goto end;
sdaPin = SDA; //use Default Pin
} else {
sdaPin = sda; // reuse prior pin
}
} else {
if(sda==-1) {
log_e("no Default SDA Pin for Second Peripheral");
goto end; //no Default pin for Second Peripheral
} else {
sdaPin = sda; // reuse prior pin
} }
if(!initPins(sdaPin, sclPin)){
goto end;
} }
i2cSlaveAttachCallbacks(num, onRequestService, onReceiveService, this);
if(i2cSlaveInit(num, sda, scl, addr, frequency, I2C_BUFFER_LENGTH, I2C_BUFFER_LENGTH) != ESP_OK){
log_e("Slave Init ERROR");
goto end;
} }
is_slave = true;
started = true;
end:
#if !CONFIG_DISABLE_HAL_LOCKS
//release lock
xSemaphoreGive(lock);
#endif
return started;
}
if(sclPin < 0) { // default param passed // Master Begin
if(num == 0) { bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency)
if(scl == -1) { {
sclPin = SCL; // use Default pin bool started = false;
} else { esp_err_t err = ESP_OK;
sclPin = scl; // reuse prior pin #if !CONFIG_DISABLE_HAL_LOCKS
if(lock == NULL){
lock = xSemaphoreCreateMutex();
if(lock == NULL){
log_e("xSemaphoreCreateMutex failed");
return false;
} }
} else {
if(scl == -1) {
log_e("no Default SCL Pin for Second Peripheral");
goto end; //no Default pin for Second Peripheral
} else {
sclPin = scl; // reuse prior pin
} }
//acquire lock
if(xSemaphoreTake(lock, portMAX_DELAY) != pdTRUE){
log_e("could not acquire lock");
return false;
} }
#endif
if(is_slave){
log_e("Bus already started in Slave Mode.");
goto end;
}
if(i2cIsInit(num)){
log_w("Bus already started in Master Mode.");
started = true;
goto end;
}
if(!initPins(sdaPin, sclPin)){
goto end;
} }
sda = sdaPin;
scl = sclPin;
err = i2cInit(num, sda, scl, frequency); err = i2cInit(num, sda, scl, frequency);
started = (err == ESP_OK); started = (err == ESP_OK);
...@@ -169,7 +231,12 @@ bool TwoWire::end() ...@@ -169,7 +231,12 @@ bool TwoWire::end()
return false; return false;
} }
#endif #endif
if(i2cIsInit(num)){ if(is_slave){
err = i2cSlaveDeinit(num);
if(err == ESP_OK){
is_slave = false;
}
} else if(i2cIsInit(num)){
err = i2cDeinit(num); err = i2cDeinit(num);
} }
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
...@@ -189,7 +256,11 @@ uint32_t TwoWire::getClock() ...@@ -189,7 +256,11 @@ uint32_t TwoWire::getClock()
log_e("could not acquire lock"); log_e("could not acquire lock");
} else { } else {
#endif #endif
if(is_slave){
log_e("Bus is in Slave Mode");
} else {
i2cGetClock(num, &frequency); i2cGetClock(num, &frequency);
}
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
//release lock //release lock
xSemaphoreGive(lock); xSemaphoreGive(lock);
...@@ -208,7 +279,12 @@ bool TwoWire::setClock(uint32_t frequency) ...@@ -208,7 +279,12 @@ bool TwoWire::setClock(uint32_t frequency)
return false; return false;
} }
#endif #endif
if(is_slave){
log_e("Bus is in Slave Mode");
err = ESP_FAIL;
} else {
err = i2cSetClock(num, frequency); err = i2cSetClock(num, frequency);
}
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
//release lock //release lock
xSemaphoreGive(lock); xSemaphoreGive(lock);
...@@ -228,6 +304,10 @@ uint16_t TwoWire::getTimeOut() ...@@ -228,6 +304,10 @@ uint16_t TwoWire::getTimeOut()
void TwoWire::beginTransmission(uint16_t address) void TwoWire::beginTransmission(uint16_t address)
{ {
if(is_slave){
log_e("Bus is in Slave Mode");
return;
}
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
if(nonStop && nonStopTask == xTaskGetCurrentTaskHandle()){ if(nonStop && nonStopTask == xTaskGetCurrentTaskHandle()){
log_e("Unfinished Repeated Start transaction! Expected requestFrom, not beginTransmission! Clearing..."); log_e("Unfinished Repeated Start transaction! Expected requestFrom, not beginTransmission! Clearing...");
...@@ -247,6 +327,10 @@ void TwoWire::beginTransmission(uint16_t address) ...@@ -247,6 +327,10 @@ void TwoWire::beginTransmission(uint16_t address)
uint8_t TwoWire::endTransmission(bool sendStop) uint8_t TwoWire::endTransmission(bool sendStop)
{ {
if(is_slave){
log_e("Bus is in Slave Mode");
return 4;
}
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
if(sendStop){ if(sendStop){
err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis); err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis);
...@@ -272,6 +356,10 @@ uint8_t TwoWire::endTransmission(bool sendStop) ...@@ -272,6 +356,10 @@ uint8_t TwoWire::endTransmission(bool sendStop)
uint8_t TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop) uint8_t TwoWire::requestFrom(uint16_t address, uint8_t size, bool sendStop)
{ {
if(is_slave){
log_e("Bus is in Slave Mode");
return 0;
}
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
if(nonStop if(nonStop
#if !CONFIG_DISABLE_HAL_LOCKS #if !CONFIG_DISABLE_HAL_LOCKS
...@@ -402,5 +490,49 @@ uint8_t TwoWire::endTransmission(void) ...@@ -402,5 +490,49 @@ uint8_t TwoWire::endTransmission(void)
return endTransmission(true); return endTransmission(true);
} }
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;
}
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;
}
wire->txLength = 0;
wire->user_onRequest();
if(wire->txLength){
wire->slaveWrite((uint8_t*)wire->txBuffer, wire->txLength);
}
}
void TwoWire::onReceive( void (*function)(int) )
{
user_onReceive = function;
}
// sets function called on slave read
void TwoWire::onRequest( void (*function)(void) )
{
user_onRequest = function;
}
TwoWire Wire = TwoWire(0); TwoWire Wire = TwoWire(0);
TwoWire Wire1 = TwoWire(1); TwoWire Wire1 = TwoWire(1);
...@@ -61,6 +61,13 @@ protected: ...@@ -61,6 +61,13 @@ protected:
TaskHandle_t nonStopTask; TaskHandle_t nonStopTask;
SemaphoreHandle_t lock; SemaphoreHandle_t lock;
#endif #endif
private:
bool is_slave;
void (*user_onRequest)(void);
void (*user_onReceive)(int);
static void onRequestService(uint8_t, void *);
static void onReceiveService(uint8_t, uint8_t*, size_t, bool, void *);
bool initPins(int sdaPin, int sclPin);
public: public:
TwoWire(uint8_t bus_num); TwoWire(uint8_t bus_num);
...@@ -70,6 +77,7 @@ public: ...@@ -70,6 +77,7 @@ public:
bool setPins(int sda, int scl); bool setPins(int sda, int scl);
bool begin(int sda=-1, int scl=-1, uint32_t frequency=0); // returns true, if successful init of i2c bus bool begin(int sda=-1, int scl=-1, uint32_t frequency=0); // returns true, if successful init of i2c bus
bool begin(uint8_t slaveAddr, int sda=-1, int scl=-1, uint32_t frequency=0);
bool end(); bool end();
void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms void setTimeOut(uint16_t timeOutMillis); // default timeout of i2c transactions is 50ms
...@@ -123,6 +131,7 @@ public: ...@@ -123,6 +131,7 @@ public:
void onReceive( void (*)(int) ); void onReceive( void (*)(int) );
void onRequest( void (*)(void) ); void onRequest( void (*)(void) );
size_t slaveWrite(const uint8_t *, size_t);
}; };
extern TwoWire Wire; extern TwoWire Wire;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment