Skip to content

Commit a50dc77

Browse files
committed
STM32: I2C: Change the master sync implementation to use ITs
With this new implementation, as in slave implementaiton, we use the interrupts 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 ec95aa5 commit a50dc77

File tree

2 files changed

+64
-82
lines changed

2 files changed

+64
-82
lines changed

targets/TARGET_STM/TARGET_STM32F4/common_objects.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct i2c_s {
9595
PinName scl;
9696
IRQn_Type event_i2cIRQ;
9797
IRQn_Type error_i2cIRQ;
98+
uint8_t XferOperation;
9899
volatile uint8_t event;
99100
#if DEVICE_I2CSLAVE
100101
uint8_t slave;
@@ -105,7 +106,6 @@ struct i2c_s {
105106
uint32_t address;
106107
uint8_t stop;
107108
uint8_t available_events;
108-
uint8_t XferOperation;
109109
#endif
110110
};
111111

targets/TARGET_STM/TARGET_STM32F4/i2c_api.c

Lines changed: 63 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,6 @@
3737
#include "pinmap.h"
3838
#include "PeripheralPins.h"
3939

40-
/* Timeout values for flags and events waiting loops. These timeouts are
41-
not based on accurate values, they just guarantee that the application will
42-
not remain stuck if the I2C communication is corrupted. */
43-
#define FLAG_TIMEOUT ((int)0x1000)
44-
#define LONG_TIMEOUT ((int)0x8000)
4540
/* Timeout values are based on core clock and I2C clock.
4641
The BYTE_TIMEOUT is computed as twice the number of cycles it would
4742
take to send 10 bits over I2C. Most Flags should take less than that.
@@ -260,10 +255,9 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl) {
260255
obj_s->pending_slave_rx_maxter_tx = 0;
261256
#endif
262257

263-
#if DEVICE_I2C_ASYNCH
264258
// I2C Xfer operation init
259+
obj_s->event = 0;
265260
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
266-
#endif
267261

268262
/* Activate default IRQ handlers for sync mode
269263
* which would be overwritten in async mode
@@ -354,95 +348,83 @@ inline int i2c_stop(i2c_t *obj) {
354348
}
355349

356350
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
357-
358-
int timeout;
359-
int count;
360-
int value;
361351
struct i2c_s *obj_s = I2C_S(obj);
362352
I2C_HandleTypeDef *handle = &(obj_s->handle);
353+
int count = 0, ret = 0;
354+
uint32_t timeout = 0;
363355

364-
i2c_start(obj);
365-
366-
// Wait until SB flag is set
367-
timeout = FLAG_TIMEOUT;
368-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
369-
timeout--;
370-
if (timeout == 0) {
371-
return -1;
372-
}
356+
if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) ||
357+
(obj_s->XferOperation == I2C_LAST_FRAME)) {
358+
if (stop)
359+
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
360+
else
361+
obj_s->XferOperation = I2C_FIRST_FRAME;
362+
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
363+
(obj_s->XferOperation == I2C_NEXT_FRAME)) {
364+
if (stop)
365+
obj_s->XferOperation = I2C_LAST_FRAME;
366+
else
367+
obj_s->XferOperation = I2C_NEXT_FRAME;
373368
}
374369

375-
handle->Instance->DR = __HAL_I2C_7BIT_ADD_READ(address);
370+
obj_s->event = 0;
371+
ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
376372

377-
// Wait address is acknowledged
378-
timeout = FLAG_TIMEOUT;
379-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
380-
timeout--;
381-
if (timeout == 0) {
382-
return -1;
373+
if(ret == HAL_OK) {
374+
timeout = BYTE_TIMEOUT_US * length;
375+
/* transfer started : wait completion or timeout */
376+
while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
377+
wait_us(1);
383378
}
384-
}
385-
__HAL_I2C_CLEAR_ADDRFLAG(handle);
386-
387-
// Read all bytes except last one
388-
for (count = 0; count < (length - 1); count++) {
389-
value = i2c_byte_read(obj, 0);
390-
data[count] = (char)value;
391-
}
392379

