From c55288a6101679b7f4f35241f708d87e40716703 Mon Sep 17 00:00:00 2001 From: fpr Date: Tue, 10 Oct 2017 17:32:44 +0200 Subject: [PATCH 1/4] Update Wire library properties Signed-off-by: fpr --- libraries/Wire/library.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/Wire/library.properties b/libraries/Wire/library.properties index 19a4d22ca1..8143ffa09f 100644 --- a/libraries/Wire/library.properties +++ b/libraries/Wire/library.properties @@ -1,8 +1,8 @@ name=Wire version=1.0 -author=Arduino -maintainer=Arduino -sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For Arduino DUE only. +author=Arduino, Wi6Labs +maintainer=stm32duino +sentence=Allows the communication between devices or sensors connected via Two Wire (I2C) Interface Bus. paragraph= category=Communication url=http://www.arduino.cc/en/Reference/Wire From cf25c92af5df5c6e2c77a44b35b78ed8622b8641 Mon Sep 17 00:00:00 2001 From: fpr Date: Tue, 10 Oct 2017 17:34:23 +0200 Subject: [PATCH 2/4] Add src folder to Wire library Signed-off-by: fpr --- libraries/Wire/{ => src}/Wire.cpp | 0 libraries/Wire/{ => src}/Wire.h | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename libraries/Wire/{ => src}/Wire.cpp (100%) rename libraries/Wire/{ => src}/Wire.h (100%) diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/src/Wire.cpp similarity index 100% rename from libraries/Wire/Wire.cpp rename to libraries/Wire/src/Wire.cpp diff --git a/libraries/Wire/Wire.h b/libraries/Wire/src/Wire.h similarity index 100% rename from libraries/Wire/Wire.h rename to libraries/Wire/src/Wire.h From 9e4c2b290a0435eda78995c67dd88377e75a315d Mon Sep 17 00:00:00 2001 From: fpr Date: Wed, 15 Nov 2017 09:28:20 +0100 Subject: [PATCH 3/4] Change Wire Rx/Tx buffers managements Buffers are now dynamically allocated (min size: BUFFER_LENGTH) Signed-off-by: fpr --- cores/arduino/stm32/twi.c | 15 ++++-- cores/arduino/stm32/twi.h | 6 +-- libraries/Wire/keywords.txt | 13 +++-- libraries/Wire/src/Wire.cpp | 97 +++++++++++++++++++++++++++++++------ libraries/Wire/src/Wire.h | 7 ++- 5 files changed, 106 insertions(+), 32 deletions(-) diff --git a/cores/arduino/stm32/twi.c b/cores/arduino/stm32/twi.c index f27239005e..1761d7d4e0 100644 --- a/cores/arduino/stm32/twi.c +++ b/cores/arduino/stm32/twi.c @@ -348,7 +348,7 @@ void i2c_setTiming(i2c_t *obj, uint32_t frequency) * @retval read status */ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, - uint8_t *data, uint8_t size) + uint8_t *data, uint16_t size) { i2c_status_e ret = I2C_ERROR; @@ -375,17 +375,24 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, * @param obj : pointer to i2c_t structure * @param data: pointer to data to be write * @param size: number of bytes to be write. - * @retval none + * @retval status */ -void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size) +i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size) { uint8_t i = 0; + // Protection to not override the TxBuffer + if(size > I2C_TXRX_BUFFER_SIZE) { + return I2C_ERROR; + } + // Check the communication status for(i = 0; i < size; i++) { obj->i2cTxRxBuffer[i] = *(data+i); obj->i2cTxRxBufferSize++; } + + return I2C_OK; } /** @@ -396,7 +403,7 @@ void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size) * @param size: number of bytes to be read. * @retval read status */ -i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size) +i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size) { i2c_status_e ret = I2C_ERROR; uint32_t tickstart = HAL_GetTick(); diff --git a/cores/arduino/stm32/twi.h b/cores/arduino/stm32/twi.h index 7125ebabf7..809ac36d95 100644 --- a/cores/arduino/stm32/twi.h +++ b/cores/arduino/stm32/twi.h @@ -148,9 +148,9 @@ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode, uint32_t ownAddress, uint8_t master); void i2c_deinit(i2c_t *obj); void i2c_setTiming(i2c_t *obj, uint32_t frequency); -i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size); -void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size); -i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size); +i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size); +i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size); +i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size); i2c_status_e i2c_IsDeviceReady(i2c_t *obj, uint8_t devAddr,uint32_t trials); diff --git a/libraries/Wire/keywords.txt b/libraries/Wire/keywords.txt index 47ffd52d02..f464dca8a3 100644 --- a/libraries/Wire/keywords.txt +++ b/libraries/Wire/keywords.txt @@ -10,13 +10,13 @@ # Methods and Functions (KEYWORD2) ####################################### -begin KEYWORD2 -setClock KEYWORD2 +begin KEYWORD2 +setClock KEYWORD2 beginTransmission KEYWORD2 -endTransmission KEYWORD2 -requestFrom KEYWORD2 -onReceive KEYWORD2 -onRequest KEYWORD2 +endTransmission KEYWORD2 +requestFrom KEYWORD2 +onReceive KEYWORD2 +onRequest KEYWORD2 ####################################### # Instances (KEYWORD2) @@ -28,4 +28,3 @@ Wire1 KEYWORD2 ####################################### # Constants (LITERAL1) ####################################### - diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index e14f1b6d33..a74aa2e756 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -28,12 +28,12 @@ extern "C" { #include "Wire.h" // Initialize Class Variables ////////////////////////////////////////////////// -uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; +uint8_t *TwoWire::rxBuffer = nullptr; uint8_t TwoWire::rxBufferIndex = 0; uint8_t TwoWire::rxBufferLength = 0; uint8_t TwoWire::txAddress = 0; -uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; +uint8_t *TwoWire::txBuffer = nullptr; uint8_t TwoWire::txBufferIndex = 0; uint8_t TwoWire::txBufferLength = 0; @@ -66,9 +66,11 @@ void TwoWire::begin(uint8_t address) { rxBufferIndex = 0; rxBufferLength = 0; + rxBuffer = resetBuffer(rxBuffer); txBufferIndex = 0; txBufferLength = 0; + txBuffer = resetBuffer(txBuffer); transmitting = 0; @@ -97,6 +99,10 @@ void TwoWire::begin(int address) void TwoWire::end(void) { + free(txBuffer); + txBuffer = nullptr; + free(rxBuffer); + rxBuffer = nullptr; i2c_deinit(&_i2c); } @@ -109,6 +115,13 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres { UNUSED(sendStop); if (master == true) { + rxBuffer = allocateBuffer(rxBuffer, quantity); + // error if no memory block available to allocate the buffer + if(rxBuffer == nullptr){ + setWriteError(); + return 0; + } + if (isize > 0) { // send internal address; this mode allows sending a repeated start to access // some devices' internal registers. This function is executed by the hardware @@ -128,12 +141,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres endTransmission(false); } - // clamp to buffer length - if(quantity > BUFFER_LENGTH){ - quantity = BUFFER_LENGTH; - } // perform blocking read into buffer - //uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop); uint8_t read = 0; if(I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity)) read = quantity; @@ -216,9 +224,15 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) break; } + //Reduce buffer size to free memory in case of large memory use + if(txBufferLength > BUFFER_LENGTH) { + txBuffer = resetBuffer(txBuffer); + } + // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; + // indicate that we are done transmitting transmitting = 0; } @@ -241,8 +255,9 @@ size_t TwoWire::write(uint8_t data) { if(transmitting){ // in master transmitter mode - // don't bother if buffer is full - if(txBufferLength >= BUFFER_LENGTH){ + txBuffer = allocateBuffer(txBuffer, txBufferLength + 1); + // error if no memory block available to allocate the buffer + if(txBuffer == nullptr){ setWriteError(); return 0; } @@ -254,27 +269,38 @@ size_t TwoWire::write(uint8_t data) }else{ // in slave send mode // reply to master - i2c_slave_write_IT(&_i2c,&data,1); + if(i2c_slave_write_IT(&_i2c,&data,1) != I2C_OK) { + return 0; + } } return 1; } -// must be called in: -// slave tx event callback -// or after beginTransmission(address) +/** + * @brief This function must be called in slave Tx event callback or after + * beginTransmission() and before endTransmission(). + * @param pdata: pointer to the buffer data + * @param quantity: number of bytes to write + * @retval number of bytes ready to write. + */ size_t TwoWire::write(const uint8_t *data, size_t quantity) { + size_t nb = 0; + if(transmitting){ // in master transmitter mode for(size_t i = 0; i < quantity; ++i){ - write(data[i]); + nb += write(data[i]); } + return nb; }else{ // in slave send mode // reply to master - i2c_slave_write_IT(&_i2c,(uint8_t *)data,quantity); + if(i2c_slave_write_IT(&_i2c, (uint8_t *)data, quantity) == I2C_OK) { + return quantity; + } } - return quantity; + return 0; } // must be called in: @@ -296,6 +322,12 @@ int TwoWire::read(void) if(rxBufferIndex < rxBufferLength){ value = rxBuffer[rxBufferIndex]; ++rxBufferIndex; + + /* Reduce buffer size to free memory in case of large memory use when no more + data available */ + if((rxBufferIndex == rxBufferLength) && (rxBufferLength > BUFFER_LENGTH)) { + rxBuffer = resetBuffer(rxBuffer); + } } return value; @@ -319,8 +351,10 @@ void TwoWire::flush(void) { rxBufferIndex = 0; rxBufferLength = 0; + rxBuffer = resetBuffer(rxBuffer); txBufferIndex = 0; txBufferLength = 0; + txBuffer = resetBuffer(txBuffer); } // behind the scenes function that is called when data is received @@ -377,6 +411,37 @@ void TwoWire::onRequest( void (*function)(void) ) user_onRequest = function; } +/** + * @brief Change the size of the buffer. + * @param buffer: pointer to the allocated buffer + * @param length: number of bytes to allocate + * @retval pointer to the new buffer location + */ +uint8_t *TwoWire::allocateBuffer(uint8_t *buffer, size_t length) +{ + // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer. + if(length < BUFFER_LENGTH) { + length = BUFFER_LENGTH; + } + + buffer = (uint8_t *)realloc(buffer, length * sizeof(uint8_t)); + return buffer; +} + +/** + * @brief Reset the buffer. Reduce its size to BUFFER_LENGTH. + * @param buffer: pointer to the allocated buffer + * @retval pointer to the new buffer location + */ +uint8_t *TwoWire::resetBuffer(uint8_t *buffer) +{ + buffer = (uint8_t *)realloc(buffer, BUFFER_LENGTH * sizeof(uint8_t)); + if(buffer != nullptr) { + memset(buffer, 0, BUFFER_LENGTH); + } + return buffer; +} + // Preinstantiate Objects ////////////////////////////////////////////////////// TwoWire Wire = TwoWire(); //D14-D15 diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 8250524569..4cb79deacc 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -36,12 +36,12 @@ class TwoWire : public Stream { private: - static uint8_t rxBuffer[BUFFER_LENGTH]; + static uint8_t *rxBuffer; static uint8_t rxBufferIndex; static uint8_t rxBufferLength; static uint8_t txAddress; - static uint8_t txBuffer[BUFFER_LENGTH]; + static uint8_t *txBuffer; static uint8_t txBufferIndex; static uint8_t txBufferLength; @@ -56,6 +56,9 @@ class TwoWire : public Stream static void onRequestService(void); static void onReceiveService(uint8_t*, int); + uint8_t *allocateBuffer(uint8_t *buffer, size_t length); + uint8_t *resetBuffer(uint8_t *buffer); + public: TwoWire(); TwoWire(uint8_t sda, uint8_t scl); From 3c7277d0bb7a05eb3c5671e274677de984aad59a Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Thu, 16 Nov 2017 09:09:50 +0100 Subject: [PATCH 4/4] Enhance Wire buffers usage - Do not call realloc each time, only if needed - Assume that user will use more than one time the same buffer size so avoid the call to realloc to decrease size - write: avoid copy byte/byte in the buffer Signed-off-by: Frederic.Pillon --- libraries/Wire/src/Wire.cpp | 94 +++++++++++++++++++++---------------- libraries/Wire/src/Wire.h | 13 +++-- 2 files changed, 64 insertions(+), 43 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index a74aa2e756..bb0963fda6 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -29,11 +29,13 @@ extern "C" { // Initialize Class Variables ////////////////////////////////////////////////// uint8_t *TwoWire::rxBuffer = nullptr; +uint8_t TwoWire::rxBufferAllocated = 0; uint8_t TwoWire::rxBufferIndex = 0; uint8_t TwoWire::rxBufferLength = 0; uint8_t TwoWire::txAddress = 0; uint8_t *TwoWire::txBuffer = nullptr; +uint8_t TwoWire::txBufferAllocated = 0; uint8_t TwoWire::txBufferIndex = 0; uint8_t TwoWire::txBufferLength = 0; @@ -66,11 +68,11 @@ void TwoWire::begin(uint8_t address) { rxBufferIndex = 0; rxBufferLength = 0; - rxBuffer = resetBuffer(rxBuffer); + resetRxBuffer(); txBufferIndex = 0; txBufferLength = 0; - txBuffer = resetBuffer(txBuffer); + resetTxBuffer(); transmitting = 0; @@ -101,8 +103,10 @@ void TwoWire::end(void) { free(txBuffer); txBuffer = nullptr; + txBufferAllocated = 0; free(rxBuffer); rxBuffer = nullptr; + rxBufferAllocated = 0; i2c_deinit(&_i2c); } @@ -115,7 +119,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres { UNUSED(sendStop); if (master == true) { - rxBuffer = allocateBuffer(rxBuffer, quantity); + allocateRxBuffer(quantity); // error if no memory block available to allocate the buffer if(rxBuffer == nullptr){ setWriteError(); @@ -224,10 +228,8 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) break; } - //Reduce buffer size to free memory in case of large memory use - if(txBufferLength > BUFFER_LENGTH) { - txBuffer = resetBuffer(txBuffer); - } + // reset Tx buffer + resetTxBuffer(); // reset tx buffer iterator vars txBufferIndex = 0; @@ -255,7 +257,7 @@ size_t TwoWire::write(uint8_t data) { if(transmitting){ // in master transmitter mode - txBuffer = allocateBuffer(txBuffer, txBufferLength + 1); + allocateTxBuffer(txBufferLength + 1); // error if no memory block available to allocate the buffer if(txBuffer == nullptr){ setWriteError(); @@ -285,14 +287,20 @@ size_t TwoWire::write(uint8_t data) */ size_t TwoWire::write(const uint8_t *data, size_t quantity) { - size_t nb = 0; - if(transmitting){ // in master transmitter mode - for(size_t i = 0; i < quantity; ++i){ - nb += write(data[i]); + allocateTxBuffer(txBufferLength + quantity); + // error if no memory block available to allocate the buffer + if(txBuffer == nullptr){ + setWriteError(); + return 0; } - return nb; + // put bytes in tx buffer + memcpy(&(txBuffer[txBufferIndex]), data, quantity); + txBufferIndex= txBufferIndex + quantity; + // update amount in buffer + txBufferLength = txBufferIndex; + return quantity; }else{ // in slave send mode // reply to master @@ -323,11 +331,12 @@ int TwoWire::read(void) value = rxBuffer[rxBufferIndex]; ++rxBufferIndex; - /* Reduce buffer size to free memory in case of large memory use when no more - data available */ - if((rxBufferIndex == rxBufferLength) && (rxBufferLength > BUFFER_LENGTH)) { - rxBuffer = resetBuffer(rxBuffer); - } + /* Commented as not I think it is not useful + * but kept to show that it is possible to + * reset rx buffer when no more data available */ + /*if(rxBufferIndex == rxBufferLength) { + resetRxBuffer(); + }*/ } return value; @@ -351,10 +360,10 @@ void TwoWire::flush(void) { rxBufferIndex = 0; rxBufferLength = 0; - rxBuffer = resetBuffer(rxBuffer); + resetRxBuffer(); txBufferIndex = 0; txBufferLength = 0; - txBuffer = resetBuffer(txBuffer); + resetTxBuffer(); } // behind the scenes function that is called when data is received @@ -373,9 +382,7 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) } // copy twi rx buffer into local read buffer // this enables new reads to happen in parallel - for(uint8_t i = 0; i < numBytes; ++i){ - rxBuffer[i] = inBytes[i]; - } + memcpy(rxBuffer, inBytes, numBytes); // set rx iterator vars rxBufferIndex = 0; rxBufferLength = numBytes; @@ -412,34 +419,41 @@ void TwoWire::onRequest( void (*function)(void) ) } /** - * @brief Change the size of the buffer. - * @param buffer: pointer to the allocated buffer + * @brief Allocate the Rx/Tx buffer to the requested length if needed + * @note Minimum allocated size is BUFFER_LENGTH) * @param length: number of bytes to allocate - * @retval pointer to the new buffer location */ -uint8_t *TwoWire::allocateBuffer(uint8_t *buffer, size_t length) +inline void TwoWire::allocateRxBuffer(size_t length) { + if(rxBufferAllocated < length) { // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer. - if(length < BUFFER_LENGTH) { - length = BUFFER_LENGTH; + if(length < BUFFER_LENGTH) { length = BUFFER_LENGTH; } + rxBuffer = (uint8_t *)realloc(rxBuffer, length * sizeof(uint8_t)); + rxBufferAllocated = (rxBuffer != nullptr) ? length: 0; } +} - buffer = (uint8_t *)realloc(buffer, length * sizeof(uint8_t)); - return buffer; +inline void TwoWire::allocateTxBuffer(size_t length) +{ + if(txBufferAllocated < length) { + // By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer. + if(length < BUFFER_LENGTH) { length = BUFFER_LENGTH; } + txBuffer = (uint8_t *)realloc(txBuffer, length * sizeof(uint8_t)); + txBufferAllocated = (txBuffer != nullptr) ? length: 0; + } } /** - * @brief Reset the buffer. Reduce its size to BUFFER_LENGTH. - * @param buffer: pointer to the allocated buffer - * @retval pointer to the new buffer location + * @brief Reset Rx/Tx buffer content to 0 */ -uint8_t *TwoWire::resetBuffer(uint8_t *buffer) +inline void TwoWire::resetRxBuffer(void) { - buffer = (uint8_t *)realloc(buffer, BUFFER_LENGTH * sizeof(uint8_t)); - if(buffer != nullptr) { - memset(buffer, 0, BUFFER_LENGTH); - } - return buffer; + if (rxBuffer != nullptr) memset(rxBuffer, 0, rxBufferAllocated); +} + +inline void TwoWire::resetTxBuffer(void) +{ + if (txBuffer != nullptr) memset(txBuffer, 0, txBufferAllocated); } // Preinstantiate Objects ////////////////////////////////////////////////////// diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 4cb79deacc..1f041e1341 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -37,11 +37,13 @@ class TwoWire : public Stream { private: static uint8_t *rxBuffer; + static uint8_t rxBufferAllocated; static uint8_t rxBufferIndex; static uint8_t rxBufferLength; static uint8_t txAddress; static uint8_t *txBuffer; + static uint8_t txBufferAllocated; static uint8_t txBufferIndex; static uint8_t txBufferLength; @@ -56,8 +58,11 @@ class TwoWire : public Stream static void onRequestService(void); static void onReceiveService(uint8_t*, int); - uint8_t *allocateBuffer(uint8_t *buffer, size_t length); - uint8_t *resetBuffer(uint8_t *buffer); + void allocateRxBuffer(size_t length); + void allocateTxBuffer(size_t length); + + void resetRxBuffer(void); + void resetTxBuffer(void); public: TwoWire(); @@ -73,7 +78,7 @@ class TwoWire : public Stream uint8_t endTransmission(uint8_t); uint8_t requestFrom(uint8_t, uint8_t); uint8_t requestFrom(uint8_t, uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); uint8_t requestFrom(int, int); uint8_t requestFrom(int, int, int); virtual size_t write(uint8_t); @@ -92,6 +97,8 @@ class TwoWire : public Stream using Print::write; }; + + extern TwoWire Wire; #endif