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
pull/3238/head
Laurent MEUNIER 2016-10-20 13:43:52 +02:00
parent ec95aa5701
commit a50dc77c60
2 changed files with 68 additions and 86 deletions

View File

@ -95,6 +95,7 @@ struct i2c_s {
PinName scl;
IRQn_Type event_i2cIRQ;
IRQn_Type error_i2cIRQ;
uint8_t XferOperation;
volatile uint8_t event;
#if DEVICE_I2CSLAVE
uint8_t slave;
@ -105,7 +106,6 @@ struct i2c_s {
uint32_t address;
uint8_t stop;
uint8_t available_events;
uint8_t XferOperation;
#endif
};

View File

@ -37,11 +37,6 @@
#include "pinmap.h"
#include "PeripheralPins.h"
/* Timeout values for flags and events waiting loops. These timeouts are
not based on accurate values, they just guarantee that the application will
not remain stuck if the I2C communication is corrupted. */
#define FLAG_TIMEOUT ((int)0x1000)
#define LONG_TIMEOUT ((int)0x8000)
/* Timeout values are based on core clock and I2C clock.
The BYTE_TIMEOUT is computed as twice the number of cycles it would
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) {
obj_s->pending_slave_rx_maxter_tx = 0;
#endif
#if DEVICE_I2C_ASYNCH
// I2C Xfer operation init
obj_s->event = 0;
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
#endif
/* Activate default IRQ handlers for sync mode
* which would be overwritten in async mode
@ -354,95 +348,83 @@ inline int i2c_stop(i2c_t *obj) {
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
int timeout;
int count;
int value;
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
int count = 0, ret = 0;
uint32_t timeout = 0;
i2c_start(obj);
if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) ||
(obj_s->XferOperation == I2C_LAST_FRAME)) {
if (stop)
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
else
obj_s->XferOperation = I2C_FIRST_FRAME;
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
(obj_s->XferOperation == I2C_NEXT_FRAME)) {
if (stop)
obj_s->XferOperation = I2C_LAST_FRAME;
else
obj_s->XferOperation = I2C_NEXT_FRAME;
}
// Wait until SB flag is set
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
timeout--;
if (timeout == 0) {
return -1;
obj_s->event = 0;
ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
if(ret == HAL_OK) {
timeout = BYTE_TIMEOUT_US * length;
/* transfer started : wait completion or timeout */
while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
wait_us(1);
}
if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
/* re-init IP to try and get back in a working state */
i2c_init(obj, obj_s->sda, obj_s->scl);
} else {
count = length;
}
}
handle->Instance->DR = __HAL_I2C_7BIT_ADD_READ(address);
// Wait address is acknowledged
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
timeout--;
if (timeout == 0) {
return -1;
}
}
__HAL_I2C_CLEAR_ADDRFLAG(handle);
// Read all bytes except last one
for (count = 0; count < (length - 1); count++) {
value = i2c_byte_read(obj, 0);
data[count] = (char)value;
}
// If not repeated start, send stop.
// Warning: must be done BEFORE the data is read.
if (stop) {
i2c_stop(obj);
}
// Read the last byte
value = i2c_byte_read(obj, 1);
data[count] = (char)value;
return length;
return count;
}
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
int timeout;
int count;
struct i2c_s *obj_s = I2C_S(obj);
I2C_HandleTypeDef *handle = &(obj_s->handle);
int count = 0, ret = 0;
uint32_t timeout = 0;
i2c_start(obj);
// Wait until SB flag is set
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
timeout--;
if (timeout == 0) {
return -1;
}
if ((obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) ||
(obj_s->XferOperation == I2C_LAST_FRAME)) {
if (stop)
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
else
obj_s->XferOperation = I2C_FIRST_FRAME;
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
(obj_s->XferOperation == I2C_NEXT_FRAME)) {
if (stop)
obj_s->XferOperation = I2C_LAST_FRAME;
else
obj_s->XferOperation = I2C_NEXT_FRAME;
}
handle->Instance->DR = __HAL_I2C_7BIT_ADD_WRITE(address);
obj_s->event = 0;
// Wait address is acknowledged
timeout = FLAG_TIMEOUT;
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
timeout--;
if (timeout == 0) {
return -1;
ret = HAL_I2C_Master_Sequential_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
if(ret == HAL_OK) {
timeout = BYTE_TIMEOUT_US * length;
/* transfer started : wait completion or timeout */
while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
wait_us(1);
}
}
__HAL_I2C_CLEAR_ADDRFLAG(handle);
for (count = 0; count < length; count++) {
if (i2c_byte_write(obj, data[count]) != 1) {
i2c_stop(obj);
return -1;
}
}
// If not repeated start, send stop.
if (stop) {
i2c_stop(obj);
if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
/* re-init IP to try and get back in a working state */
i2c_init(obj, obj_s->sda, obj_s->scl);
} else {
count = length;
}
}
return count;
@ -673,26 +655,25 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) {
#endif // DEVICE_I2CSLAVE
#if DEVICE_I2C_ASYNCH
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
/* Get object ptr based on handler ptr */
i2c_t *obj = get_i2c_obj(hi2c);
struct i2c_s *obj_s = I2C_S(obj);
#if DEVICE_I2C_ASYNCH
/* Handle potential Tx/Rx use case */
if ((obj->tx_buff.length) && (obj->rx_buff.length)) {
if (obj_s->stop) {
if (obj_s->stop) {
obj_s->XferOperation = I2C_LAST_FRAME;
}
else {
} else {
obj_s->XferOperation = I2C_NEXT_FRAME;
}
HAL_I2C_Master_Sequential_Receive_IT(hi2c, obj_s->address, (uint8_t*)obj->rx_buff.buffer , obj->rx_buff.length, obj_s->XferOperation);
}
else {
else
#endif
{
/* Set event flag */
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
}
@ -720,6 +701,7 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c){
obj_s->event = I2C_EVENT_ERROR;
}
#if DEVICE_I2C_ASYNCH
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c){
/* Get object ptr based on handler ptr */
i2c_t *obj = get_i2c_obj(hi2c);