From b145e6597589272956a75f9d1002e0ca2cbd0f30 Mon Sep 17 00:00:00 2001 From: me-no-dev Date: Mon, 11 Oct 2021 14:46:31 +0300 Subject: [PATCH] API Optimizations - Support Wire::end() for Slave - Prevent Master operations when in Slave mode --- cores/esp32/esp32-hal-i2c-slave.c | 133 ++++++++++-------- cores/esp32/esp32-hal-i2c-slave.h | 8 +- libraries/Wire/src/Wire.cpp | 219 +++++++++++++++++------------- libraries/Wire/src/Wire.h | 1 + 4 files changed, 206 insertions(+), 155 deletions(-) diff --git a/cores/esp32/esp32-hal-i2c-slave.c b/cores/esp32/esp32-hal-i2c-slave.c index 96750c5a..458b74f2 100755 --- a/cores/esp32/esp32-hal-i2c-slave.c +++ b/cores/esp32/esp32-hal-i2c-slave.c @@ -181,6 +181,7 @@ static inline bool i2c_ll_slave_rw(i2c_dev_t *hw)//not exposed by hal_ll } //-------------------------------------- PRIVATE (Function Prototypes) ------------------------------------------------ +static void i2c_slave_free_resources(i2c_slave_struct_t * i2c); static void i2c_slave_delay_us(uint64_t us); static void i2c_slave_gpio_mode(int8_t pin, gpio_mode_t mode); static bool i2c_slave_check_line_state(int8_t sda, int8_t scl); @@ -199,7 +200,7 @@ static void i2c_slave_task(void *pv_args); //-------------------------------------- Public Functions ------------------------------------------------------------- //===================================================================================================================== -esp_err_t i2c_slave_attach_callbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, 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){ if(num >= SOC_I2C_NUM){ log_e("Invalid port num: %u", num); return ESP_ERR_INVALID_ARG; @@ -213,57 +214,7 @@ esp_err_t i2c_slave_attach_callbacks(uint8_t num, i2c_slave_request_cb_t request return ESP_OK; } -esp_err_t i2c_slave_deinit(uint8_t num){ - if(num >= SOC_I2C_NUM){ - log_e("Invalid port num: %u", num); - return ESP_ERR_INVALID_ARG; - } - - i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; - I2C_SLAVE_MUTEX_LOCK(); - i2c_slave_detach_gpio(i2c); - i2c_ll_set_slave_addr(i2c->dev, 0, false); - i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); - i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK); - - if (i2c->intr_handle) { - esp_intr_free(i2c->intr_handle); - i2c->intr_handle = NULL; - } - - if(i2c->task_handle){ - vTaskDelete(i2c->task_handle); - i2c->task_handle = NULL; - } - -#if I2C_SLAVE_USE_RX_QUEUE - if (i2c->rx_queue) { - vQueueDelete(i2c->rx_queue); - i2c->rx_queue = NULL; - } -#else - if (i2c->rx_ring_buf) { - vRingbufferDelete(i2c->rx_ring_buf); - i2c->rx_ring_buf = NULL; - } -#endif - - if (i2c->tx_queue) { - vQueueDelete(i2c->tx_queue); - i2c->tx_queue = NULL; - } - - if (i2c->event_queue) { - vQueueDelete(i2c->event_queue); - i2c->event_queue = NULL; - } - - i2c->rx_data_count = 0; - I2C_SLAVE_MUTEX_UNLOCK(); - return ESP_OK; -} - -esp_err_t i2c_slave_init(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len) { +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) { if(num >= SOC_I2C_NUM){ log_e("Invalid port num: %u", num); return ESP_ERR_INVALID_ARG; @@ -274,6 +225,12 @@ esp_err_t i2c_slave_init(uint8_t num, int sda, int scl, uint16_t slaveID, uint32 return ESP_ERR_INVALID_ARG; } + if(!frequency){ + frequency = 100000; + } else if(frequency > 1000000){ + frequency = 1000000; + } + log_i("Initialising I2C Slave: sda=%d scl=%d freq=%d, addr=0x%x", sda, scl, frequency, slaveID); i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; @@ -288,9 +245,9 @@ esp_err_t i2c_slave_init(uint8_t num, int sda, int scl, uint16_t slaveID, uint32 } } #endif - i2c_slave_deinit(num); I2C_SLAVE_MUTEX_LOCK(); + i2c_slave_free_resources(i2c); #if I2C_SLAVE_USE_RX_QUEUE i2c->rx_queue = xQueueCreate(rx_len, sizeof(uint8_t)); @@ -391,18 +348,39 @@ esp_err_t i2c_slave_init(uint8_t num, int sda, int scl, uint16_t slaveID, uint32 return ret; fail: + i2c_slave_free_resources(i2c); I2C_SLAVE_MUTEX_UNLOCK(); - i2c_slave_deinit(num); return ret; } -size_t i2c_slave_write(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { +esp_err_t i2cSlaveDeinit(uint8_t num){ + if(num >= SOC_I2C_NUM){ + log_e("Invalid port num: %u", num); + return ESP_ERR_INVALID_ARG; + } + + i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; + if(!i2c->lock){ + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } + I2C_SLAVE_MUTEX_LOCK(); + i2c_slave_free_resources(i2c); + I2C_SLAVE_MUTEX_UNLOCK(); + return ESP_OK; +} + +size_t i2cSlaveWrite(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms) { if(num >= SOC_I2C_NUM){ log_e("Invalid port num: %u", num); return 0; } size_t to_queue = 0, to_fifo = 0; i2c_slave_struct_t * i2c = &_i2c_bus_array[num]; + if(!i2c->lock){ + log_e("Lock is not initialized! Did you call i2c_slave_init()?"); + return ESP_ERR_NO_MEM; + } if(!i2c->tx_queue){ return 0; } @@ -460,6 +438,47 @@ size_t i2c_slave_write(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t t //-------------------------------------- Private Functions ------------------------------------------------------------ //===================================================================================================================== +static void i2c_slave_free_resources(i2c_slave_struct_t * i2c){ + i2c_slave_detach_gpio(i2c); + i2c_ll_set_slave_addr(i2c->dev, 0, false); + i2c_ll_disable_intr_mask(i2c->dev, I2C_LL_INTR_MASK); + i2c_ll_clr_intsts_mask(i2c->dev, I2C_LL_INTR_MASK); + + if (i2c->intr_handle) { + esp_intr_free(i2c->intr_handle); + i2c->intr_handle = NULL; + } + + if(i2c->task_handle){ + vTaskDelete(i2c->task_handle); + i2c->task_handle = NULL; + } + +#if I2C_SLAVE_USE_RX_QUEUE + if (i2c->rx_queue) { + vQueueDelete(i2c->rx_queue); + i2c->rx_queue = NULL; + } +#else + if (i2c->rx_ring_buf) { + vRingbufferDelete(i2c->rx_ring_buf); + i2c->rx_ring_buf = NULL; + } +#endif + + if (i2c->tx_queue) { + vQueueDelete(i2c->tx_queue); + i2c->tx_queue = NULL; + } + + if (i2c->event_queue) { + vQueueDelete(i2c->event_queue); + i2c->event_queue = NULL; + } + + i2c->rx_data_count = 0; +} + static bool i2c_slave_set_frequency(i2c_slave_struct_t * i2c, uint32_t clk_speed) { if (i2c == NULL) { @@ -610,7 +629,7 @@ static bool i2c_slave_send_event(i2c_slave_struct_t * i2c, i2c_slave_queue_event bool pxHigherPriorityTaskWoken = false; if(i2c->event_queue) { if(xQueueSendFromISR(i2c->event_queue, event, (BaseType_t * const)&pxHigherPriorityTaskWoken) != pdTRUE){ - log_e("event_queue_full"); + //log_e("event_queue_full"); } } return pxHigherPriorityTaskWoken; @@ -684,7 +703,7 @@ static void i2c_slave_isr_handler(void* arg) if(rx_fifo_len){ //READ RX FIFO pxHigherPriorityTaskWoken |= i2c_slave_handle_rx_fifo_full(i2c, rx_fifo_len); } - if(!slave_rw || i2c->rx_data_count){ //WRITE or RepeatedStart + if(i2c->rx_data_count){ //WRITE or RepeatedStart //SEND RX Event i2c_slave_queue_event_t event; event.event = I2C_SLAVE_EVT_RX; diff --git a/cores/esp32/esp32-hal-i2c-slave.h b/cores/esp32/esp32-hal-i2c-slave.h index c63a2b0c..ceed8b10 100755 --- a/cores/esp32/esp32-hal-i2c-slave.h +++ b/cores/esp32/esp32-hal-i2c-slave.h @@ -24,11 +24,11 @@ extern "C" { 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 i2c_slave_attach_callbacks(uint8_t num, i2c_slave_request_cb_t request_callback, i2c_slave_receive_cb_t receive_callback, 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 i2c_slave_init(uint8_t num, int sda, int scl, uint16_t slaveID, uint32_t frequency, size_t rx_len, size_t tx_len); -esp_err_t i2c_slave_deinit(uint8_t num); -size_t i2c_slave_write(uint8_t num, const uint8_t *buf, uint32_t len, uint32_t timeout_ms); +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 } diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 06e19d12..1c8775f0 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -63,6 +63,47 @@ TwoWire::~TwoWire() #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) { #if !CONFIG_DISABLE_HAL_LOCKS @@ -80,8 +121,7 @@ bool TwoWire::setPins(int sdaPin, int sclPin) } #endif if(!i2cIsInit(num)){ - sda = sdaPin; - scl = sclPin; + initPins(sdaPin, sclPin); } else { log_e("bus already initialized. change pins only when not."); } @@ -92,6 +132,52 @@ bool TwoWire::setPins(int sdaPin, int sclPin) return !i2cIsInit(num); } +// 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(!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; +} + +// Master Begin bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) { bool started = false; @@ -110,46 +196,18 @@ bool TwoWire::begin(int sdaPin, int sclPin, uint32_t frequency) 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(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"); - goto end; //no Default pin for Second Peripheral - } else { - sdaPin = sda; // reuse prior pin - } - } + if(!initPins(sdaPin, sclPin)){ + goto end; } - - 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"); - goto end; //no Default pin for Second Peripheral - } else { - sclPin = scl; // reuse prior pin - } - } - } - - sda = sdaPin; - scl = sclPin; err = i2cInit(num, sda, scl, frequency); started = (err == ESP_OK); @@ -173,7 +231,12 @@ bool TwoWire::end() return false; } #endif - if(i2cIsInit(num)){ + if(is_slave){ + err = i2cSlaveDeinit(num); + if(err == ESP_OK){ + is_slave = false; + } + } else if(i2cIsInit(num)){ err = i2cDeinit(num); } #if !CONFIG_DISABLE_HAL_LOCKS @@ -193,7 +256,11 @@ uint32_t TwoWire::getClock() log_e("could not acquire lock"); } else { #endif - i2cGetClock(num, &frequency); + if(is_slave){ + log_e("Bus is in Slave Mode"); + } else { + i2cGetClock(num, &frequency); + } #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); @@ -212,7 +279,12 @@ bool TwoWire::setClock(uint32_t frequency) return false; } #endif - err = i2cSetClock(num, frequency); + if(is_slave){ + log_e("Bus is in Slave Mode"); + err = ESP_FAIL; + } else { + err = i2cSetClock(num, frequency); + } #if !CONFIG_DISABLE_HAL_LOCKS //release lock xSemaphoreGive(lock); @@ -232,6 +304,10 @@ uint16_t TwoWire::getTimeOut() void TwoWire::beginTransmission(uint16_t address) { + if(is_slave){ + log_e("Bus is in Slave Mode"); + return; + } #if !CONFIG_DISABLE_HAL_LOCKS if(nonStop && nonStopTask == xTaskGetCurrentTaskHandle()){ log_e("Unfinished Repeated Start transaction! Expected requestFrom, not beginTransmission! Clearing..."); @@ -251,6 +327,10 @@ void TwoWire::beginTransmission(uint16_t address) uint8_t TwoWire::endTransmission(bool sendStop) { + if(is_slave){ + log_e("Bus is in Slave Mode"); + return 4; + } esp_err_t err = ESP_OK; if(sendStop){ err = i2cWrite(num, txAddress, txBuffer, txLength, _timeOutMillis); @@ -276,6 +356,10 @@ uint8_t TwoWire::endTransmission(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; if(nonStop #if !CONFIG_DISABLE_HAL_LOCKS @@ -406,62 +490,9 @@ uint8_t TwoWire::endTransmission(void) return endTransmission(true); } -bool TwoWire::begin(uint8_t addr, int sdaPin, int sclPin, uint32_t frequency) -{ - if(!frequency){ - frequency = 100000; - } else if(frequency > 1000000){ - frequency = 1000000; - } - - 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; - i2c_slave_attach_callbacks(num, onRequestService, onReceiveService, this); - if(i2c_slave_init(num, sda, scl, addr, frequency, I2C_BUFFER_LENGTH, I2C_BUFFER_LENGTH) != ESP_OK){ - Serial.println("INIT ERROR"); - return false; - } - is_slave = true; - return true; -} - size_t TwoWire::slaveWrite(const uint8_t * buffer, size_t len) { - return i2c_slave_write(num, buffer, len, _timeOutMillis); + return i2cSlaveWrite(num, buffer, len, _timeOutMillis); } void TwoWire::onReceiveService(uint8_t num, uint8_t* inBytes, size_t numBytes, bool stop, void * arg) diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index f7d6a0f7..892846b3 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -67,6 +67,7 @@ private: 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: TwoWire(uint8_t bus_num);