393-
// If not repeated start, send stop.
394-
// Warning: must be done BEFORE the data is read.
395-
if (stop) {
396-
i2c_stop(obj);
380+
if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
381+
/* re-init IP to try and get back in a working state */
382+
i2c_init(obj, obj_s->sda, obj_s->scl);
383+
} else {
384+
count = length;
385+
}
397386
}
398387

399-
// Read the last byte
400-
value = i2c_byte_read(obj, 1);
401-
data[count] = (char)value;
402-
403-
return length;
388+
return count;
404389
}
405390

406391
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
407-
408-
int timeout;
409-
int count;
410392
struct i2c_s *obj_s = I2C_S(obj);
411393
I2C_HandleTypeDef *handle = &(obj_s->handle);
394+
int count = 0, ret = 0;
395+
uint32_t timeout = 0;
412396

413-
i2c_start(obj);
414-
415-
// Wait until SB flag is set
416-
timeout = FLAG_TIMEOUT;
417-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
418-
timeout--;
419-
if (timeout == 0) {
420-
return -1;
421-
}
397+
if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) ||
398+
(obj_s->XferOperation == I2C_LAST_FRAME)) {
399+
if (stop)
400+
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
401+
else
402+
obj_s->XferOperation = I2C_FIRST_FRAME;
403+
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
404+
(obj_s->XferOperation == I2C_NEXT_FRAME)) {
405+
if (stop)
406+
obj_s->XferOperation = I2C_LAST_FRAME;
407+
else
408+
obj_s->XferOperation = I2C_NEXT_FRAME;
422409
}
423410

424-
handle->Instance->DR = __HAL_I2C_7BIT_ADD_WRITE(address);
411+
obj_s->event = 0;
425412

426-
// Wait address is acknowledged
427-
timeout = FLAG_TIMEOUT;
428-
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
429-
timeout--;
430-
if (timeout == 0) {
431-
return -1;
432-
}
433-
}
434-
__HAL_I2C_CLEAR_ADDRFLAG(handle);
413+
ret = HAL_I2C_Master_Sequential_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
435414

436-
for (count = 0; count < length; count++) {
437-
if (i2c_byte_write(obj, data[count]) != 1) {
438-
i2c_stop(obj);
439-
return -1;
415+
if(ret == HAL_OK) {
416+
timeout = BYTE_TIMEOUT_US * length;
417+
/* transfer started : wait completion or timeout */
418+
while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
419+
wait_us(1);
440420
}
441-
}
442421

443-
// If not repeated start, send stop.
444-
if (stop) {
445-
i2c_stop(obj);
422+
if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
423+
/* re-init IP to try and get back in a working state */
424+
i2c_init(obj, obj_s->sda, obj_s->scl);
425+
} else {
426+
count = length;
427+
}
446428
}
447429

448430
return count;
@@ -673,26 +655,25 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) {
673655

674656
#endif // DEVICE_I2CSLAVE
675657

676-
#if DEVICE_I2C_ASYNCH
677-
678658
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
679659
/* Get object ptr based on handler ptr */
680660
i2c_t *obj = get_i2c_obj(hi2c);
681661
struct i2c_s *obj_s = I2C_S(obj);
682662

663+
#if DEVICE_I2C_ASYNCH
683664
/* Handle potential Tx/Rx use case */
684665
if ((obj->tx_buff.length) && (obj->rx_buff.length)) {
685-
686-
if (obj_s->stop) {
666+
if (obj_s->stop) {
687667
obj_s->XferOperation = I2C_LAST_FRAME;
688-
}
689-
else {
668+
} else {
690669
obj_s->XferOperation = I2C_NEXT_FRAME;
691670
}
692671

693672
HAL_I2C_Master_Sequential_Receive_IT(hi2c, obj_s->address, (uint8_t*)obj->rx_buff.buffer , obj->rx_buff.length, obj_s->XferOperation);
694673
}
695-
else {
674+
else
675+
#endif
676+
{
696677
/* Set event flag */
697678
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
698679
}
@@ -720,6 +701,7 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c){
720701
obj_s->event = I2C_EVENT_ERROR;
721702
}
722703

704+
#if DEVICE_I2C_ASYNCH
723705
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c){
724706
/* Get object ptr based on handler ptr */
725707
i2c_t *obj = get_i2c_obj(hi2c);

0 commit comments

Comments
 (0)