Skip to content

Commit 79504a6

Browse files
committed
STM32: I2C: Change the slave API implementation to use ITs
With this new implementation, the slave use the Interrupt to be notified of a request from master, instead of accessing to registers continuously. This has 2 main advantages: - this shall improve performances overall and allows for sleep time in the future - this also removes some direct registers access from this layer of code and makes it more generic among families
1 parent d71537b commit 79504a6

File tree

2 files changed

+78
-122
lines changed

2 files changed

+78
-122
lines changed

targets/TARGET_STM/TARGET_STM32F4/common_objects.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,14 @@ struct i2c_s {
9393
uint8_t index;
9494
IRQn_Type event_i2cIRQ;
9595
IRQn_Type error_i2cIRQ;
96+
volatile uint8_t event;
97+
#if DEVICE_I2CSLAVE
9698
uint8_t slave;
99+
volatile uint8_t pending_slave_tx_master_rx;
100+
volatile uint8_t pending_slave_rx_maxter_tx;
101+
#endif
97102
#if DEVICE_I2C_ASYNCH
98103
uint32_t address;
99-
uint8_t event;
100104
uint8_t stop;
101105
uint8_t available_events;
102106
uint8_t XferOperation;

targets/TARGET_STM/TARGET_STM32F4/i2c_api.c

Lines changed: 73 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,19 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
241241
#if DEVICE_I2CSLAVE
242242
// I2C master by default
243243
obj_s->slave = 0;
244+
obj_s->pending_slave_tx_master_rx = 0;
245+
obj_s->pending_slave_rx_maxter_tx = 0;
244246
#endif
245247

246248
#if DEVICE_I2C_ASYNCH
247249
// I2C Xfer operation init
248250
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
249251
#endif
252+
253+
/* Activate default IRQ handlers for sync mode
254+
* which would be overwritten in async mode
255+
*/
256+
i2c_irq_set(obj, 1);
250257
}
251258

252259
void i2c_frequency(i2c_t *obj, int hz)
@@ -273,12 +280,6 @@ void i2c_frequency(i2c_t *obj, int hz)
273280
handle->Init.OwnAddress2 = 0;
274281
HAL_I2C_Init(handle);
275282

276-
#if DEVICE_I2CSLAVE
277-
if (obj_s->slave) {
278-
/* Enable Address Acknowledge */
279-
handle->Instance->CR1 |= I2C_CR1_ACK;
280-
}
281-
#endif
282283
}
283284

284285
i2c_t *get_i2c_obj(I2C_HandleTypeDef *hi2c){
@@ -529,25 +530,25 @@ void i2c_reset(i2c_t *obj) {
529530
void i2c_slave_address(i2c_t *obj, int idx, uint32_t address, uint32_t mask) {
530531
struct i2c_s *obj_s = I2C_S(obj);
531532
I2C_HandleTypeDef *handle = &(obj_s->handle);
532-
I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
533533

534534
// I2C configuration
535535
handle->Init.OwnAddress1 = address;
536536
HAL_I2C_Init(handle);
537+
538+
HAL_I2C_EnableListen_IT(handle);
537539
}
538540

539541
void i2c_slave_mode(i2c_t *obj, int enable_slave) {
540542

541543
struct i2c_s *obj_s = I2C_S(obj);
542-
I2C_TypeDef *i2c = (I2C_TypeDef *)obj_s->i2c;
544+
I2C_HandleTypeDef *handle = &(obj_s->handle);
543545

544546
if (enable_slave) {
545547
obj_s->slave = 1;
546-
547-
/* Enable Address Acknowledge */
548-
i2c->CR1 |= I2C_CR1_ACK;
548+
HAL_I2C_EnableListen_IT(handle);
549549
} else {
550550
obj_s->slave = 0;
551+
HAL_I2C_DisableListen_IT(handle);
551552
}
552553
}
553554

@@ -557,145 +558,96 @@ void i2c_slave_mode(i2c_t *obj, int enable_slave) {
557558
#define WriteGeneral 2 // the master is writing to all slave
558559
#define WriteAddressed 3 // the master is writing to this slave (slave = receiver)
559560

560-
int i2c_slave_receive(i2c_t *obj) {
561561

562+
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode) {
563+
/* Get object ptr based on handler ptr */
564+
i2c_t *obj = get_i2c_obj(hi2c);
562565
struct i2c_s *obj_s = I2C_S(obj);
563-
I2C_HandleTypeDef *handle = &(obj_s->handle);
564-
565-
int retValue = NoData;
566566

567-
/* Reading BUSY flag before ADDR flag could clear ADDR */
568-
int addr = __HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR);
569-
570-
if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == 1) {
571-
if (addr == 1) {
572-
if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TRA) == 1) {
573-
retValue = ReadAddressed;
574-
} else {
575-
retValue = WriteAddressed;
576-
}
577-
__HAL_I2C_CLEAR_ADDRFLAG(handle);
578-
}
567+
/* Transfer direction in HAL is from Master point of view */
568+
if(TransferDirection == I2C_DIRECTION_RECEIVE) {
569+
obj_s->pending_slave_tx_master_rx = 1;
579570
}
580571

581-
return (retValue);
572+
if(TransferDirection == I2C_DIRECTION_TRANSMIT) {
573+
obj_s->pending_slave_rx_maxter_tx = 1;
574+
}
582575
}
583576

