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/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 diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/src/Wire.cpp similarity index 78% rename from libraries/Wire/Wire.cpp rename to libraries/Wire/src/Wire.cpp index e14f1b6d33..d329edf35b 100644 --- a/libraries/Wire/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 is size if greater than 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/Wire.h b/libraries/Wire/src/Wire.h similarity index 94% rename from libraries/Wire/Wire.h rename to libraries/Wire/src/Wire.h index 8250524569..4cb79deacc 100644 --- a/libraries/Wire/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);