Skip to content

Commit 19930bf

Browse files
authored
Merge pull request #152 from fpistm/pr/131
Change Wire Rx/Tx buffers managements
2 parents e55fdab + 3c7277d commit 19930bf

File tree

6 files changed

+135
-40
lines changed

6 files changed

+135
-40
lines changed

cores/arduino/stm32/twi.c

+11-4
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ void i2c_setTiming(i2c_t *obj, uint32_t frequency)
348348
* @retval read status
349349
*/
350350
i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address,
351-
uint8_t *data, uint8_t size)
351+
uint8_t *data, uint16_t size)
352352

353353
{
354354
i2c_status_e ret = I2C_ERROR;
@@ -375,17 +375,24 @@ i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address,
375375
* @param obj : pointer to i2c_t structure
376376
* @param data: pointer to data to be write
377377
* @param size: number of bytes to be write.
378-
* @retval none
378+
* @retval status
379379
*/
380-
void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size)
380+
i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size)
381381
{
382382
uint8_t i = 0;
383383

384+
// Protection to not override the TxBuffer
385+
if(size > I2C_TXRX_BUFFER_SIZE) {
386+
return I2C_ERROR;
387+
}
388+
384389
// Check the communication status
385390
for(i = 0; i < size; i++) {
386391
obj->i2cTxRxBuffer[i] = *(data+i);
387392
obj->i2cTxRxBufferSize++;
388393
}
394+
395+
return I2C_OK;
389396
}
390397

391398
/**
@@ -396,7 +403,7 @@ void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size)
396403
* @param size: number of bytes to be read.
397404
* @retval read status
398405
*/
399-
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size)
406+
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size)
400407
{
401408
i2c_status_e ret = I2C_ERROR;
402409
uint32_t tickstart = HAL_GetTick();

cores/arduino/stm32/twi.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode,
148148
uint32_t ownAddress, uint8_t master);
149149
void i2c_deinit(i2c_t *obj);
150150
void i2c_setTiming(i2c_t *obj, uint32_t frequency);
151-
i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size);
152-
void i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint8_t size);
153-
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint8_t size);
151+
i2c_status_e i2c_master_write(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size);
152+
i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size);
153+
i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uint16_t size);
154154

155155
i2c_status_e i2c_IsDeviceReady(i2c_t *obj, uint8_t devAddr,uint32_t trials);
156156

libraries/Wire/keywords.txt

+6-7
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
# Methods and Functions (KEYWORD2)
1111
#######################################
1212

13-
begin KEYWORD2
14-
setClock KEYWORD2
13+
begin KEYWORD2
14+
setClock KEYWORD2
1515
beginTransmission KEYWORD2
16-
endTransmission KEYWORD2
17-
requestFrom KEYWORD2
18-
onReceive KEYWORD2
19-
onRequest KEYWORD2
16+
endTransmission KEYWORD2
17+
requestFrom KEYWORD2
18+
onReceive KEYWORD2
19+
onRequest KEYWORD2
2020

2121
#######################################
2222
# Instances (KEYWORD2)
@@ -28,4 +28,3 @@ Wire1 KEYWORD2
2828
#######################################
2929
# Constants (LITERAL1)
3030
#######################################
31-

libraries/Wire/library.properties

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
name=Wire
22
version=1.0
3-
author=Arduino
4-
maintainer=Arduino <[email protected]>
5-
sentence=Allows the communication between devices or sensors connected via Two Wire Interface Bus. For Arduino DUE only.
3+
author=Arduino, Wi6Labs
4+
maintainer=stm32duino
5+
sentence=Allows the communication between devices or sensors connected via Two Wire (I2C) Interface Bus.
66
paragraph=
77
category=Communication
88
url=http://www.arduino.cc/en/Reference/Wire

libraries/Wire/Wire.cpp renamed to libraries/Wire/src/Wire.cpp

