Skip to content

Commit 0b7dbae

Browse files
committed
I2C multi instances: Remove static qualifier on TwoWire attributes
I2C buffers, as well as some other attributes of the TwoWire class, should not be static (shared between instances), otherwise multi instance I2C doesn't work properly. For example when MCU is master on one instance and slave on the other, Slave reception under interruption can happen in the middle of master transmission, and there is conflict on the shared resources. fixes #699
1 parent 0ff0a2a commit 0b7dbae

File tree

4 files changed

+49
-53
lines changed

4 files changed

+49
-53
lines changed

libraries/Wire/src/Wire.cpp

Lines changed: 25 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,6 @@ extern "C" {
2727

2828
#include "Wire.h"
2929

30-
// Initialize Class Variables //////////////////////////////////////////////////
31-
uint8_t *TwoWire::rxBuffer = nullptr;
32-
uint8_t TwoWire::rxBufferAllocated = 0;
33-
uint8_t TwoWire::rxBufferIndex = 0;
34-
uint8_t TwoWire::rxBufferLength = 0;
35-
36-
uint8_t TwoWire::txAddress = 0;
37-
uint8_t *TwoWire::txBuffer = nullptr;
38-
uint8_t TwoWire::txBufferAllocated = 0;
39-
uint8_t TwoWire::txBufferIndex = 0;
40-
uint8_t TwoWire::txBufferLength = 0;
41-
42-
uint8_t TwoWire::transmitting = 0;
43-
void (*TwoWire::user_onRequest)(void);
44-
void (*TwoWire::user_onReceive)(int);
45-
4630
// Constructors ////////////////////////////////////////////////////////////////
4731

4832
TwoWire::TwoWire()
@@ -81,6 +65,13 @@ void TwoWire::begin(uint8_t address, bool generalCall)
8165
txBufferLength = 0;
8266
resetTxBuffer();
8367

68+
rxBuffer = nullptr;
69+
rxBufferAllocated = 0;
70+
txAddress = 0;
71+
txBuffer = nullptr;
72+
txBufferAllocated = 0;
73+
_i2c.__this = (void *)this;
74+
user_onRequest = NULL;
8475
transmitting = 0;
8576

8677
ownAddress = address << 1;
@@ -403,44 +394,48 @@ void TwoWire::flush(void)
403394
}
404395