584-
int i2c_slave_read(i2c_t *obj, char *data, int length) {
585-
577+
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *I2cHandle){
578+
/* Get object ptr based on handler ptr */
579+
i2c_t *obj = get_i2c_obj(I2cHandle);
586580
struct i2c_s *obj_s = I2C_S(obj);
587-
I2C_HandleTypeDef *handle = &(obj_s->handle);
588-
589-
uint32_t Timeout;
590-
int size = 0;
591-
592-
while (length > 0) {
581+
obj_s->pending_slave_tx_master_rx = 0;
582+
}
593583

594-
/* Wait until RXNE flag is set */
595-
// Wait until the byte is received
596-
Timeout = FLAG_TIMEOUT;
597-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_RXNE) == RESET) {
598-
Timeout--;
599-
if (Timeout == 0) {
600-
return -1;
601-
}
602-
}
584+
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *I2cHandle){
585+
/* Get object ptr based on handler ptr */
586+
i2c_t *obj = get_i2c_obj(I2cHandle);
587+
struct i2c_s *obj_s = I2C_S(obj);
588+
obj_s->pending_slave_rx_maxter_tx = 0;
589+
}
603590

604-
/* Read data from DR */
605-
(*data++) = handle->Instance->DR;
606-
length--;
607-
size++;
591+
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
592+
{
593+
/* restart listening for master requests */
594+
HAL_I2C_EnableListen_IT(hi2c);
595+
}
608596

609-
if ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == SET) && (length != 0)) {
610-
/* Read data from DR */
611-
(*data++) = handle->Instance->DR;
612-
length--;
613-
size++;
614-
}
615-
}
597+
int i2c_slave_receive(i2c_t *obj) {
616598

617-
/* Wait until STOP flag is set */
618-
Timeout = FLAG_TIMEOUT;
619-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF) == RESET) {
620-
Timeout--;
621-
if (Timeout == 0) {
622-
return -1;
623-
}
624-
}
599+
struct i2c_s *obj_s = I2C_S(obj);
600+
int retValue = NoData;
625601

626-
/* Clear STOP flag */
627-
__HAL_I2C_CLEAR_STOPFLAG(handle);
602+
if(obj_s->pending_slave_rx_maxter_tx) {
603+
retValue = WriteAddressed;
604+
}
628605

629-
/* Wait until BUSY flag is reset */
630-
Timeout = FLAG_TIMEOUT;
631-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == SET) {
632-
Timeout--;
633-
if (Timeout == 0) {
634-
return -1;
635-
}
636-
}
606+
if(obj_s->pending_slave_tx_master_rx) {
607+
retValue = ReadAddressed;
608+
}
637609

638-
return size;
610+
return (retValue);
639611
}
640612

641-
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
642-
643-
uint32_t Timeout;
644-
int size = 0;
613+
int i2c_slave_read(i2c_t *obj, char *data, int length) {
645614
struct i2c_s *obj_s = I2C_S(obj);
646615
I2C_HandleTypeDef *handle = &(obj_s->handle);
616+
int count = 0;
617+
int ret = 0;
647618

648-
while (length > 0) {
649-
/* Wait until TXE flag is set */
650-
Timeout = FLAG_TIMEOUT;
651-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE) == RESET) {
652-
Timeout--;
653-
if (Timeout == 0) {
654-
return -1;
655-
}
656-
}
657-
658-
/* Write data to DR */
659-
handle->Instance->DR = (*data++);
660-
length--;
661-
size++;
619+
/* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
620+
ret = HAL_I2C_Slave_Sequential_Receive_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
662621

663-
if ((__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BTF) == SET) && (length != 0)) {
664-
/* Write data to DR */
665-
handle->Instance->DR = (*data++);
666-
length--;
667-
size++;
668-
}
622+
if(ret != HAL_OK) {
623+
count = 0;
624+
} else {
625+
count = length;
669626
}
670627

671-
/* Wait until AF flag is set */
672-
Timeout = FLAG_TIMEOUT;
673-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_AF) == RESET) {
674-
Timeout--;
675-
if (Timeout == 0) {
676-
return -1;
677-
}
678-
}
628+
while(obj_s->pending_slave_rx_maxter_tx);
679629

680-
/* Clear AF flag */
681-
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_AF);
630+
return count;
631+
}
682632

633+
int i2c_slave_write(i2c_t *obj, const char *data, int length) {
634+
struct i2c_s *obj_s = I2C_S(obj);
635+
I2C_HandleTypeDef *handle = &(obj_s->handle);
636+
int count = 0;
637+
int ret = 0;
683638

684-
/* Wait until BUSY flag is reset */
685-
Timeout = FLAG_TIMEOUT;
686-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_BUSY) == SET) {
687-
Timeout--;
688-
if (Timeout == 0) {
689-
return -1;
690-
}
691-
}
639+
/* Always use I2C_NEXT_FRAME as slave will just adapt to master requests */
640+
ret = HAL_I2C_Slave_Sequential_Transmit_IT(handle, (uint8_t *) data, length, I2C_NEXT_FRAME);
692641

693-
handle->State = HAL_I2C_STATE_READY;
642+
if(ret != HAL_OK) {
643+
count = 0;
644+
} else {
645+
count = length;
646+
}
694647

695-
/* Process Unlocked */
696-
__HAL_UNLOCK(handle);
648+
while(obj_s->pending_slave_tx_master_rx);
697649

698-
return size;
650+
return count;
699651
}
700652

701653
#endif // DEVICE_I2CSLAVE

0 commit comments

Comments
 (0)