+99-20
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,14 @@ extern "C" {
2828
#include "Wire.h"
2929

3030
// Initialize Class Variables //////////////////////////////////////////////////
31-
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
31+
uint8_t *TwoWire::rxBuffer = nullptr;
32+
uint8_t TwoWire::rxBufferAllocated = 0;
3233
uint8_t TwoWire::rxBufferIndex = 0;
3334
uint8_t TwoWire::rxBufferLength = 0;
3435

3536
uint8_t TwoWire::txAddress = 0;
36-
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
37+
uint8_t *TwoWire::txBuffer = nullptr;
38+
uint8_t TwoWire::txBufferAllocated = 0;
3739
uint8_t TwoWire::txBufferIndex = 0;
3840
uint8_t TwoWire::txBufferLength = 0;
3941

@@ -66,9 +68,11 @@ void TwoWire::begin(uint8_t address)
6668
{
6769
rxBufferIndex = 0;
6870
rxBufferLength = 0;
71+
resetRxBuffer();
6972

7073
txBufferIndex = 0;
7174
txBufferLength = 0;
75+
resetTxBuffer();
7276

7377
transmitting = 0;
7478

@@ -97,6 +101,12 @@ void TwoWire::begin(int address)
97101

98102
void TwoWire::end(void)
99103
{
104+
free(txBuffer);
105+
txBuffer = nullptr;
106+
txBufferAllocated = 0;
107+
free(rxBuffer);
108+
rxBuffer = nullptr;
109+
rxBufferAllocated = 0;
100110
i2c_deinit(&_i2c);
101111
}
102112

@@ -109,6 +119,13 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
109119
{
110120
UNUSED(sendStop);
111121
if (master == true) {
122+
allocateRxBuffer(quantity);
123+
// error if no memory block available to allocate the buffer
124+
if(rxBuffer == nullptr){
125+
setWriteError();
126+
return 0;
127+
}
128+
112129
if (isize > 0) {
113130
// send internal address; this mode allows sending a repeated start to access
114131
// some devices' internal registers. This function is executed by the hardware
@@ -128,12 +145,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
128145
endTransmission(false);
129146
}
130147

131-
// clamp to buffer length
132-
if(quantity > BUFFER_LENGTH){
133-
quantity = BUFFER_LENGTH;
134-
}
135148
// perform blocking read into buffer
136-
//uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop);
137149
uint8_t read = 0;
138150
if(I2C_OK == i2c_master_read(&_i2c, address << 1, rxBuffer, quantity))
139151
read = quantity;
@@ -216,9 +228,13 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
216228
break;
217229
}
218230

231+
// reset Tx buffer
232+
resetTxBuffer();
233+
219234
// reset tx buffer iterator vars
220235
txBufferIndex = 0;
221236
txBufferLength = 0;
237+
222238
// indicate that we are done transmitting
223239
transmitting = 0;
224240
}
@@ -241,8 +257,9 @@ size_t TwoWire::write(uint8_t data)
241257
{
242258
if(transmitting){
243259
// in master transmitter mode
244-
// don't bother if buffer is full
245-
if(txBufferLength >= BUFFER_LENGTH){
260+
allocateTxBuffer(txBufferLength + 1);
261+
// error if no memory block available to allocate the buffer
262+
if(txBuffer == nullptr){
246263
setWriteError();
247264
return 0;
248265
}
@@ -254,27 +271,44 @@ size_t TwoWire::write(uint8_t data)
254271
}else{
255272
// in slave send mode
256273
// reply to master
257-
i2c_slave_write_IT(&_i2c,&data,1);
274+
if(i2c_slave_write_IT(&_i2c,&data,1) != I2C_OK) {
275+
return 0;
276+
}
258277
}
259278
return 1;
260279
}
261280

262-
// must be called in:
263-
// slave tx event callback
264-
// or after beginTransmission(address)
281+
/**
282+
* @brief This function must be called in slave Tx event callback or after
283+
* beginTransmission() and before endTransmission().
284+
* @param pdata: pointer to the buffer data
285+
* @param quantity: number of bytes to write
286+
* @retval number of bytes ready to write.
287+
*/
265288
size_t TwoWire::write(const uint8_t *data, size_t quantity)
266289
{
267290
if(transmitting){
268291
// in master transmitter mode
269-
for(size_t i = 0; i < quantity; ++i){
270-
write(data[i]);
292+
allocateTxBuffer(txBufferLength + quantity);
293+
// error if no memory block available to allocate the buffer
294+
if(txBuffer == nullptr){
295+
setWriteError();
296+
return 0;
271297
}
298+
// put bytes in tx buffer
299+
memcpy(&(txBuffer[txBufferIndex]), data, quantity);
300+
txBufferIndex= txBufferIndex + quantity;
301+
// update amount in buffer
302+
txBufferLength = txBufferIndex;
303+
return quantity;
272304
}else{
273305
// in slave send mode
274306
// reply to master
275-
i2c_slave_write_IT(&_i2c,(uint8_t *)data,quantity);
307+
if(i2c_slave_write_IT(&_i2c, (uint8_t *)data, quantity) == I2C_OK) {
308+
return quantity;
309+
}
276310
}
277-
return quantity;
311+
return 0;
278312
}
279313

280314
// must be called in:
@@ -296,6 +330,13 @@ int TwoWire::read(void)
296330
if(rxBufferIndex < rxBufferLength){
297331
value = rxBuffer[rxBufferIndex];
298332
++rxBufferIndex;
333+
334+
/* Commented as not I think it is not useful
335+
* but kept to show that it is possible to
336+
* reset rx buffer when no more data available */
337+
/*if(rxBufferIndex == rxBufferLength) {
338+
resetRxBuffer();
339+
}*/
299340
}
300341

301342
return value;
@@ -319,8 +360,10 @@ void TwoWire::flush(void)
319360
{
320361
rxBufferIndex = 0;
321362
rxBufferLength = 0;
363+
resetRxBuffer();
322364
txBufferIndex = 0;
323365
txBufferLength = 0;
366+
resetTxBuffer();
324367
}
325368

326369
// behind the scenes function that is called when data is received
@@ -339,9 +382,7 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes)
339382
}
340383
// copy twi rx buffer into local read buffer
341384
// this enables new reads to happen in parallel
342-
for(uint8_t i = 0; i < numBytes; ++i){
343-
rxBuffer[i] = inBytes[i];
344-
}
385+
memcpy(rxBuffer, inBytes, numBytes);
345386
// set rx iterator vars
346387
rxBufferIndex = 0;
347388
rxBufferLength = numBytes;
@@ -377,6 +418,44 @@ void TwoWire::onRequest( void (*function)(void) )
377418
user_onRequest = function;
378419
}
379420

421+
/**
422+
* @brief Allocate the Rx/Tx buffer to the requested length if needed
423+
* @note Minimum allocated size is BUFFER_LENGTH)
424+
* @param length: number of bytes to allocate
425+
*/
426+
inline void TwoWire::allocateRxBuffer(size_t length)
427+
{
428+
if(rxBufferAllocated < length) {
429+
// By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
430+
if(length < BUFFER_LENGTH) { length = BUFFER_LENGTH; }
431+
rxBuffer = (uint8_t *)realloc(rxBuffer, length * sizeof(uint8_t));
432+
rxBufferAllocated = (rxBuffer != nullptr) ? length: 0;
433+
}
434+
}
435+
436+
inline void TwoWire::allocateTxBuffer(size_t length)
437+
{
438+
if(txBufferAllocated < length) {
439+
// By default we allocate BUFFER_LENGTH bytes. It is the min size of the buffer.
440+
if(length < BUFFER_LENGTH) { length = BUFFER_LENGTH; }
441+
txBuffer = (uint8_t *)realloc(txBuffer, length * sizeof(uint8_t));
442+
txBufferAllocated = (txBuffer != nullptr) ? length: 0;
443+
}
444+
}
445+
446+
/**
447+
* @brief Reset Rx/Tx buffer content to 0
448+
*/
449+
inline void TwoWire::resetRxBuffer(void)
450+
{
451+
if (rxBuffer != nullptr) memset(rxBuffer, 0, rxBufferAllocated);
452+
}
453+
454+
inline void TwoWire::resetTxBuffer(void)
455+
{
456+
if (txBuffer != nullptr) memset(txBuffer, 0, txBufferAllocated);
457+
}
458+
380459
// Preinstantiate Objects //////////////////////////////////////////////////////
381460

382461
TwoWire Wire = TwoWire(); //D14-D15

libraries/Wire/Wire.h renamed to libraries/Wire/src/Wire.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@
3636
class TwoWire : public Stream
3737
{
3838
private:
39-
static uint8_t rxBuffer[BUFFER_LENGTH];
39+
static uint8_t *rxBuffer;
40+
static uint8_t rxBufferAllocated;
4041
static uint8_t rxBufferIndex;
4142
static uint8_t rxBufferLength;
4243

4344
static uint8_t txAddress;
44-
static uint8_t txBuffer[BUFFER_LENGTH];
45+
static uint8_t *txBuffer;
46+
static uint8_t txBufferAllocated;
4547
static uint8_t txBufferIndex;
4648
static uint8_t txBufferLength;
4749

@@ -56,6 +58,12 @@ class TwoWire : public Stream
5658
static void onRequestService(void);
5759
static void onReceiveService(uint8_t*, int);
5860

61+
void allocateRxBuffer(size_t length);
62+
void allocateTxBuffer(size_t length);
63+
64+
void resetRxBuffer(void);
65+
void resetTxBuffer(void);
66+
5967
public:
6068
TwoWire();
6169
TwoWire(uint8_t sda, uint8_t scl);
@@ -70,7 +78,7 @@ class TwoWire : public Stream
7078
uint8_t endTransmission(uint8_t);
7179
uint8_t requestFrom(uint8_t, uint8_t);
7280
uint8_t requestFrom(uint8_t, uint8_t, uint8_t);
73-
uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t);
81+
uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t);
7482
uint8_t requestFrom(int, int);
7583
uint8_t requestFrom(int, int, int);
7684
virtual size_t write(uint8_t);
@@ -89,6 +97,8 @@ class TwoWire : public Stream
8997
using Print::write;
9098
};
9199

100+
101+
92102
extern TwoWire Wire;
93103

94104
#endif

0 commit comments

Comments
 (0)