405396
// behind the scenes function that is called when data is received
406-
void TwoWire::onReceiveService(uint8_t *inBytes, int numBytes)
397+
void TwoWire::onReceiveService(i2c_t *obj, uint8_t *inBytes, int numBytes)
407398
{
399+
TwoWire *TW = (TwoWire *)(obj->__this);
400+
408401
// don't bother if user hasn't registered a callback
409-
if (user_onReceive) {
402+
if (TW->user_onReceive) {
410403
// don't bother if rx buffer is in use by a master requestFrom() op
411404
// i know this drops data, but it allows for slight stupidity
412405
// meaning, they may not have read all the master requestFrom() data yet
413-
if (rxBufferIndex >= rxBufferLength) {
406+
if (TW->rxBufferIndex >= TW->rxBufferLength) {
414407

415-
allocateRxBuffer(numBytes);
408+
TW->allocateRxBuffer(numBytes);
416409
// error if no memory block available to allocate the buffer
417-
if (rxBuffer == nullptr) {
410+
if (TW->rxBuffer == nullptr) {
418411
Error_Handler();
419412
}
420413

421414
// copy twi rx buffer into local read buffer
422415
// this enables new reads to happen in parallel
423-
memcpy(rxBuffer, inBytes, numBytes);
416+
memcpy(TW->rxBuffer, inBytes, numBytes);
424417
// set rx iterator vars
425-
rxBufferIndex = 0;
426-
rxBufferLength = numBytes;
418+
TW->rxBufferIndex = 0;
419+
TW->rxBufferLength = numBytes;
427420
// alert user program
428-
user_onReceive(numBytes);
421+
TW->user_onReceive(numBytes);
429422
}
430423
}
431424
}
432425

433426
// behind the scenes function that is called when data is requested
434-
void TwoWire::onRequestService(void)
427+
void TwoWire::onRequestService(i2c_t *obj)
435428
{
429+
TwoWire *TW = (TwoWire *)(obj->__this);
430+
436431
// don't bother if user hasn't registered a callback
437-
if (user_onRequest) {
432+
if (TW->user_onRequest) {
438433
// reset tx buffer iterator vars
439434
// !!! this will kill any pending pre-master sendTo() activity
440-
txBufferIndex = 0;
441-
txBufferLength = 0;
435+
TW->txBufferIndex = 0;
436+
TW->txBufferLength = 0;
442437
// alert user program
443-
user_onRequest();
438+
TW->user_onRequest();
444439
}
445440
}
446441

libraries/Wire/src/Wire.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,28 @@ extern "C" {
3737

3838
class TwoWire : public Stream {
3939
private:
40-
static uint8_t *rxBuffer;
41-
static uint8_t rxBufferAllocated;
42-
static uint8_t rxBufferIndex;
43-
static uint8_t rxBufferLength;
40+
uint8_t *rxBuffer;
41+
uint8_t rxBufferAllocated;
42+
uint8_t rxBufferIndex;
43+
uint8_t rxBufferLength;
4444

45-
static uint8_t txAddress;
46-
static uint8_t *txBuffer;
47-
static uint8_t txBufferAllocated;
48-
static uint8_t txBufferIndex;
49-
static uint8_t txBufferLength;
45+
uint8_t txAddress;
46+
uint8_t *txBuffer;
47+
uint8_t txBufferAllocated;
48+
uint8_t txBufferIndex;
49+
uint8_t txBufferLength;
5050

51-
static uint8_t transmitting;
51+
uint8_t transmitting;
5252

5353
uint8_t ownAddress;
5454
i2c_t _i2c;
5555

56-
static void (*user_onRequest)(void);
57-
static void (*user_onReceive)(int);
58-
static void onRequestService(void);
59-
static void onReceiveService(uint8_t *, int);
56+
void (*user_onRequest)(void);
57+
void (*user_onReceive)(int);
58+
static void onRequestService(i2c_t *);
59+
static void onReceiveService(i2c_t *, uint8_t *, int);
6060

61-
static void allocateRxBuffer(size_t length);
61+
void allocateRxBuffer(size_t length);
6262
void allocateTxBuffer(size_t length);
6363

6464
void resetRxBuffer(void);

libraries/Wire/src/utility/twi.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -948,7 +948,7 @@ i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c)
948948
* @param function: callback function to use
949949
* @retval None
950950
*/
951-
void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(uint8_t *, int))
951+
void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(i2c_t *, uint8_t *, int))
952952
{
953953
if ((obj != NULL) && (function != NULL)) {
954954
obj->i2c_onSlaveReceive = function;
@@ -961,7 +961,7 @@ void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(uint8_t *, int))
961961
* @param function: callback function to use
962962
* @retval None
963963
*/
964-
void i2c_attachSlaveTxEvent(i2c_t *obj, void (*function)(void))
964+
void i2c_attachSlaveTxEvent(i2c_t *obj, void (*function)(i2c_t *))
965965
{
966966
if ((obj != NULL) && (function != NULL)) {
967967
obj->i2c_onSlaveTransmit = function;
@@ -986,7 +986,7 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui
986986
obj->slaveMode = SLAVE_MODE_TRANSMIT;
987987

988988
if (obj->i2c_onSlaveTransmit != NULL) {
989-
obj->i2c_onSlaveTransmit();
989+
obj->i2c_onSlaveTransmit(obj);
990990
}
991991
#if defined(STM32F0xx) || defined(STM32F1xx) || defined(STM32F2xx) || defined(STM32F3xx) ||\
992992
defined(STM32F4xx) || defined(STM32L0xx) || defined(STM32L1xx) || defined(STM32MP1xx)
@@ -1026,7 +1026,7 @@ void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
10261026
/* Previous master transaction now ended, so inform upper layer if needed
10271027
* then prepare for listening to next request */
10281028
if ((obj->slaveMode == SLAVE_MODE_RECEIVE) && (obj->slaveRxNbData != 0)) {
1029-
obj->i2c_onSlaveReceive((uint8_t *) obj->i2cTxRxBuffer, obj->slaveRxNbData);
1029+
obj->i2c_onSlaveReceive(obj, (uint8_t *) obj->i2cTxRxBuffer, obj->slaveRxNbData);
10301030
}
10311031
obj->slaveMode = SLAVE_MODE_LISTEN;
10321032
obj->slaveRxNbData = 0;

libraries/Wire/src/utility/twi.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,16 @@ struct i2c_s {
9999
*/
100100
I2C_TypeDef *i2c;
101101
I2C_HandleTypeDef handle;
102+
void *__this;
102103
PinName sda;
103104
PinName scl;
104105
IRQn_Type irq;
105106
#if !defined(STM32F0xx) && !defined(STM32G0xx) && !defined(STM32L0xx)
106107
IRQn_Type irqER;
107108
#endif /* !STM32F0xx && !STM32G0xx && !STM32L0xx */
108109
volatile int slaveRxNbData; // Number of accumulated bytes received in Slave mode
109-
void (*i2c_onSlaveReceive)(uint8_t *, int);
110-
void (*i2c_onSlaveTransmit)(void);
110+
void (*i2c_onSlaveReceive)(i2c_t *, uint8_t *, int);
111+
void (*i2c_onSlaveTransmit)(i2c_t *);
111112
volatile uint8_t i2cTxRxBuffer[I2C_TXRX_BUFFER_SIZE];
112113
volatile uint8_t i2cTxRxBufferSize;
113114
volatile uint8_t slaveMode;
@@ -138,8 +139,8 @@ i2c_status_e i2c_master_read(i2c_t *obj, uint8_t dev_address, uint8_t *data, uin
138139

139140
i2c_status_e i2c_IsDeviceReady(i2c_t *obj, uint8_t devAddr, uint32_t trials);
140141

141-
void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(uint8_t *, int));
142-
void i2c_attachSlaveTxEvent(i2c_t *obj, void (*function)(void));
142+
void i2c_attachSlaveRxEvent(i2c_t *obj, void (*function)(i2c_t *, uint8_t *, int));
143+
void i2c_attachSlaveTxEvent(i2c_t *obj, void (*function)(i2c_t *));
143144

144145
#ifdef __cplusplus
145146
}

0 commit comments

Comments
 (0)