mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #15350 from mbed-ce/upstreamed/rethink-stm32-i2c-hal
Rethink STM32 I2C v2 HALpull/15357/head
commit
d4df7135a9
|
@ -35,10 +35,36 @@
|
||||||
*
|
*
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that an unspecified error has occurred in the transfer. This usually means
|
||||||
|
* either an internal error in the Mbed MCU's I2C module, or something like an arbitration loss.
|
||||||
|
* Does not indicate a NACK.
|
||||||
|
*/
|
||||||
#define I2C_EVENT_ERROR (1 << 1)
|
#define I2C_EVENT_ERROR (1 << 1)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the slave did not respond to the address byte of the transfer.
|
||||||
|
*/
|
||||||
#define I2C_EVENT_ERROR_NO_SLAVE (1 << 2)
|
#define I2C_EVENT_ERROR_NO_SLAVE (1 << 2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the transfer completed successfully.
|
||||||
|
*/
|
||||||
#define I2C_EVENT_TRANSFER_COMPLETE (1 << 3)
|
#define I2C_EVENT_TRANSFER_COMPLETE (1 << 3)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that a NACK was received after the address byte, but before the requested number of bytes
|
||||||
|
* could be transferred.
|
||||||
|
*
|
||||||
|
* Note: Not every manufacturer HAL is able to make a distinction between this flag and #I2C_EVENT_ERROR_NO_SLAVE.
|
||||||
|
* On a NACK, you might conceivably get one or both of these flags.
|
||||||
|
*/
|
||||||
#define I2C_EVENT_TRANSFER_EARLY_NACK (1 << 4)
|
#define I2C_EVENT_TRANSFER_EARLY_NACK (1 << 4)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this macro to request all possible I2C events.
|
||||||
|
*/
|
||||||
#define I2C_EVENT_ALL (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_COMPLETE | I2C_EVENT_ERROR_NO_SLAVE | I2C_EVENT_TRANSFER_EARLY_NACK)
|
#define I2C_EVENT_ALL (I2C_EVENT_ERROR | I2C_EVENT_TRANSFER_COMPLETE | I2C_EVENT_ERROR_NO_SLAVE | I2C_EVENT_TRANSFER_EARLY_NACK)
|
||||||
|
|
||||||
/**@}*/
|
/**@}*/
|
||||||
|
@ -61,7 +87,8 @@ typedef struct i2c_s i2c_t;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
I2C_ERROR_NO_SLAVE = -1,
|
I2C_ERROR_NO_SLAVE = -1,
|
||||||
I2C_ERROR_BUS_BUSY = -2
|
I2C_ERROR_BUS_BUSY = -2,
|
||||||
|
I2C_ERROR_INVALID_USAGE = -3 ///< Invalid usage of the I2C API, e.g. by mixing single-byte and transactional function calls.
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -229,7 +256,7 @@ int i2c_byte_read(i2c_t *obj, int last);
|
||||||
*
|
*
|
||||||
* @param obj The I2C object
|
* @param obj The I2C object
|
||||||
* @param data Byte to be written
|
* @param data Byte to be written
|
||||||
* @return 0 if NAK was received, 1 if ACK was received, 2 for timeout.
|
* @return 0 if NAK was received, 1 if ACK was received, 2 for timeout, or 3 for other error.
|
||||||
*/
|
*/
|
||||||
int i2c_byte_write(i2c_t *obj, int data);
|
int i2c_byte_write(i2c_t *obj, int data);
|
||||||
|
|
||||||
|
|
|
@ -77,39 +77,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct analogin_s {
|
struct analogin_s {
|
||||||
ADC_HandleTypeDef handle;
|
ADC_HandleTypeDef handle;
|
||||||
PinName pin;
|
PinName pin;
|
||||||
|
|
|
@ -90,41 +90,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
int sda_func;
|
|
||||||
int scl_func;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dac_s {
|
struct dac_s {
|
||||||
DACName dac;
|
DACName dac;
|
||||||
PinName pin;
|
PinName pin;
|
||||||
|
|
|
@ -108,39 +108,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct analogin_s {
|
struct analogin_s {
|
||||||
ADC_HandleTypeDef handle;
|
ADC_HandleTypeDef handle;
|
||||||
PinName pin;
|
PinName pin;
|
||||||
|
|
|
@ -89,41 +89,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
int sda_func;
|
|
||||||
int scl_func;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
|
|
|
@ -88,41 +88,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
int sda_func;
|
|
||||||
int scl_func;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dac_s {
|
struct dac_s {
|
||||||
DACName dac;
|
DACName dac;
|
||||||
PinName pin;
|
PinName pin;
|
||||||
|
|
|
@ -97,39 +97,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct analogin_s {
|
struct analogin_s {
|
||||||
ADC_HandleTypeDef handle;
|
ADC_HandleTypeDef handle;
|
||||||
PinName pin;
|
PinName pin;
|
||||||
|
|
|
@ -91,41 +91,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
int sda_func;
|
|
||||||
int scl_func;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
#if DEVICE_FLASH
|
#if DEVICE_FLASH
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
|
|
|
@ -87,41 +87,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
int sda_func;
|
|
||||||
int scl_func;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
|
|
|
@ -97,39 +97,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
|
|
|
@ -97,39 +97,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
|
|
|
@ -80,39 +80,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
|
|
|
@ -83,39 +83,6 @@ struct serial_s {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
struct i2c_s {
|
|
||||||
/* The 1st 2 members I2CName i2c
|
|
||||||
* and I2C_HandleTypeDef handle should
|
|
||||||
* be kept as the first members of this struct
|
|
||||||
* to ensure i2c_get_obj to work as expected
|
|
||||||
*/
|
|
||||||
I2CName i2c;
|
|
||||||
I2C_HandleTypeDef handle;
|
|
||||||
uint8_t index;
|
|
||||||
int hz;
|
|
||||||
PinName sda;
|
|
||||||
PinName scl;
|
|
||||||
IRQn_Type event_i2cIRQ;
|
|
||||||
IRQn_Type error_i2cIRQ;
|
|
||||||
uint32_t XferOperation;
|
|
||||||
volatile uint8_t event;
|
|
||||||
volatile int pending_start;
|
|
||||||
int current_hz;
|
|
||||||
#if DEVICE_I2CSLAVE
|
|
||||||
uint8_t slave;
|
|
||||||
volatile uint8_t pending_slave_tx_master_rx;
|
|
||||||
volatile uint8_t pending_slave_rx_maxter_tx;
|
|
||||||
uint8_t *slave_rx_buffer;
|
|
||||||
volatile uint16_t slave_rx_buffer_size;
|
|
||||||
volatile uint16_t slave_rx_count;
|
|
||||||
#endif
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
|
||||||
uint32_t address;
|
|
||||||
uint8_t stop;
|
|
||||||
uint8_t available_events;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct flash_s {
|
struct flash_s {
|
||||||
/* nothing to be stored for now */
|
/* nothing to be stored for now */
|
||||||
uint32_t dummy;
|
uint32_t dummy;
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#define DEVICE_ID_LENGTH 24
|
#define DEVICE_ID_LENGTH 24
|
||||||
|
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
#include "stm_i2c_api.h"
|
||||||
|
|
||||||
#if DEVICE_USTICKER
|
#if DEVICE_USTICKER
|
||||||
#include "us_ticker_defines.h"
|
#include "us_ticker_defines.h"
|
||||||
|
|
|
@ -525,6 +525,9 @@ void i2c_init_internal(i2c_t *obj, const i2c_pinmap_t *pinmap)
|
||||||
|
|
||||||
#ifdef I2C_IP_VERSION_V2
|
#ifdef I2C_IP_VERSION_V2
|
||||||
obj_s->current_hz = obj_s->hz;
|
obj_s->current_hz = obj_s->hz;
|
||||||
|
#else
|
||||||
|
// I2C Xfer operation init
|
||||||
|
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if DEVICE_I2CSLAVE
|
#if DEVICE_I2CSLAVE
|
||||||
|
@ -534,12 +537,8 @@ void i2c_init_internal(i2c_t *obj, const i2c_pinmap_t *pinmap)
|
||||||
obj_s->pending_slave_rx_maxter_tx = 0;
|
obj_s->pending_slave_rx_maxter_tx = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// I2C Xfer operation init
|
|
||||||
obj_s->event = 0;
|
obj_s->event = 0;
|
||||||
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE);
|
||||||
#ifdef I2C_IP_VERSION_V2
|
|
||||||
obj_s->pending_start = 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_deinit_internal(i2c_t *obj)
|
void i2c_deinit_internal(i2c_t *obj)
|
||||||
|
@ -823,11 +822,14 @@ int i2c_stop(i2c_t *obj)
|
||||||
// Generate the STOP condition
|
// Generate the STOP condition
|
||||||
i2c->CR1 |= I2C_CR1_STOP;
|
i2c->CR1 |= I2C_CR1_STOP;
|
||||||
|
|
||||||
/* In case of mixed usage of the APIs (unitary + SYNC)
|
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
||||||
* re-init HAL state
|
|
||||||
*/
|
// Wait until condition is generated
|
||||||
if (obj_s->XferOperation != I2C_FIRST_AND_LAST_FRAME) {
|
int timeout = FLAG_TIMEOUT;
|
||||||
i2c_init_internal(obj, NULL);
|
while (__HAL_I2C_GET_FLAG(&obj_s->handle, I2C_FLAG_BUSY)) {
|
||||||
|
if ((timeout--) == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -887,11 +889,75 @@ int i2c_byte_write(i2c_t *obj, int data)
|
||||||
#endif //I2C_IP_VERSION_V1
|
#endif //I2C_IP_VERSION_V1
|
||||||
#ifdef I2C_IP_VERSION_V2
|
#ifdef I2C_IP_VERSION_V2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the given state is a state where we can start a new I2C transaction with the
|
||||||
|
* STM32 HAL.
|
||||||
|
*/
|
||||||
|
inline bool i2c_is_ready_for_transaction_start(stm_i2c_state state)
|
||||||
|
{
|
||||||
|
// Note: We can safely send a transaction start in the middle of any single byte operation; this creates a
|
||||||
|
// repeated start.
|
||||||
|
|
||||||
|
return state == STM_I2C_IDLE || STM_I2C_PENDING_START == state
|
||||||
|
|| state == STM_I2C_SB_READ_IN_PROGRESS || state == STM_I2C_SB_WRITE_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If currently in a single-byte operation, special reset logic is needed to get the peripheral
|
||||||
|
* ready to repeated-start another transaction. This function performs those steps if they are needed.
|
||||||
|
*/
|
||||||
|
static void prep_for_restart_if_needed(struct i2c_s *obj_s) {
|
||||||
|
if (obj_s->state == STM_I2C_SB_READ_IN_PROGRESS || obj_s->state == STM_I2C_SB_WRITE_IN_PROGRESS) {
|
||||||
|
// Force an end to the current operation by setting bytes remaining to 0 and RELOAD to false.
|
||||||
|
// Without this, the I2C peripheral seems to refuse to send another start condition as it
|
||||||
|
// thinks the previous operation is still running.
|
||||||
|
uint32_t cr2_val = obj_s->handle.Instance->CR2;
|
||||||
|
cr2_val &= ~(I2C_CR2_RELOAD_Msk);
|
||||||
|
cr2_val &= ~(I2C_CR2_NBYTES_Msk);
|
||||||
|
obj_s->handle.Instance->CR2 = cr2_val;
|
||||||
|
|
||||||
|
// Wait until the hardware ends the transfer and sets the transfer complete flag.
|
||||||
|
int timeout = FLAG_TIMEOUT;
|
||||||
|
while (!__HAL_I2C_GET_FLAG(&obj_s->handle, I2C_FLAG_TC)) {
|
||||||
|
if ((timeout--) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate the STM32 HAL "xferOptions" value based on the current state and whether we are going to send a
|
||||||
|
* STOP at the end of the current transaction.
|
||||||
|
*/
|
||||||
|
static uint32_t get_hal_xfer_options(struct i2c_s *obj_s, bool stop) {
|
||||||
|
if (obj_s->state == STM_I2C_SB_READ_IN_PROGRESS || obj_s->state == STM_I2C_SB_WRITE_IN_PROGRESS) {
|
||||||
|
if(stop) {
|
||||||
|
// Generate restart condition and stop at end
|
||||||
|
return I2C_OTHER_AND_LAST_FRAME;
|
||||||
|
} else {
|
||||||
|
// Generate restart condition but don't send STOP
|
||||||
|
return I2C_OTHER_FRAME;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(stop) {
|
||||||
|
// Generate start condition and stop at end
|
||||||
|
return I2C_FIRST_AND_LAST_FRAME;
|
||||||
|
} else {
|
||||||
|
return I2C_LAST_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int i2c_start(i2c_t *obj)
|
int i2c_start(i2c_t *obj)
|
||||||
{
|
{
|
||||||
struct i2c_s *obj_s = I2C_S(obj);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
/* This I2C IP doesn't */
|
|
||||||
obj_s->pending_start = 1;
|
prep_for_restart_if_needed(obj_s);
|
||||||
|
|
||||||
|
// The I2C peripheral in this chip cannot issue a start condition without also sending the first address byte.
|
||||||
|
// So, this function just has to set a flag, and we will send the actual start condition later.
|
||||||
|
obj_s->state = STM_I2C_PENDING_START;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -899,7 +965,7 @@ int i2c_stop(i2c_t *obj)
|
||||||
{
|
{
|
||||||
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 timeout = FLAG_TIMEOUT;
|
int timeout;
|
||||||
#if DEVICE_I2CSLAVE
|
#if DEVICE_I2CSLAVE
|
||||||
if (obj_s->slave) {
|
if (obj_s->slave) {
|
||||||
/* re-init slave when stop is requested */
|
/* re-init slave when stop is requested */
|
||||||
|
@ -908,20 +974,51 @@ int i2c_stop(i2c_t *obj)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ensure the transmission is started before sending a stop
|
if(obj_s->state == STM_I2C_IDLE)
|
||||||
if ((handle->Instance->CR2 & (uint32_t)I2C_CR2_RD_WRN) == 0) {
|
{
|
||||||
timeout = FLAG_TIMEOUT;
|
// We get here if we got a NACK earlier and the operation aborted itself.
|
||||||
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXIS)) {
|
// The hardware will generate a stop condition, so wait for that to happen.
|
||||||
|
timeout = BYTE_TIMEOUT/8;
|
||||||
|
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF)) {
|
||||||
if ((timeout--) == 0) {
|
if ((timeout--) == 0) {
|
||||||
return I2C_ERROR_BUS_BUSY;
|
DEBUG_PRINTF("timeout in i2c_byte_write waiting for I2C_FLAG_STOPF\r\n");
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_STOPF);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else if(!(obj_s->state == STM_I2C_SB_READ_IN_PROGRESS || obj_s->state == STM_I2C_SB_WRITE_IN_PROGRESS))
|
||||||
|
{
|
||||||
|
// Cannot use single-byte functions while a transaction is in progress.
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the STOP condition
|
// Generate the STOP condition
|
||||||
handle->Instance->CR2 = I2C_CR2_STOP;
|
handle->Instance->CR2 = I2C_CR2_STOP;
|
||||||
|
|
||||||
timeout = FLAG_TIMEOUT;
|
// Unfortunately, the STM32 I2C peripheral seems to be unable to generate a STOP condition immediately after the address
|
||||||
|
// byte. Simply setting CR2 to STOP (the normal procedure if at least one data byte has been sent) does not work
|
||||||
|
// -- the peripheral will hang forever and leave the bus in a bad state. STMicro seems to passively acknowledge
|
||||||
|
// this in their code (via their I2C_Flush_TXDR() HAL function).
|
||||||
|
// As the lesser of two evils, we will have to write out another byte here so that we can recover the bus,
|
||||||
|
// even though that might cause unintended behavior in some cases.
|
||||||
|
// Note: It *is* possible to do a zero-data-byte I2C transaction on these devices, but you have to use
|
||||||
|
// the transaction API, not the single-byte one.
|
||||||
|
if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXIS) != RESET)
|
||||||
|
{
|
||||||
|
// If TXIS is set, that means we have just sent the address byte and not any data bytes yet.
|
||||||
|
handle->Instance->TXDR = 0x00U;
|
||||||
|
/* Flush TX register if not empty */
|
||||||
|
if (__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE) == RESET)
|
||||||
|
{
|
||||||
|
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_TXE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timeout = BYTE_TIMEOUT;
|
||||||
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF)) {
|
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_STOPF)) {
|
||||||
if ((timeout--) == 0) {
|
if ((timeout--) == 0) {
|
||||||
return I2C_ERROR_BUS_BUSY;
|
return I2C_ERROR_BUS_BUSY;
|
||||||
|
@ -931,7 +1028,7 @@ int i2c_stop(i2c_t *obj)
|
||||||
/* Clear STOP Flag */
|
/* Clear STOP Flag */
|
||||||
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_STOPF);
|
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_STOPF);
|
||||||
|
|
||||||
/* Erase slave address, this wiil be used as a marker
|
/* Erase slave address, this will be used as a marker
|
||||||
* to know when we need to prepare next start */
|
* to know when we need to prepare next start */
|
||||||
handle->Instance->CR2 &= ~I2C_CR2_SADD;
|
handle->Instance->CR2 &= ~I2C_CR2_SADD;
|
||||||
|
|
||||||
|
@ -941,11 +1038,8 @@ int i2c_stop(i2c_t *obj)
|
||||||
*/
|
*/
|
||||||
i2c_sw_reset(obj);
|
i2c_sw_reset(obj);
|
||||||
|
|
||||||
/* In case of mixed usage of the APIs (unitary + SYNC)
|
// This function restores the I2C to IDLE state.
|
||||||
* re-init HAL state */
|
obj_s->state = STM_I2C_IDLE;
|
||||||
if (obj_s->XferOperation != I2C_FIRST_AND_LAST_FRAME) {
|
|
||||||
i2c_init_internal(obj, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -954,7 +1048,6 @@ int i2c_byte_read(i2c_t *obj, int last)
|
||||||
{
|
{
|
||||||
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 timeout = FLAG_TIMEOUT;
|
|
||||||
uint32_t tmpreg = handle->Instance->CR2;
|
uint32_t tmpreg = handle->Instance->CR2;
|
||||||
char data;
|
char data;
|
||||||
#if DEVICE_I2CSLAVE
|
#if DEVICE_I2CSLAVE
|
||||||
|
@ -962,7 +1055,15 @@ int i2c_byte_read(i2c_t *obj, int last)
|
||||||
return i2c_slave_read(obj, &data, 1);
|
return i2c_slave_read(obj, &data, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(obj_s->state != STM_I2C_SB_READ_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
// Must be in a read operation in order to read!
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Then send data when there's room in the TX fifo */
|
/* Then send data when there's room in the TX fifo */
|
||||||
|
int timeout = FLAG_TIMEOUT;
|
||||||
if ((tmpreg & I2C_CR2_RELOAD) != 0) {
|
if ((tmpreg & I2C_CR2_RELOAD) != 0) {
|
||||||
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
|
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
|
||||||
if ((timeout--) == 0) {
|
if ((timeout--) == 0) {
|
||||||
|
@ -1009,8 +1110,15 @@ int i2c_byte_write(i2c_t *obj, int data)
|
||||||
return i2c_slave_write(obj, (char *) &data, 1);
|
return i2c_slave_write(obj, (char *) &data, 1);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (obj_s->pending_start) {
|
|
||||||
obj_s->pending_start = 0;
|
if(!(obj_s->state == STM_I2C_SB_WRITE_IN_PROGRESS || obj_s->state == STM_I2C_PENDING_START))
|
||||||
|
{
|
||||||
|
// Must either be ready to send address or ready to write data bytes
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj_s->state == STM_I2C_PENDING_START)
|
||||||
|
{
|
||||||
//* First byte after the start is the address */
|
//* First byte after the start is the address */
|
||||||
tmpreg |= (uint32_t)((uint32_t)data & I2C_CR2_SADD);
|
tmpreg |= (uint32_t)((uint32_t)data & I2C_CR2_SADD);
|
||||||
if (data & 0x01) {
|
if (data & 0x01) {
|
||||||
|
@ -1023,24 +1131,34 @@ int i2c_byte_write(i2c_t *obj, int data)
|
||||||
tmpreg &= ~I2C_CR2_RELOAD;
|
tmpreg &= ~I2C_CR2_RELOAD;
|
||||||
/* Disable Autoend */
|
/* Disable Autoend */
|
||||||
tmpreg &= ~I2C_CR2_AUTOEND;
|
tmpreg &= ~I2C_CR2_AUTOEND;
|
||||||
/* Do not set any transfer size for now */
|
/* Set transfer size to 1 */
|
||||||
tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
|
tmpreg |= (I2C_CR2_NBYTES & (1 << I2C_CR2_NBYTES_Pos));
|
||||||
/* Set the prepared configuration */
|
/* Set the prepared configuration */
|
||||||
handle->Instance->CR2 = tmpreg;
|
handle->Instance->CR2 = tmpreg;
|
||||||
} else {
|
|
||||||
/* Set the prepared configuration */
|
|
||||||
tmpreg = handle->Instance->CR2;
|
|
||||||
|
|
||||||
/* Then send data when there's room in the TX fifo */
|
// Wait until we get the result for the address byte.
|
||||||
if ((tmpreg & I2C_CR2_RELOAD) != 0) {
|
// The hardware clears the I2C_CR2_START bit when the start condition has been sent.
|
||||||
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR)) {
|
timeout = BYTE_TIMEOUT;
|
||||||
if ((timeout--) == 0) {
|
while (handle->Instance->CR2 & I2C_CR2_START) {
|
||||||
DEBUG_PRINTF("timeout in i2c_byte_write\r\n");
|
if ((timeout--) == 0) {
|
||||||
return 2;
|
return 2;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Enable reload mode as we don't know how many bytes will eb sent */
|
|
||||||
|
// Set to read or write based on the address
|
||||||
|
obj_s->state = data & 0x1 ? STM_I2C_SB_READ_IN_PROGRESS : STM_I2C_SB_WRITE_IN_PROGRESS;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if(obj_s->state == STM_I2C_SB_READ_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
// Cannot do a write in a read transaction!
|
||||||
|
return 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpreg = handle->Instance->CR2;
|
||||||
|
|
||||||
|
/* Enable reload mode as we don't know how many bytes will be sent */
|
||||||
tmpreg |= I2C_CR2_RELOAD;
|
tmpreg |= I2C_CR2_RELOAD;
|
||||||
/* Set transfer size to 1 */
|
/* Set transfer size to 1 */
|
||||||
tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
|
tmpreg |= (I2C_CR2_NBYTES & (1 << 16));
|
||||||
|
@ -1050,11 +1168,32 @@ int i2c_byte_write(i2c_t *obj, int data)
|
||||||
timeout = FLAG_TIMEOUT;
|
timeout = FLAG_TIMEOUT;
|
||||||
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE)) {
|
while (!__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TXE)) {
|
||||||
if ((timeout--) == 0) {
|
if ((timeout--) == 0) {
|
||||||
|
DEBUG_PRINTF("timeout in i2c_byte_write waiting for I2C_FLAG_TXE\r\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Write byte */
|
/* Write byte */
|
||||||
handle->Instance->TXDR = data;
|
handle->Instance->TXDR = data;
|
||||||
|
|
||||||
|
// Wait until we get the result for that byte
|
||||||
|
// Since we set NBYTES to 1 and RELOAD to 1, the Transfer Complete Reload flag will set when this byte has transferred.
|
||||||
|
// Since we set AUTOEND to 0, the MCU will pause the SCL clock from then until we write another byte.
|
||||||
|
timeout = BYTE_TIMEOUT;
|
||||||
|
while (!(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_TCR) || __HAL_I2C_GET_FLAG(handle, I2C_FLAG_AF))) {
|
||||||
|
if ((timeout--) == 0) {
|
||||||
|
DEBUG_PRINTF("timeout in i2c_byte_write waiting for byte complete\r\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If I2C_FLAG_AF is set, we got a NACK, and the hardware is currently generating a stop.
|
||||||
|
// Otherwise, we got an ACK.
|
||||||
|
if(__HAL_I2C_GET_FLAG(handle, I2C_FLAG_AF))
|
||||||
|
{
|
||||||
|
__HAL_I2C_CLEAR_FLAG(handle, I2C_FLAG_AF);
|
||||||
|
obj_s->state = STM_I2C_IDLE;
|
||||||
|
return 0; // NACK
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -1068,8 +1207,8 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
|
||||||
{
|
{
|
||||||
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 = I2C_ERROR_BUS_BUSY, ret = 0;
|
int count = I2C_ERROR_BUS_BUSY;
|
||||||
uint32_t timeout = 0;
|
uint32_t xferOptions;
|
||||||
#if defined(I2C_IP_VERSION_V1)
|
#if defined(I2C_IP_VERSION_V1)
|
||||||
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
||||||
uint32_t op1 = I2C_FIRST_AND_LAST_FRAME;
|
uint32_t op1 = I2C_FIRST_AND_LAST_FRAME;
|
||||||
|
@ -1088,17 +1227,17 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
|
||||||
obj_s->XferOperation = I2C_NEXT_FRAME;
|
obj_s->XferOperation = I2C_NEXT_FRAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
xferOptions = obj_s->XferOperation;
|
||||||
#elif defined(I2C_IP_VERSION_V2)
|
#elif defined(I2C_IP_VERSION_V2)
|
||||||
if ((obj_s->XferOperation == I2C_FIRST_FRAME) || (obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) || (obj_s->XferOperation == I2C_LAST_FRAME)) {
|
if(!i2c_is_ready_for_transaction_start(obj_s->state))
|
||||||
if (stop) {
|
{
|
||||||
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
// I2C peripheral is not ready to start a new transaction
|
||||||
} else {
|
return I2C_ERROR_INVALID_USAGE;
|
||||||
obj_s->XferOperation = I2C_FIRST_FRAME;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// should not happend
|
|
||||||
error("I2C: abnormal case should not happend");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prep_for_restart_if_needed(obj_s);
|
||||||
|
|
||||||
|
xferOptions = get_hal_xfer_options(obj_s, stop);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj_s->event = 0;
|
obj_s->event = 0;
|
||||||
|
@ -1108,10 +1247,11 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
|
||||||
*/
|
*/
|
||||||
i2c_ev_err_enable(obj, i2c_get_irq_handler(obj));
|
i2c_ev_err_enable(obj, i2c_get_irq_handler(obj));
|
||||||
|
|
||||||
ret = HAL_I2C_Master_Seq_Receive_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
|
int ret = HAL_I2C_Master_Seq_Receive_IT(handle, address, (uint8_t *) data, length, xferOptions);
|
||||||
|
|
||||||
if (ret == HAL_OK) {
|
if (ret == HAL_OK) {
|
||||||
timeout = BYTE_TIMEOUT_US * (length + 1);
|
STM_I2C_SET_STATE(obj_s, STM_I2C_TR_WRITE_IN_PROGRESS);
|
||||||
|
uint32_t timeout = BYTE_TIMEOUT_US * (length + 1);
|
||||||
/* transfer started : wait completion or timeout */
|
/* transfer started : wait completion or timeout */
|
||||||
while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
|
while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
|
||||||
wait_us(1);
|
wait_us(1);
|
||||||
|
@ -1121,13 +1261,28 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
|
||||||
|
|
||||||
if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
|
if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
|
||||||
DEBUG_PRINTF("TIMEOUT or error in i2c_read\r\n");
|
DEBUG_PRINTF("TIMEOUT or error in i2c_read\r\n");
|
||||||
|
|
||||||
|
// Pass up the error code indicating a NACK
|
||||||
|
if(obj_s->event | I2C_EVENT_ERROR_NO_SLAVE)
|
||||||
|
{
|
||||||
|
count = I2C_ERROR_NO_SLAVE;
|
||||||
|
}
|
||||||
|
|
||||||
/* re-init IP to try and get back in a working state */
|
/* re-init IP to try and get back in a working state */
|
||||||
i2c_init_internal(obj, NULL);
|
i2c_init_internal(obj, NULL);
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
count = length;
|
count = length;
|
||||||
|
|
||||||
|
// If we requested repeated start, go into PENDING_START state so the user can call write_byte().
|
||||||
|
// Otherwise, we are now IDLE.
|
||||||
|
STM_I2C_SET_STATE(obj_s, stop ? STM_I2C_IDLE : STM_I2C_PENDING_START);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTF("ERROR in i2c_read:%d\r\n", ret);
|
DEBUG_PRINTF("ERROR in i2c_read:%d\r\n", ret);
|
||||||
|
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -1137,8 +1292,8 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
|
||||||
{
|
{
|
||||||
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 = I2C_ERROR_BUS_BUSY, ret = 0;
|
int count = I2C_ERROR_BUS_BUSY;
|
||||||
uint32_t timeout = 0;
|
uint32_t xferOptions;
|
||||||
|
|
||||||
#if defined(I2C_IP_VERSION_V1)
|
#if defined(I2C_IP_VERSION_V1)
|
||||||
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
||||||
|
@ -1158,27 +1313,29 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
|
||||||
obj_s->XferOperation = I2C_NEXT_FRAME;
|
obj_s->XferOperation = I2C_NEXT_FRAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
xferOptions = obj_s->XferOperation;
|
||||||
#elif defined(I2C_IP_VERSION_V2)
|
#elif defined(I2C_IP_VERSION_V2)
|
||||||
if ((obj_s->XferOperation == I2C_FIRST_FRAME) || (obj_s->XferOperation == I2C_FIRST_AND_LAST_FRAME) || (obj_s->XferOperation == I2C_LAST_FRAME)) {
|
if(!i2c_is_ready_for_transaction_start(obj_s->state))
|
||||||
if (stop) {
|
{
|
||||||
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
// I2C peripheral is not ready to start a new transaction
|
||||||
} else {
|
return I2C_ERROR_INVALID_USAGE;
|
||||||
obj_s->XferOperation = I2C_FIRST_FRAME;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// should not happend
|
|
||||||
error("I2C: abnormal case should not happend");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prep_for_restart_if_needed(obj_s);
|
||||||
|
|
||||||
|
xferOptions = get_hal_xfer_options(obj_s, stop);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
obj_s->event = 0;
|
obj_s->event = 0;
|
||||||
|
|
||||||
i2c_ev_err_enable(obj, i2c_get_irq_handler(obj));
|
i2c_ev_err_enable(obj, i2c_get_irq_handler(obj));
|
||||||
|
|
||||||
ret = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *) data, length, obj_s->XferOperation);
|
int ret = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *) data, length, xferOptions);
|
||||||
|
|
||||||
if (ret == HAL_OK) {
|
if (ret == HAL_OK)
|
||||||
timeout = BYTE_TIMEOUT_US * (length + 1);
|
{
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_TR_WRITE_IN_PROGRESS);
|
||||||
|
uint32_t timeout = BYTE_TIMEOUT_US * (length + 1);
|
||||||
/* transfer started : wait completion or timeout */
|
/* transfer started : wait completion or timeout */
|
||||||
while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
|
while (!(obj_s->event & I2C_EVENT_ALL) && (--timeout != 0)) {
|
||||||
wait_us(1);
|
wait_us(1);
|
||||||
|
@ -1188,13 +1345,27 @@ int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
|
||||||
|
|
||||||
if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
|
if ((timeout == 0) || (obj_s->event != I2C_EVENT_TRANSFER_COMPLETE)) {
|
||||||
DEBUG_PRINTF(" TIMEOUT or error in i2c_write\r\n");
|
DEBUG_PRINTF(" TIMEOUT or error in i2c_write\r\n");
|
||||||
|
|
||||||
|
// Pass up the error code indicating a NACK
|
||||||
|
if(obj_s->event | I2C_EVENT_ERROR_NO_SLAVE)
|
||||||
|
{
|
||||||
|
count = I2C_ERROR_NO_SLAVE;
|
||||||
|
}
|
||||||
|
|
||||||
/* re-init IP to try and get back in a working state */
|
/* re-init IP to try and get back in a working state */
|
||||||
i2c_init_internal(obj, NULL);
|
i2c_init_internal(obj, NULL);
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
count = length;
|
count = length;
|
||||||
|
|
||||||
|
// If we requested repeated start, go into PENDING_START state so the user can call write_byte().
|
||||||
|
// Otherwise, we are now IDLE.
|
||||||
|
STM_I2C_SET_STATE(obj_s, stop ? STM_I2C_IDLE : STM_I2C_PENDING_START);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTF("ERROR in i2c_write\r\n");
|
DEBUG_PRINTF("ERROR in i2c_write\r\n");
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
|
@ -1207,28 +1378,48 @@ void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
|
||||||
struct i2c_s *obj_s = I2C_S(obj);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
|
|
||||||
#if DEVICE_I2C_ASYNCH
|
#if DEVICE_I2C_ASYNCH
|
||||||
/* Handle potential Tx/Rx use case */
|
|
||||||
if ((obj->tx_buff.length) && (obj->rx_buff.length)) {
|
|
||||||
#if defined(I2C_IP_VERSION_V1)
|
#if defined(I2C_IP_VERSION_V1)
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
#elif defined(I2C_IP_VERSION_V2)
|
|
||||||
if (obj_s->stop) {
|
|
||||||
obj_s->XferOperation = I2C_FIRST_AND_LAST_FRAME;
|
|
||||||
} else {
|
|
||||||
obj_s->XferOperation = I2C_FIRST_FRAME;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
HAL_I2C_Master_Seq_Receive_IT(hi2c, obj_s->address, (uint8_t *)obj->rx_buff.buffer, obj->rx_buff.length, obj_s->XferOperation);
|
HAL_I2C_Master_Seq_Receive_IT(hi2c, obj_s->address, (uint8_t *)obj->rx_buff.buffer, obj->rx_buff.length, obj_s->XferOperation);
|
||||||
} else
|
} else
|
||||||
|
#elif defined(I2C_IP_VERSION_V2)
|
||||||
|
if(obj_s->state == STM_I2C_ASYNC_WRITE_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
if(obj->rx_buff.length > 0)
|
||||||
|
{
|
||||||
|
// This is a write-then-read transaction, switch to reading.
|
||||||
|
uint32_t xferOptions = obj_s->stop ? I2C_FIRST_AND_LAST_FRAME : I2C_FIRST_FRAME;
|
||||||
|
HAL_I2C_Master_Seq_Receive_IT(hi2c, obj_s->address, (uint8_t *) obj->rx_buff.buffer, obj->rx_buff.length,
|
||||||
|
xferOptions);
|
||||||
|
obj_s->state = STM_I2C_ASYNC_READ_IN_PROGRESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write-only async transaction, we're done.
|
||||||
|
obj_s->event |= I2C_EVENT_TRANSFER_COMPLETE;
|
||||||
|
|
||||||
|
if(!obj_s->stop && !(obj_s->event & I2C_EVENT_ERROR_NO_SLAVE))
|
||||||
|
{
|
||||||
|
// If the transaction was successful and we did a repeated start, update state appropriately.
|
||||||
|
obj_s->state = STM_I2C_PENDING_START;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj_s->state = STM_I2C_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
/* Set event flag */
|
// Set event flag. Note: We still get the complete callback even if an error was encountered,
|
||||||
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
|
// so use |= to preserve any error flags.
|
||||||
|
obj_s->event |= I2C_EVENT_TRANSFER_COMPLETE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1239,9 +1430,24 @@ void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
|
||||||
struct i2c_s *obj_s = I2C_S(obj);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
#ifdef I2C_IP_VERSION_V1
|
#ifdef I2C_IP_VERSION_V1
|
||||||
hi2c->PreviousState = I2C_STATE_NONE;
|
hi2c->PreviousState = I2C_STATE_NONE;
|
||||||
|
#elif defined(I2C_IP_VERSION_V2)
|
||||||
|
if(obj_s->state == STM_I2C_ASYNC_READ_IN_PROGRESS)
|
||||||
|
{
|
||||||
|
if(!obj_s->stop && !(obj_s->event & I2C_EVENT_ERROR_NO_SLAVE))
|
||||||
|
{
|
||||||
|
// If the transaction was successful and we did a repeated start, update state appropriately.
|
||||||
|
obj_s->state = STM_I2C_PENDING_START;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
obj_s->state = STM_I2C_IDLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Set event flag */
|
|
||||||
obj_s->event = I2C_EVENT_TRANSFER_COMPLETE;
|
// Set event flag. Note: We still get the complete callback even if an error was encountered,
|
||||||
|
// so use |= to preserve any error flags.
|
||||||
|
obj_s->event |= I2C_EVENT_TRANSFER_COMPLETE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
|
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
|
||||||
|
@ -1265,6 +1471,15 @@ void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c)
|
||||||
/* Keep Set event flag */
|
/* Keep Set event flag */
|
||||||
event_code = (I2C_EVENT_TRANSFER_EARLY_NACK) | (I2C_EVENT_ERROR_NO_SLAVE);
|
event_code = (I2C_EVENT_TRANSFER_EARLY_NACK) | (I2C_EVENT_ERROR_NO_SLAVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we only got a NACK, no reason to call the cavalry
|
||||||
|
if(handle->ErrorCode == HAL_I2C_ERROR_AF)
|
||||||
|
{
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE); // Hardware stops the transaction when it gets a NACK
|
||||||
|
obj_s->event = event_code;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG_PRINTF("HAL_I2C_ErrorCallback:%d, index=%d\r\n", (int) hi2c->ErrorCode, obj_s->index);
|
DEBUG_PRINTF("HAL_I2C_ErrorCallback:%d, index=%d\r\n", (int) hi2c->ErrorCode, obj_s->index);
|
||||||
|
|
||||||
/* re-init IP to try and get back in a working state */
|
/* re-init IP to try and get back in a working state */
|
||||||
|
@ -1524,11 +1739,15 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx,
|
||||||
obj_s->address = address;
|
obj_s->address = address;
|
||||||
obj_s->stop = stop;
|
obj_s->stop = stop;
|
||||||
|
|
||||||
|
// For async I2C interrupts, we need to use a somewhat odd structure. We redirect the ISR to call a C++ function,
|
||||||
|
// I2C::irq_handler_asynch(). That function then sends the IRQ back down to the HAL layer, and also
|
||||||
|
// does some RTOS stuff to wake up any waiting threads.
|
||||||
i2c_ev_err_enable(obj, handler);
|
i2c_ev_err_enable(obj, handler);
|
||||||
|
|
||||||
|
int halRet = HAL_OK;
|
||||||
|
#if defined(I2C_IP_VERSION_V1)
|
||||||
/* Set operation step depending if stop sending required or not */
|
/* Set operation step depending if stop sending required or not */
|
||||||
if ((tx_length && !rx_length) || (!tx_length && rx_length)) {
|
if ((tx_length && !rx_length) || (!tx_length && rx_length)) {
|
||||||
#if defined(I2C_IP_VERSION_V1)
|
|
||||||
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
||||||
uint32_t op1 = I2C_FIRST_AND_LAST_FRAME;
|
uint32_t op1 = I2C_FIRST_AND_LAST_FRAME;
|
||||||
uint32_t op2 = I2C_LAST_FRAME;
|
uint32_t op2 = I2C_LAST_FRAME;
|
||||||
|
@ -1546,39 +1765,56 @@ void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length, void *rx,
|
||||||
obj_s->XferOperation = I2C_NEXT_FRAME;
|
obj_s->XferOperation = I2C_NEXT_FRAME;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#elif defined(I2C_IP_VERSION_V2)
|
|
||||||
if ((obj_s->XferOperation == I2C_FIRST_FRAME) || (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 {
|
|
||||||
// should not happend
|
|
||||||
error("I2C: abnormal case should not happend");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (tx_length > 0) {
|
if (tx_length > 0) {
|
||||||
HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, obj_s->XferOperation);
|
halRet = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, obj_s->XferOperation);
|
||||||
}
|
}
|
||||||
if (rx_length > 0) {
|
else { // RX
|
||||||
HAL_I2C_Master_Seq_Receive_IT(handle, address, (uint8_t *)rx, rx_length, obj_s->XferOperation);
|
halRet = HAL_I2C_Master_Seq_Receive_IT(handle, address, (uint8_t *)rx, rx_length, obj_s->XferOperation);
|
||||||
}
|
}
|
||||||
} else if (tx_length && rx_length) {
|
} else if (tx_length && rx_length) {
|
||||||
/* Two steps operation, don't modify XferOperation, keep it for next step */
|
|
||||||
#if defined(I2C_IP_VERSION_V1)
|
|
||||||
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
// Trick to remove compiler warning "left and right operands are identical" in some cases
|
||||||
uint32_t op1 = I2C_FIRST_AND_LAST_FRAME;
|
uint32_t op1 = I2C_FIRST_AND_LAST_FRAME;
|
||||||
uint32_t op2 = I2C_LAST_FRAME;
|
uint32_t op2 = I2C_LAST_FRAME;
|
||||||
if ((obj_s->XferOperation == op1) || (obj_s->XferOperation == op2)) {
|
if ((obj_s->XferOperation == op1) || (obj_s->XferOperation == op2)) {
|
||||||
HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, I2C_FIRST_FRAME);
|
halRet = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, I2C_FIRST_FRAME);
|
||||||
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
|
} else if ((obj_s->XferOperation == I2C_FIRST_FRAME) ||
|
||||||
(obj_s->XferOperation == I2C_NEXT_FRAME)) {
|
(obj_s->XferOperation == I2C_NEXT_FRAME)) {
|
||||||
HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, I2C_NEXT_FRAME);
|
halRet = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, I2C_NEXT_FRAME);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#elif defined(I2C_IP_VERSION_V2)
|
#elif defined(I2C_IP_VERSION_V2)
|
||||||
HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, I2C_FIRST_FRAME);
|
|
||||||
|
prep_for_restart_if_needed(obj_s);
|
||||||
|
|
||||||
|
uint32_t xferOptions = get_hal_xfer_options(obj_s, stop);
|
||||||
|
|
||||||
|
if(!i2c_is_ready_for_transaction_start(obj_s->state))
|
||||||
|
{
|
||||||
|
// I2C peripheral is not ready to start a new transaction
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((tx_length && !rx_length) || (!tx_length && rx_length)) {
|
||||||
|
|
||||||
|
if (tx_length > 0) {
|
||||||
|
obj_s->state = STM_I2C_ASYNC_WRITE_IN_PROGRESS;
|
||||||
|
halRet = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *)tx, tx_length, xferOptions);
|
||||||
|
}
|
||||||
|
else { // RX
|
||||||
|
obj_s->state = STM_I2C_ASYNC_READ_IN_PROGRESS;
|
||||||
|
halRet = HAL_I2C_Master_Seq_Receive_IT(handle, address, (uint8_t *)rx, rx_length, xferOptions);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (tx_length && rx_length) {
|
||||||
|
obj_s->state = STM_I2C_ASYNC_WRITE_IN_PROGRESS;
|
||||||
|
halRet = HAL_I2C_Master_Seq_Transmit_IT(handle, address, (uint8_t *) tx, tx_length, xferOptions);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if(halRet != HAL_OK) {
|
||||||
|
DEBUG_PRINTF("Error %d trying to start async I2C transaction.\n", halRet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1598,15 +1834,13 @@ uint32_t i2c_irq_handler_asynch(i2c_t *obj)
|
||||||
|
|
||||||
uint8_t i2c_active(i2c_t *obj)
|
uint8_t i2c_active(i2c_t *obj)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct i2c_s *obj_s = I2C_S(obj);
|
struct i2c_s *obj_s = I2C_S(obj);
|
||||||
I2C_HandleTypeDef *handle = &(obj_s->handle);
|
|
||||||
|
|
||||||
if (handle->State == HAL_I2C_STATE_READY) {
|
#ifdef I2C_IP_VERSION_V2
|
||||||
return 0;
|
return !i2c_is_ready_for_transaction_start(obj_s->state);
|
||||||
} else {
|
#else
|
||||||
return 1;
|
return obj_s->handle.State != HAL_I2C_STATE_READY;
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void i2c_abort_asynch(i2c_t *obj)
|
void i2c_abort_asynch(i2c_t *obj)
|
||||||
|
@ -1619,6 +1853,8 @@ void i2c_abort_asynch(i2c_t *obj)
|
||||||
uint16_t Dummy_DevAddress = 0x00;
|
uint16_t Dummy_DevAddress = 0x00;
|
||||||
|
|
||||||
HAL_I2C_Master_Abort_IT(handle, Dummy_DevAddress);
|
HAL_I2C_Master_Abort_IT(handle, Dummy_DevAddress);
|
||||||
|
|
||||||
|
STM_I2C_SET_STATE(obj_s, STM_I2C_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if MBED_CONF_TARGET_I2C_TIMING_VALUE_ALGO
|
#if MBED_CONF_TARGET_I2C_TIMING_VALUE_ALGO
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2016-2022 STMicroelectronics
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef MBED_STM_I2C_API_H
|
||||||
|
#define MBED_STM_I2C_API_H
|
||||||
|
|
||||||
|
#include "i2c_device.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* State of the I2C peripheral.
|
||||||
|
* Note: SB stands for Single Byte, TR stands for Transaction
|
||||||
|
*/
|
||||||
|
typedef enum stm_i2c_state
|
||||||
|
{
|
||||||
|
STM_I2C_IDLE,
|
||||||
|
STM_I2C_PENDING_START, // This state is created either by calling start(), or by completing a transaction with the repeated start flag
|
||||||
|
STM_I2C_SB_READ_IN_PROGRESS,
|
||||||
|
STM_I2C_SB_WRITE_IN_PROGRESS,
|
||||||
|
STM_I2C_TR_READ_IN_PROGRESS,
|
||||||
|
STM_I2C_TR_WRITE_IN_PROGRESS,
|
||||||
|
STM_I2C_ASYNC_READ_IN_PROGRESS,
|
||||||
|
STM_I2C_ASYNC_WRITE_IN_PROGRESS
|
||||||
|
} stm_i2c_state;
|
||||||
|
|
||||||
|
#ifdef I2C_IP_VERSION_V2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extended I2C structure containing STM-specific data
|
||||||
|
*/
|
||||||
|
struct i2c_s {
|
||||||
|
/* The 1st 2 members I2CName i2c
|
||||||
|
* and I2C_HandleTypeDef handle should
|
||||||
|
* be kept as the first members of this struct
|
||||||
|
* to ensure i2c_get_obj to work as expected
|
||||||
|
*/
|
||||||
|
I2CName i2c;
|
||||||
|
I2C_HandleTypeDef handle;
|
||||||
|
uint8_t index;
|
||||||
|
int hz;
|
||||||
|
PinName sda;
|
||||||
|
PinName scl;
|
||||||
|
IRQn_Type event_i2cIRQ;
|
||||||
|
IRQn_Type error_i2cIRQ;
|
||||||
|
volatile stm_i2c_state state;
|
||||||
|
|
||||||
|
/// Used to pass events (the I2C_EVENT_xxx defines) from ISRs to the main thread
|
||||||
|
volatile uint8_t event;
|
||||||
|
|
||||||
|
int current_hz;
|
||||||
|
#if DEVICE_I2CSLAVE
|
||||||
|
uint8_t slave;
|
||||||
|
volatile uint8_t pending_slave_tx_master_rx;
|
||||||
|
volatile uint8_t pending_slave_rx_maxter_tx;
|
||||||
|
uint8_t *slave_rx_buffer;
|
||||||
|
volatile uint16_t slave_rx_buffer_size;
|
||||||
|
volatile uint16_t slave_rx_count;
|
||||||
|
#endif
|
||||||
|
#if DEVICE_I2C_ASYNCH
|
||||||
|
/// Address that the current asynchronous transaction is talking to
|
||||||
|
uint32_t address;
|
||||||
|
|
||||||
|
/// If true, send a stop at the end of the current asynchronous transaction
|
||||||
|
bool stop;
|
||||||
|
|
||||||
|
/// Specifies which events (the I2C_EVENT_xxx defines) can be passed up to the application from the IRQ handler
|
||||||
|
uint8_t available_events;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if STATIC_PINMAP_READY
|
||||||
|
int sda_func;
|
||||||
|
int scl_func;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macro that can be used to set the state of an I2C object.
|
||||||
|
// Compiles to nothing for IP v1
|
||||||
|
#ifdef I2C_IP_VERSION_V2
|
||||||
|
#define STM_I2C_SET_STATE(i2c_s, new_state) i2c_s->state = new_state
|
||||||
|
#else
|
||||||
|
#define STM_I2C_SET_STATE(i2c_s, new_state) (void)i2c_s
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //MBED_STM_I2C_API_H
|
Loading…
Reference in New Issue