Skip to content

Commit b043838

Browse files
committed
I2C Slave : rework slave receive data sequence
This work includes some rework of the Slave RX path, which is based on below principle: - we don't know in advance how many bytes will be sent by the I2C master so we'll be listening to bytes 1 by 1 - in order to get them one by one, we're programing the I2C with HAL_I2C_Slave_Sequential_Receive_IT and 1 byte at a time and we're using the HAL_I2C_SlaveRxCpltCallback to store the byte then programing again for next byte. - this sequence is ended when the HAL_I2C_ListenCpltCallback is called, which happens when the master ends the ongoing sequence. We can then prepare for the next one. In order to implement this mecanism, we're introduced a local counter slaveRxNbData where we store the number of received bytes, as well as a new slave mode SLAVE_MODE_LISTEN which allows for extra checks. i2c_s structure members that can be modified from main context or under interrupt context have been marked as volatile.
1 parent 10925a1 commit b043838

File tree

2 files changed

+57
-12
lines changed

2 files changed

+57
-12
lines changed

cores/arduino/stm32/twi.c

+53-9
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575

7676
#define SLAVE_MODE_TRANSMIT 0
7777
#define SLAVE_MODE_RECEIVE 1
78+
#define SLAVE_MODE_LISTEN 2
79+
7880

7981
/**
8082
* @}
@@ -283,6 +285,9 @@ void i2c_custom_init(i2c_t *obj, i2c_timing_e timing, uint32_t addressingMode, u
283285
HAL_I2C_Init(handle);
284286

285287
obj->isMaster = master;
288+
/* Initialize default values */
289+
obj->slaveRxNbData = 0;
290+
obj->slaveMode = SLAVE_MODE_LISTEN;
286291
}
287292

288293
/**
@@ -395,9 +400,10 @@ i2c_status_e i2c_slave_write_IT(i2c_t *obj, uint8_t *data, uint16_t size)
395400
// Check the communication status
396401
for(i = 0; i < size; i++) {
397402
obj->i2cTxRxBuffer[i] = *(data+i);
398-
obj->i2cTxRxBufferSize++;
399403
}
400404

405+
obj->i2cTxRxBufferSize = size;
406+
401407
return I2C_OK;
402408
}
403409

@@ -509,8 +515,6 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui
509515

510516
if(AddrMatchCode == hi2c->Init.OwnAddress1) {
511517
if(TransferDirection == I2C_DIRECTION_RECEIVE) {
512-
513-
obj->i2cTxRxBufferSize = 0;
514518
obj->slaveMode = SLAVE_MODE_TRANSMIT;
515519

516520
if(obj->i2c_onSlaveTransmit != NULL) {
@@ -519,9 +523,12 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui
519523
HAL_I2C_Slave_Sequential_Transmit_IT(hi2c, obj->i2cTxRxBuffer,
520524
obj->i2cTxRxBufferSize, I2C_LAST_FRAME);
521525
} else {
526+
obj->slaveRxNbData = 0;
522527
obj->slaveMode = SLAVE_MODE_RECEIVE;
523-
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, obj->i2cTxRxBuffer,
524-
I2C_TXRX_BUFFER_SIZE, I2C_LAST_FRAME);
528+
/* We don't know in advance how many bytes will be sent by master so
529+
* we'll fetch one by one until master ends the sequence */
530+
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, &(obj->i2cTxRxBuffer[obj->slaveRxNbData]),
531+
1, I2C_NEXT_FRAME);
525532
}
526533
}
527534
}
@@ -534,19 +541,56 @@ void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, ui
534541
*/
535542
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
536543
{
537-
uint8_t nbData = 0;
538544
i2c_t *obj = get_i2c_obj(hi2c);
539545

546+
/* Previous master transaction now ended, so inform upper layer if needed
547+
* then prepare for listeing to next request */
540548
if((obj->i2c_onSlaveReceive != NULL) &&
541549
(obj->slaveMode == SLAVE_MODE_RECEIVE)) {
542-
nbData = I2C_TXRX_BUFFER_SIZE - obj->handle.XferSize;
543-
if(nbData != 0) {
544-
obj->i2c_onSlaveReceive(obj->i2cTxRxBuffer, nbData);
550+
if(obj->slaveRxNbData != 0) {
551+
obj->i2c_onSlaveReceive(obj->i2cTxRxBuffer, obj->slaveRxNbData);
545552
}
546553
}
554+
obj->slaveMode = SLAVE_MODE_LISTEN;
555+
obj->slaveRxNbData = 0;
547556
HAL_I2C_EnableListen_IT(hi2c);
548557
}
549558

559+
/**
560+
* @brief Slave RX complete callback
561+
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
562+
* the configuration information for the specified I2C.
563+
* @retval None
564+
*/
565+
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
566+
{
567+
i2c_t *obj = get_i2c_obj(hi2c);
568+
/* One more byte was received, store it then prepare next */
569+
if(obj->slaveRxNbData < I2C_TXRX_BUFFER_SIZE) {
570+
obj->slaveRxNbData++;
571+
} else {
572+
printf("ERROR: I2C Slave RX overflow\n");
573+
}
574+
/* Restart interrupt mode for next Byte */
575+
if(obj->slaveMode == SLAVE_MODE_RECEIVE) {
576+
HAL_I2C_Slave_Sequential_Receive_IT(hi2c, &(obj->i2cTxRxBuffer[obj->slaveRxNbData]),
577+
1, I2C_NEXT_FRAME);
578+
}
579+
}
580+
581+
/**
582+
* @brief Slave TX complete callback
583+
* @param hi2c Pointer to a I2C_HandleTypeDef structure that contains
584+
* the configuration information for the specified I2C.
585+
* @retval None
586+
*/
587+
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
588+
{
589+
i2c_t *obj = get_i2c_obj(hi2c);
590+
/* reset transmit buffer size */
591+
obj->i2cTxRxBufferSize = 0;
592+
}
593+
550594
/**
551595
* @brief I2C error callback.
552596
* @note In master mode, the callback is not used because the error is reported

cores/arduino/stm32/twi.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,13 @@ struct i2c_s {
9191
#if !defined(STM32F0xx) && !defined(STM32L0xx)
9292
IRQn_Type irqER;
9393
#endif //!defined(STM32F0xx) && !defined(STM32L0xx)
94-
uint8_t slaveMode;
94+
volatile uint8_t slaveMode;
9595
uint8_t isMaster;
96+
volatile int slaveRxNbData; // Number of accumulated bytes received in Slave mode
9697
void (*i2c_onSlaveReceive)(uint8_t *, int);
9798
void (*i2c_onSlaveTransmit)(void);
98-
uint8_t i2cTxRxBuffer[I2C_TXRX_BUFFER_SIZE];
99-
uint8_t i2cTxRxBufferSize;
99+
volatile uint8_t i2cTxRxBuffer[I2C_TXRX_BUFFER_SIZE];
100+
volatile uint8_t i2cTxRxBufferSize;
100101
};
101102

102103
///@brief I2C state

0 commit comments

Comments
 (0)