mirror of https://github.com/ARMmbed/mbed-os.git
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 familiespull/3238/head
parent
ec95aa5701
commit
a50dc77c60
|
@ -95,6 +95,7 @@ struct i2c_s {
|
||||||
PinName scl;
|
PinName scl;
|
||||||
IRQn_Type event_i2cIRQ;
|
IRQn_Type event_i2cIRQ;
|
||||||
IRQn_Type error_i2cIRQ;
|
IRQn_Type error_i2cIRQ;
|
||||||
|
uint8_t XferOperation;
|
||||||
volatile uint8_t event;
|
volatile uint8_t event;
|
||||||
#if DEVICE_I2CSLAVE
|
#if DEVICE_I2CSLAVE
|
||||||
uint8_t slave;
|
uint8_t slave;
|
||||||
|
@ -105,7 +106,6 @@ struct i2c_s {
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
uint8_t stop;
|
uint8_t stop;
|
||||||
uint8_t available_events;
|
uint8_t available_events;
|
||||||
uint8_t XferOperation;
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -37,11 +37,6 @@
|
||||||
#include "pinmap.h"
|
#include "pinmap.h"
|
||||||
#include "PeripheralPins.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.
|
/* Timeout values are based on core clock and I2C clock.
|
||||||
The BYTE_TIMEOUT is computed as twice the number of cycles it would
|
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.
|
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;
|
obj_s->pending_slave_rx_maxter_tx = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
// I2C Xfer operation init
|
// I2C Xfer operation init
|
||||||
|
obj_s->event = 0;
|
||||||
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Activate default IRQ handlers for sync mode
|
/* Activate default IRQ handlers for sync mode
|
||||||
* which would be overwritten in async 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 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);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
I2C_HandleTypeDef *handle = &(obj_s->handle);
|
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
|
obj_s->event = 0;
|
||||||
timeout = FLAG_TIMEOUT;
|
ret = HAL_I2C_Master_Sequential_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
|
||||||
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
|
|
||||||
timeout--;
|
if(ret == HAL_OK) {
|
||||||
if (timeout == 0) {
|
timeout = BYTE_TIMEOUT_US * length;
|
||||||
return -1;
|
/* 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);
|
return count;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop) {
|
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);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
I2C_HandleTypeDef *handle = &(obj_s->handle);
|
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)) {
|
||||||
// Wait until SB flag is set
|
if (stop)
|
||||||
timeout = FLAG_TIMEOUT;
|
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
||||||
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_SB) == RESET) {
|
else
|
||||||
timeout--;
|
obj_s->XferOperation = I2C_FIRST_FRAME;
|
||||||
if (timeout == 0) {
|
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
|
||||||
return -1;
|
(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
|
ret = HAL_I2C_Master_Sequential_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
|
||||||
timeout = FLAG_TIMEOUT;
|
|
||||||
while (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_ADDR) == RESET) {
|
if(ret == HAL_OK) {
|
||||||
timeout--;
|
timeout = BYTE_TIMEOUT_US * length;
|
||||||
if (timeout == 0) {
|
/* transfer started : wait completion or timeout */
|
||||||
return -1;
|
while(!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
|
||||||
|
wait_us(1);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
__HAL_I2C_CLEAR_ADDRFLAG(handle);
|
|
||||||
|
|
||||||
for (count = 0; count < length; count++) {
|
if((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
|
||||||
if (i2c_byte_write(obj, data[count]) != 1) {
|
/* re-init IP to try and get back in a working state */
|
||||||
i2c_stop(obj);
|
i2c_init(obj, obj_s->sda, obj_s->scl);
|
||||||
return -1;
|
} else {
|
||||||
}
|
count = length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not repeated start, send stop.
|
|
||||||
if (stop) {
|
|
||||||
i2c_stop(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -673,26 +655,25 @@ int i2c_slave_write(i2c_t *obj, const char *data, int length) {
|
||||||
|
|
||||||
#endif // DEVICE_I2CSLAVE
|
#endif // DEVICE_I2CSLAVE
|
||||||
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
|
|
||||||
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
|
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c){
|
||||||
/* Get object ptr based on handler ptr */
|
/* Get object ptr based on handler ptr */
|
||||||
i2c_t *obj = get_i2c_obj(hi2c);
|
i2c_t *obj = get_i2c_obj(hi2c);
|
||||||
struct i2c_s *obj_s = I2C_S(obj);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
|
|
||||||
|
#if DEVICE_I2C_ASYNCH
|
||||||
/* Handle potential Tx/Rx use case */
|
/* Handle potential Tx/Rx use case */
|
||||||
if ((obj->tx_buff.length) && (obj->rx_buff.length)) {
|
if ((obj->tx_buff.length) && (obj->rx_buff.length)) {
|
||||||
|
if (obj_s->stop) {
|
||||||
if (obj_s->stop) {
|
|
||||||
obj_s->XferOperation = I2C_LAST_FRAME;
|
obj_s->XferOperation = I2C_LAST_FRAME;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
obj_s->XferOperation = I2C_NEXT_FRAME;
|
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);
|
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 */
|
/* Set event flag */
|
||||||
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
|
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
|
||||||
}
|
}
|
||||||
|
@ -720,6 +701,7 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c){
|
||||||
obj_s->event = I2C_EVENT_ERROR;
|
obj_s->event = I2C_EVENT_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEVICE_I2C_ASYNCH
|
||||||
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c){
|
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c){
|
||||||
/* Get object ptr based on handler ptr */
|
/* Get object ptr based on handler ptr */
|
||||||
i2c_t *obj = get_i2c_obj(hi2c);
|
i2c_t *obj = get_i2c_obj(hi2c);
|
||||||
|
|
Loading…
Reference in New Issue