mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-30 15:52:12 +01:00
OP-1275 Working initial PIOS_I2C implementation
This commit is contained in:
parent
cd7c76aa13
commit
55d52ceab0
@ -37,33 +37,71 @@
|
||||
#endif
|
||||
|
||||
#include <pios_i2c_priv.h>
|
||||
/* Interrupt flags descriptions taken from UM1566 */
|
||||
|
||||
/* - TX1: Manages the event “Transmit Interrupt Status”
|
||||
* which means a new data shall be written in the I2C data register for the next transfer. */
|
||||
/* - RXNE: Manages the event “Receive Buffer Not Empty” which
|
||||
* means a data has been received and should be read from the data register. */
|
||||
/* - TCR: Available in Master mode only. Manages Transfer Complete Reload event which means
|
||||
* the master or slave received or transmitted nbytes and Reload =1. */
|
||||
/* - TC: Available in Master mode only. Manages Transfer Complete event which means the master
|
||||
* received or transmitted all data and communication will be closed (Generate stop) or
|
||||
* another one will start (Repeated start). */
|
||||
/* - ADDR: Manages the event “Address phase done” which means that the device in mode slave
|
||||
* received start bit followed by its own address and acknowledged it. */
|
||||
/* - NACK: Manages the event “Not Acknowledge received flag” which means the device received
|
||||
* a NACK. In master mode this flag indicates an error (slave don’t respond to sent address).
|
||||
* In slave mode, when master received all data it send NACK to indicate to slave that all
|
||||
* data are received.*/
|
||||
/* - STOP: Manages the event “Stop bit received” which means that the master has
|
||||
* closed the communication.*/
|
||||
|
||||
|
||||
// Error mask = Bus error | Arbitration lost | Overrun/Underrun
|
||||
#define I2C_ISR_ERROR_MASK (I2C_ISR_BERR|I2C_ISR_ARLO|I2C_ISR_OVR)
|
||||
#define I2C_ISR_ERR (I2C_IT_ERRI)
|
||||
//Transfer Complete interrupt mask
|
||||
#define I2C_ISR_BUF (I2C_IT_TCI)
|
||||
#define I2C_ISR_ERROR_MASK (I2C_ISR_BERR | I2C_ISR_ARLO | I2C_ISR_OVR)
|
||||
#define I2C_IT_ERR (I2C_IT_ERRI)
|
||||
// Interrupt sources
|
||||
|
||||
// Transfer Complete interrupt mask
|
||||
#define I2C_IT_BUF (I2C_IT_TCI)
|
||||
|
||||
// Stop Detection interrupt mask|Not Acknowledge received interrupt mask|
|
||||
// Address Match interrupt mask|RX interrupt mask
|
||||
#define I2C_ISR_EVT (I2C_IT_STOPI|I2C_IT_NACKI|I2C_IT_ADDRI|I2C_IT_RXI|I2C_IT_TXI)
|
||||
#define I2C_IT_EVT (I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ADDRI | I2C_IT_RXI | I2C_IT_TXI)
|
||||
|
||||
// #define I2C_HALT_ON_ERRORS
|
||||
#define I2C_ERROR_FLAGS \
|
||||
(I2C_FLAG_NACKF | I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR | \
|
||||
I2C_FLAG_PECERR | I2C_FLAG_TIMEOUT | I2C_FLAG_ALERT \
|
||||
)
|
||||
|
||||
#define I2C_EVENT_FLAGS \
|
||||
(I2C_FLAG_TXE | I2C_FLAG_TXIS | I2C_FLAG_RXNE | \
|
||||
I2C_FLAG_NACKF | I2C_FLAG_STOPF | I2C_FLAG_TC | I2C_FLAG_TCR)
|
||||
|
||||
enum i2c_adapter_state {
|
||||
I2C_STATE_FSM_FAULT = 0, /* Must be zero so undefined transitions land here */
|
||||
|
||||
I2C_STATE_BUS_ERROR,
|
||||
|
||||
I2C_STATE_STOPPED,
|
||||
I2C_STATE_STOPPING,
|
||||
|
||||
I2C_STATE_TXN_SETUP,
|
||||
|
||||
I2C_STATE_TRANSFER,
|
||||
|
||||
I2C_STATE_NACK,
|
||||
|
||||
I2C_STATE_NUM_STATES /* Must be last */
|
||||
};
|
||||
|
||||
enum i2c_adapter_event {
|
||||
I2C_EVENT_BUS_ERROR,
|
||||
I2C_EVENT_START,
|
||||
I2C_EVENT_STARTED_MORE_TXN_READ,
|
||||
I2C_EVENT_STARTED_MORE_TXN_WRITE,
|
||||
I2C_EVENT_STARTED_LAST_TXN_READ,
|
||||
I2C_EVENT_STARTED_LAST_TXN_WRITE,
|
||||
I2C_EVENT_ADDR_SENT_LEN_EQ_0,
|
||||
I2C_EVENT_ADDR_SENT_LEN_EQ_1,
|
||||
I2C_EVENT_ADDR_SENT_LEN_EQ_2,
|
||||
I2C_EVENT_ADDR_SENT_LEN_GT_2,
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_EQ_0,
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_EQ_1,
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_EQ_2,
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_GT_2,
|
||||
I2C_EVENT_TRANSFER_DONE,
|
||||
I2C_EVENT_TRANSFER_DONE_NEXT_TXN,
|
||||
I2C_EVENT_NACK,
|
||||
I2C_EVENT_STOPPED,
|
||||
I2C_EVENT_AUTO, /* FIXME: remove this */
|
||||
@ -77,13 +115,10 @@ static struct pios_i2c_fault_history i2c_adapter_fault_history;
|
||||
volatile uint32_t i2c_evirq_history[I2C_LOG_DEPTH];
|
||||
volatile uint8_t i2c_evirq_history_pointer = 0;
|
||||
|
||||
volatile uint32_t i2c_erirq_history[I2C_LOG_DEPTH];
|
||||
volatile uint8_t i2c_erirq_history_pointer = 0;
|
||||
|
||||
volatile enum i2c_adapter_state i2c_state_history[I2C_LOG_DEPTH];
|
||||
volatile uint8_t i2c_state_history[I2C_LOG_DEPTH];
|
||||
volatile uint8_t i2c_state_history_pointer = 0;
|
||||
|
||||
volatile enum i2c_adapter_event i2c_state_event_history[I2C_LOG_DEPTH];
|
||||
volatile uint8_t i2c_state_event_history[I2C_LOG_DEPTH];
|
||||
volatile uint8_t i2c_state_event_history_pointer;
|
||||
|
||||
static uint8_t i2c_fsm_fault_count = 0;
|
||||
@ -97,28 +132,8 @@ static void go_fsm_fault(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_bus_error(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_stopping(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_stopped(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_starting(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_addr(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_more_txn_pre_one(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_pre_first(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_pre_middle(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_more_txn_pre_last(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_post_last(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
static void go_r_any_txn_addr(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_last_txn_pre_one(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_pre_first(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_pre_middle(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_last_txn_pre_last(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_r_any_txn_post_last(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
static void go_w_any_txn_addr(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_w_any_txn_middle(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_w_more_txn_last(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
static void go_w_any_txn_addr(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_w_any_txn_middle(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_w_last_txn_last(struct pios_i2c_adapter *i2c_adapter);
|
||||
void go_txn_setup(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void go_transfer(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
static void go_nack(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
@ -127,241 +142,76 @@ struct i2c_adapter_transition {
|
||||
enum i2c_adapter_state next_state[I2C_EVENT_NUM_EVENTS];
|
||||
};
|
||||
|
||||
static void i2c_irq_error_handler(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void i2c_irq_event_handler(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
static void i2c_adapter_process_auto(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event);
|
||||
static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter);
|
||||
static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter);
|
||||
// static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter);
|
||||
static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter);
|
||||
|
||||
#ifdef PIOS_I2C_DIAGNOSTICS
|
||||
static void i2c_adapter_log_fault(enum pios_i2c_error_type type);
|
||||
#endif
|
||||
|
||||
static const struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM_STATES] = {
|
||||
[I2C_STATE_FSM_FAULT] = {
|
||||
[I2C_STATE_FSM_FAULT] = {
|
||||
.entry_fn = go_fsm_fault,
|
||||
.next_state = {
|
||||
.next_state = {
|
||||
[I2C_EVENT_AUTO] = I2C_STATE_STOPPING,
|
||||
},
|
||||
},
|
||||
[I2C_STATE_BUS_ERROR] = {
|
||||
[I2C_STATE_BUS_ERROR] = {
|
||||
.entry_fn = go_bus_error,
|
||||
.next_state = {
|
||||
.next_state = {
|
||||
[I2C_EVENT_AUTO] = I2C_STATE_STOPPING,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_STOPPED] = {
|
||||
[I2C_STATE_STOPPED] = {
|
||||
.entry_fn = go_stopped,
|
||||
.next_state = {
|
||||
[I2C_EVENT_START] = I2C_STATE_STARTING,
|
||||
.next_state = {
|
||||
[I2C_EVENT_START] = I2C_STATE_TXN_SETUP,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_STOPPING] = {
|
||||
[I2C_STATE_STOPPING] = {
|
||||
.entry_fn = go_stopping,
|
||||
.next_state = {
|
||||
.next_state = {
|
||||
[I2C_EVENT_STOPPED] = I2C_STATE_STOPPED,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
/*
|
||||
* Transaction setup
|
||||
*/
|
||||
|
||||
[I2C_STATE_STARTING] = {
|
||||
.entry_fn = go_starting,
|
||||
.next_state = {
|
||||
[I2C_EVENT_STARTED_MORE_TXN_READ] = I2C_STATE_R_MORE_TXN_ADDR,
|
||||
[I2C_EVENT_STARTED_MORE_TXN_WRITE] = I2C_STATE_W_MORE_TXN_ADDR,
|
||||
[I2C_EVENT_STARTED_LAST_TXN_READ] = I2C_STATE_R_LAST_TXN_ADDR,
|
||||
[I2C_EVENT_STARTED_LAST_TXN_WRITE] = I2C_STATE_W_LAST_TXN_ADDR,
|
||||
[I2C_STATE_TXN_SETUP] = {
|
||||
.entry_fn = go_txn_setup,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE] = I2C_STATE_TRANSFER,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
/*
|
||||
* Read with restart
|
||||
* Transfers
|
||||
*/
|
||||
|
||||
[I2C_STATE_R_MORE_TXN_ADDR] = {
|
||||
.entry_fn = go_r_any_txn_addr,
|
||||
.next_state = {
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_1] = I2C_STATE_R_MORE_TXN_PRE_ONE,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_2] = I2C_STATE_R_MORE_TXN_PRE_FIRST,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_GT_2] = I2C_STATE_R_MORE_TXN_PRE_FIRST,
|
||||
[I2C_STATE_TRANSFER] = {
|
||||
.entry_fn = go_transfer,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE] = I2C_STATE_TRANSFER,
|
||||
[I2C_EVENT_TRANSFER_DONE_NEXT_TXN] = I2C_STATE_TXN_SETUP,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_STOPPING,
|
||||
[I2C_EVENT_STOPPED] = I2C_STATE_STOPPING,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_MORE_TXN_PRE_ONE] = {
|
||||
.entry_fn = go_r_more_txn_pre_one,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_1] = I2C_STATE_R_MORE_TXN_POST_LAST,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_MORE_TXN_PRE_FIRST] = {
|
||||
.entry_fn = go_r_any_txn_pre_first,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_2] = I2C_STATE_R_MORE_TXN_PRE_LAST,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_GT_2] = I2C_STATE_R_MORE_TXN_PRE_MIDDLE,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_MORE_TXN_PRE_MIDDLE] = {
|
||||
.entry_fn = go_r_any_txn_pre_middle,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_2] = I2C_STATE_R_MORE_TXN_PRE_LAST,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_GT_2] = I2C_STATE_R_MORE_TXN_PRE_MIDDLE,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_MORE_TXN_PRE_LAST] = {
|
||||
.entry_fn = go_r_more_txn_pre_last,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_1] = I2C_STATE_R_MORE_TXN_POST_LAST,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_MORE_TXN_POST_LAST] = {
|
||||
.entry_fn = go_r_any_txn_post_last,
|
||||
.next_state = {
|
||||
[I2C_EVENT_AUTO] = I2C_STATE_STARTING,
|
||||
},
|
||||
},
|
||||
|
||||
/*
|
||||
* Read
|
||||
*/
|
||||
|
||||
[I2C_STATE_R_LAST_TXN_ADDR] = {
|
||||
.entry_fn = go_r_any_txn_addr,
|
||||
.next_state = {
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_1] = I2C_STATE_R_LAST_TXN_PRE_ONE,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_2] = I2C_STATE_R_LAST_TXN_PRE_FIRST,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_GT_2] = I2C_STATE_R_LAST_TXN_PRE_FIRST,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_LAST_TXN_PRE_ONE] = {
|
||||
.entry_fn = go_r_last_txn_pre_one,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_1] = I2C_STATE_R_LAST_TXN_POST_LAST,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_LAST_TXN_PRE_FIRST] = {
|
||||
.entry_fn = go_r_any_txn_pre_first,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_2] = I2C_STATE_R_LAST_TXN_PRE_LAST,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_GT_2] = I2C_STATE_R_LAST_TXN_PRE_MIDDLE,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_LAST_TXN_PRE_MIDDLE] = {
|
||||
.entry_fn = go_r_any_txn_pre_middle,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_2] = I2C_STATE_R_LAST_TXN_PRE_LAST,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_GT_2] = I2C_STATE_R_LAST_TXN_PRE_MIDDLE,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_LAST_TXN_PRE_LAST] = {
|
||||
.entry_fn = go_r_last_txn_pre_last,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_1] = I2C_STATE_R_LAST_TXN_POST_LAST,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_R_LAST_TXN_POST_LAST] = {
|
||||
.entry_fn = go_r_any_txn_post_last,
|
||||
.next_state = {
|
||||
[I2C_EVENT_AUTO] = I2C_STATE_STOPPING,
|
||||
},
|
||||
},
|
||||
|
||||
/*
|
||||
* Write with restart
|
||||
*/
|
||||
|
||||
[I2C_STATE_W_MORE_TXN_ADDR] = {
|
||||
.entry_fn = go_w_any_txn_addr,
|
||||
.next_state = {
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_1] = I2C_STATE_W_MORE_TXN_LAST,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_2] = I2C_STATE_W_MORE_TXN_MIDDLE,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_GT_2] = I2C_STATE_W_MORE_TXN_MIDDLE,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_W_MORE_TXN_MIDDLE] = {
|
||||
.entry_fn = go_w_any_txn_middle,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_1] = I2C_STATE_W_MORE_TXN_LAST,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_2] = I2C_STATE_W_MORE_TXN_MIDDLE,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_GT_2] = I2C_STATE_W_MORE_TXN_MIDDLE,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_W_MORE_TXN_LAST] = {
|
||||
.entry_fn = go_w_more_txn_last,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_0] = I2C_STATE_STARTING,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
/*
|
||||
* Write
|
||||
*/
|
||||
|
||||
[I2C_STATE_W_LAST_TXN_ADDR] = {
|
||||
.entry_fn = go_w_any_txn_addr,
|
||||
.next_state = {
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_1] = I2C_STATE_W_LAST_TXN_LAST,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_EQ_2] = I2C_STATE_W_LAST_TXN_MIDDLE,
|
||||
[I2C_EVENT_ADDR_SENT_LEN_GT_2] = I2C_STATE_W_LAST_TXN_MIDDLE,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_W_LAST_TXN_MIDDLE] = {
|
||||
.entry_fn = go_w_any_txn_middle,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_1] = I2C_STATE_W_LAST_TXN_LAST,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_2] = I2C_STATE_W_LAST_TXN_MIDDLE,
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_GT_2] = I2C_STATE_W_LAST_TXN_MIDDLE,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
|
||||
[I2C_STATE_W_LAST_TXN_LAST] = {
|
||||
.entry_fn = go_w_last_txn_last,
|
||||
.next_state = {
|
||||
[I2C_EVENT_TRANSFER_DONE_LEN_EQ_0] = I2C_STATE_STOPPING,
|
||||
[I2C_EVENT_NACK] = I2C_STATE_NACK,
|
||||
[I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
|
||||
},
|
||||
},
|
||||
[I2C_STATE_NACK] = {
|
||||
[I2C_STATE_NACK] = {
|
||||
.entry_fn = go_nack,
|
||||
.next_state = {
|
||||
.next_state = {
|
||||
[I2C_EVENT_AUTO] = I2C_STATE_STOPPING,
|
||||
},
|
||||
},
|
||||
@ -392,7 +242,7 @@ static void go_stopping(struct pios_i2c_adapter *i2c_adapter)
|
||||
signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE;
|
||||
#endif
|
||||
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_ERR | I2C_IT_BUF | I2C_IT_EVT, DISABLE);
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) {
|
||||
@ -400,17 +250,20 @@ static void go_stopping(struct pios_i2c_adapter *i2c_adapter)
|
||||
PIOS_DEBUG_Assert(0);
|
||||
#endif
|
||||
}
|
||||
portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken); /* FIXME: is this the right place for this? */
|
||||
portEND_SWITCHING_ISR(pxHigherPriorityTaskWoken);
|
||||
#endif /* USE_FREERTOS */
|
||||
}
|
||||
|
||||
static void go_stopped(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERRI, DISABLE);
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, ENABLE);
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
// I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, ENABLE);
|
||||
}
|
||||
|
||||
static void go_starting(struct pios_i2c_adapter *i2c_adapter)
|
||||
/**
|
||||
* Setup a new transfer
|
||||
* @param i2c_adapter
|
||||
*/
|
||||
void go_txn_setup(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
@ -419,182 +272,46 @@ static void go_starting(struct pios_i2c_adapter *i2c_adapter)
|
||||
i2c_adapter->active_byte = &(i2c_adapter->active_txn->buf[0]);
|
||||
i2c_adapter->last_byte = &(i2c_adapter->active_txn->buf[i2c_adapter->active_txn->len - 1]);
|
||||
|
||||
I2C_GenerateSTART(i2c_adapter->cfg->regs, ENABLE);
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
|
||||
if (i2c_adapter->active_txn->rw == PIOS_I2C_TXN_READ) {
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
|
||||
I2C_TransferHandling(i2c_adapter->cfg->regs, i2c_adapter->active_txn->addr, i2c_adapter->active_txn->len,
|
||||
/* Only last transaction generates Auto End */
|
||||
i2c_adapter->active_txn == i2c_adapter->last_txn ? I2C_AutoEnd_Mode : I2C_SoftEnd_Mode,
|
||||
I2C_Generate_Start_Read);
|
||||
} else {
|
||||
// For write operations, do not enable the IT_BUF events.
|
||||
// The current driver does not act when the TX data register is not full, only when the complete byte is sent.
|
||||
// With the IT_BUF enabled, we constantly get IRQs, See OP-326
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_ERR, ENABLE);
|
||||
I2C_TransferHandling(i2c_adapter->cfg->regs, i2c_adapter->active_txn->addr, i2c_adapter->active_txn->len,
|
||||
/* Only last transaction generates Auto End */
|
||||
i2c_adapter->active_txn == i2c_adapter->last_txn ? I2C_AutoEnd_Mode : I2C_SoftEnd_Mode,
|
||||
I2C_Generate_Start_Write);
|
||||
}
|
||||
}
|
||||
|
||||
/* Common to 'more' and 'last' transaction */
|
||||
static void go_r_any_txn_addr(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn->rw == PIOS_I2C_TXN_READ);
|
||||
|
||||
I2C_Send7bitAddress(i2c_adapter->cfg->regs, (i2c_adapter->active_txn->addr) << 1, I2C_Direction_Receiver);
|
||||
}
|
||||
|
||||
static void go_r_more_txn_pre_one(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
|
||||
I2C_GenerateSTART(i2c_adapter->cfg->regs, ENABLE);
|
||||
}
|
||||
|
||||
static void go_r_last_txn_pre_one(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
|
||||
I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE);
|
||||
}
|
||||
|
||||
/* Common to 'more' and 'last' transaction */
|
||||
static void go_r_any_txn_pre_first(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, ENABLE);
|
||||
}
|
||||
|
||||
/* Common to 'more' and 'last' transaction */
|
||||
static void go_r_any_txn_pre_middle(struct pios_i2c_adapter *i2c_adapter)
|
||||
/**
|
||||
* transfer a byte and advance to the next byte/txn if this is not the last byte of the last txn
|
||||
* @param i2c_adapter
|
||||
*/
|
||||
static void go_transfer(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
|
||||
*(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs);
|
||||
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
}
|
||||
|
||||
static void go_r_more_txn_pre_last(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
|
||||
PIOS_IRQ_Disable();
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
I2C_GenerateSTART(i2c_adapter->cfg->regs, ENABLE);
|
||||
*(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs);
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
|
||||
PIOS_IRQ_Enable();
|
||||
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
}
|
||||
|
||||
static void go_r_last_txn_pre_last(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
|
||||
PIOS_IRQ_Disable();
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE);
|
||||
*(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs);
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, ENABLE);
|
||||
PIOS_IRQ_Enable();
|
||||
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
}
|
||||
|
||||
/* Common to 'more' and 'last' transaction */
|
||||
static void go_r_any_txn_post_last(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte == i2c_adapter->last_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
|
||||
*(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs);
|
||||
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
|
||||
/* Move to the next transaction */
|
||||
i2c_adapter->active_txn++;
|
||||
}
|
||||
|
||||
/* Common to 'more' and 'last' transaction */
|
||||
static void go_w_any_txn_addr(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn->rw == PIOS_I2C_TXN_WRITE);
|
||||
|
||||
I2C_Send7bitAddress(i2c_adapter->cfg->regs, (i2c_adapter->active_txn->addr) << 1, I2C_Direction_Transmitter);
|
||||
}
|
||||
|
||||
static void go_w_any_txn_middle(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte < i2c_adapter->last_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
|
||||
I2C_SendData(i2c_adapter->cfg->regs, *(i2c_adapter->active_byte));
|
||||
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte <= i2c_adapter->last_byte);
|
||||
}
|
||||
|
||||
static void go_w_more_txn_last(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte == i2c_adapter->last_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
|
||||
I2C_SendData(i2c_adapter->cfg->regs, *(i2c_adapter->active_byte));
|
||||
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
|
||||
/* Move to the next transaction */
|
||||
i2c_adapter->active_txn++;
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
}
|
||||
|
||||
static void go_w_last_txn_last(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_byte == i2c_adapter->last_byte);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn >= i2c_adapter->first_txn);
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn <= i2c_adapter->last_txn);
|
||||
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_BUF, DISABLE);
|
||||
I2C_SendData(i2c_adapter->cfg->regs, *(i2c_adapter->active_byte));
|
||||
|
||||
// SHOULD MOVE THIS INTO A STOPPING STATE AND SET IT ONLY AFTER THE BYTE WAS SENT
|
||||
I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE);
|
||||
|
||||
if (i2c_adapter->active_txn->rw == PIOS_I2C_TXN_READ) {
|
||||
*(i2c_adapter->active_byte) = I2C_ReceiveData(i2c_adapter->cfg->regs);
|
||||
} else {
|
||||
I2C_SendData(i2c_adapter->cfg->regs, *(i2c_adapter->active_byte));
|
||||
}
|
||||
/* it this the last transaction? */
|
||||
if (i2c_adapter->active_byte == i2c_adapter->last_byte &&
|
||||
i2c_adapter->active_txn < i2c_adapter->last_txn) {
|
||||
i2c_adapter->active_txn++;
|
||||
return;
|
||||
}
|
||||
/* Move to the next byte */
|
||||
i2c_adapter->active_byte++;
|
||||
}
|
||||
|
||||
static void go_nack(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
|
||||
I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE);
|
||||
I2C_TransferHandling(i2c_adapter->cfg->regs, 0, 0, I2C_AutoEnd_Mode, I2C_Generate_Stop);
|
||||
}
|
||||
|
||||
static void i2c_adapter_inject_event(struct pios_i2c_adapter *i2c_adapter, enum i2c_adapter_event event)
|
||||
@ -652,7 +369,7 @@ static void i2c_adapter_fsm_init(struct pios_i2c_adapter *i2c_adapter)
|
||||
i2c_adapter_reset_bus(i2c_adapter);
|
||||
i2c_adapter->curr_state = I2C_STATE_STOPPED;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
uint32_t guard;
|
||||
@ -665,7 +382,7 @@ static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter)
|
||||
*/
|
||||
#define I2C_CR1_STOP_REQUESTED 0x0200
|
||||
for (guard = 1000000; /* FIXME: should use the configured bus timeout */
|
||||
guard && (i2c_adapter->cfg->regs->CR1 & I2C_CR1_STOP_REQUESTED); guard--) {
|
||||
guard && (i2c_adapter->cfg->regs->ISR & I2C_FLAG_STOPF); guard--) {
|
||||
continue;
|
||||
}
|
||||
if (!guard) {
|
||||
@ -675,83 +392,11 @@ static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter *i2c_adapter)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
static void i2c_adapter_reset_bus(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
/* Reset the I2C block */
|
||||
I2C_DeInit(i2c_adapter->cfg->regs);
|
||||
|
||||
/* Make sure the bus is free by clocking it until any slaves release the bus. */
|
||||
GPIO_InitTypeDef scl_gpio_init;
|
||||
scl_gpio_init = i2c_adapter->cfg->scl.init;
|
||||
scl_gpio_init.GPIO_Mode = GPIO_Mode_Out_OD;
|
||||
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
|
||||
GPIO_Init(i2c_adapter->cfg->scl.gpio, &scl_gpio_init);
|
||||
|
||||
GPIO_InitTypeDef sda_gpio_init;
|
||||
sda_gpio_init = i2c_adapter->cfg->sda.init;
|
||||
sda_gpio_init.GPIO_Mode = GPIO_Mode_Out_OD;
|
||||
GPIO_SetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
|
||||
GPIO_Init(i2c_adapter->cfg->sda.gpio, &sda_gpio_init);
|
||||
|
||||
/* Check SDA line to determine if slave is asserting bus and clock out if so, this may */
|
||||
/* have to be repeated (due to futher bus errors) but better than clocking 0xFF into an */
|
||||
/* ESC */
|
||||
// bool sda_hung = GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) == Bit_RESET;
|
||||
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) == Bit_RESET) {
|
||||
/* Set clock high and wait for any clock stretching to finish. */
|
||||
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
|
||||
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin) == Bit_RESET) {
|
||||
;
|
||||
}
|
||||
PIOS_DELAY_WaituS(2);
|
||||
|
||||
/* Set clock low */
|
||||
GPIO_ResetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
|
||||
PIOS_DELAY_WaituS(2);
|
||||
|
||||
/* Clock high again */
|
||||
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
|
||||
PIOS_DELAY_WaituS(2);
|
||||
}
|
||||
|
||||
/* Generate a start then stop condition */
|
||||
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
|
||||
PIOS_DELAY_WaituS(2);
|
||||
GPIO_ResetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
|
||||
PIOS_DELAY_WaituS(2);
|
||||
GPIO_ResetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
|
||||
PIOS_DELAY_WaituS(2);
|
||||
|
||||
/* Set data and clock high and wait for any clock stretching to finish. */
|
||||
GPIO_SetBits(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin);
|
||||
GPIO_SetBits(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin);
|
||||
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.init.GPIO_Pin) == Bit_RESET) {
|
||||
;
|
||||
}
|
||||
/* Wait for data to be high */
|
||||
while (GPIO_ReadInputDataBit(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.init.GPIO_Pin) != Bit_SET) {
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
/* Bus signals are guaranteed to be high (ie. free) after this point */
|
||||
/* Initialize the GPIO pins to the peripheral function */
|
||||
GPIO_Init(i2c_adapter->cfg->scl.gpio, &(i2c_adapter->cfg->scl.init));
|
||||
GPIO_Init(i2c_adapter->cfg->sda.gpio, &(i2c_adapter->cfg->sda.init));
|
||||
|
||||
/* Reset the I2C block */
|
||||
I2C_DeInit(i2c_adapter->cfg->regs);
|
||||
|
||||
/* Initialize the I2C block */
|
||||
I2C_Init(i2c_adapter->cfg->regs, &(i2c_adapter->cfg->init));
|
||||
|
||||
#define I2C_BUSY 0x20
|
||||
if (i2c_adapter->cfg->regs->SR2 & I2C_BUSY) {
|
||||
/* Reset the I2C block */
|
||||
I2C_SoftwareResetCmd(i2c_adapter->cfg->regs, ENABLE);
|
||||
I2C_SoftwareResetCmd(i2c_adapter->cfg->regs, DISABLE);
|
||||
}
|
||||
(void)i2c_adapter;
|
||||
// I2C_SoftwareResetCmd(i2c_adapter->cfg->regs);
|
||||
}
|
||||
|
||||
#include <pios_i2c_priv.h>
|
||||
@ -769,6 +414,8 @@ static bool i2c_adapter_fsm_terminated(struct pios_i2c_adapter *i2c_adapter)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PIOS_I2C_DIAGNOSTICS)
|
||||
|
||||
/**
|
||||
* Logs the last N state transitions and N IRQ events due to
|
||||
* an error condition
|
||||
@ -776,13 +423,10 @@ static bool i2c_adapter_fsm_terminated(struct pios_i2c_adapter *i2c_adapter)
|
||||
*/
|
||||
void i2c_adapter_log_fault(enum pios_i2c_error_type type)
|
||||
{
|
||||
#if defined(PIOS_I2C_DIAGNOSTICS)
|
||||
i2c_adapter_fault_history.type = type;
|
||||
for (uint8_t i = 0; i < I2C_LOG_DEPTH; i++) {
|
||||
i2c_adapter_fault_history.evirq[i] =
|
||||
i2c_evirq_history[(I2C_LOG_DEPTH + i2c_evirq_history_pointer - 1 - i) % I2C_LOG_DEPTH];
|
||||
i2c_adapter_fault_history.erirq[i] =
|
||||
i2c_erirq_history[(I2C_LOG_DEPTH + i2c_erirq_history_pointer - 1 - i) % I2C_LOG_DEPTH];
|
||||
i2c_adapter_fault_history.event[i] =
|
||||
i2c_state_event_history[(I2C_LOG_DEPTH + i2c_state_event_history_pointer - 1 - i) % I2C_LOG_DEPTH];
|
||||
i2c_adapter_fault_history.state[i] =
|
||||
@ -799,9 +443,9 @@ void i2c_adapter_log_fault(enum pios_i2c_error_type type)
|
||||
i2c_error_interrupt_counter++;
|
||||
break;
|
||||
}
|
||||
#endif /* if defined(PIOS_I2C_DIAGNOSTICS) */
|
||||
}
|
||||
|
||||
#endif /* if defined(PIOS_I2C_DIAGNOSTICS) */
|
||||
|
||||
/**
|
||||
* Logs the last N state transitions and N IRQ events due to
|
||||
@ -899,6 +543,7 @@ int32_t PIOS_I2C_Init(uint32_t *i2c_id, const struct pios_i2c_adapter_cfg *cfg)
|
||||
case (uint32_t)I2C1:
|
||||
/* Enable I2C peripheral clock (APB1 == slow speed) */
|
||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
|
||||
RCC_I2CCLKConfig(RCC_I2C1CLK_HSI);
|
||||
break;
|
||||
case (uint32_t)I2C2:
|
||||
/* Enable I2C peripheral clock (APB1 == slow speed) */
|
||||
@ -907,17 +552,24 @@ int32_t PIOS_I2C_Init(uint32_t *i2c_id, const struct pios_i2c_adapter_cfg *cfg)
|
||||
}
|
||||
|
||||
if (i2c_adapter->cfg->remap) {
|
||||
GPIO_PinRemapConfig(i2c_adapter->cfg->remap, ENABLE);
|
||||
GPIO_PinAFConfig(i2c_adapter->cfg->scl.gpio, i2c_adapter->cfg->scl.pin_source, i2c_adapter->cfg->remap);
|
||||
GPIO_PinAFConfig(i2c_adapter->cfg->sda.gpio, i2c_adapter->cfg->sda.pin_source, i2c_adapter->cfg->remap);
|
||||
}
|
||||
|
||||
GPIO_Init(i2c_adapter->cfg->scl.gpio, &i2c_adapter->cfg->scl.init);
|
||||
GPIO_Init(i2c_adapter->cfg->sda.gpio, &i2c_adapter->cfg->sda.init);
|
||||
|
||||
I2C_Init(i2c_adapter->cfg->regs, &i2c_adapter->cfg->init);
|
||||
|
||||
I2C_Cmd(i2c_adapter->cfg->regs, ENABLE);
|
||||
|
||||
/* Initialize the state machine */
|
||||
i2c_adapter_fsm_init(i2c_adapter);
|
||||
|
||||
*i2c_id = (uint32_t)i2c_adapter;
|
||||
|
||||
/* Configure and enable I2C interrupts */
|
||||
/* Configure and enable I2C interrupt */
|
||||
NVIC_Init(&(i2c_adapter->cfg->event.init));
|
||||
NVIC_Init(&(i2c_adapter->cfg->error.init));
|
||||
|
||||
/* No error */
|
||||
return 0;
|
||||
@ -998,17 +650,16 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[],
|
||||
;
|
||||
}
|
||||
|
||||
if (i2c_adapter_wait_for_stopped(i2c_adapter)) {
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STOPPED);
|
||||
} else {
|
||||
i2c_adapter_fsm_init(i2c_adapter);
|
||||
}
|
||||
i2c_adapter_fsm_init(i2c_adapter);
|
||||
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
/* Unlock the bus */
|
||||
xSemaphoreGive(i2c_adapter->sem_busy);
|
||||
if (!semaphore_success) {
|
||||
#ifdef PIOS_I2C_DIAGNOSTICS
|
||||
i2c_timeout_counter++;
|
||||
#endif
|
||||
}
|
||||
#endif /* USE_FREERTOS */
|
||||
|
||||
@ -1017,184 +668,52 @@ int32_t PIOS_I2C_Transfer(uint32_t i2c_id, const struct pios_i2c_txn txn_list[],
|
||||
0;
|
||||
}
|
||||
|
||||
void PIOS_I2C_IRQ_Handler(uint32_t i2c_id){
|
||||
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
|
||||
|
||||
bool valid = PIOS_I2C_validate(i2c_adapter);
|
||||
|
||||
PIOS_Assert(valid)
|
||||
|
||||
if(!(i2c_adapter->cfg->regs->ISR & I2C_ISR_ERROR_MASK)){
|
||||
i2c_irq_event_handler(i2c_adapter);
|
||||
} else {
|
||||
i2c_irq_error_handler(i2c_adapter);
|
||||
}
|
||||
}
|
||||
|
||||
void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id)
|
||||
void PIOS_I2C_IRQ_Handler(uint32_t i2c_id)
|
||||
{
|
||||
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
|
||||
|
||||
bool valid = PIOS_I2C_validate(i2c_adapter);
|
||||
|
||||
PIOS_Assert(valid)
|
||||
i2c_irq_event_handler(i2c_adapter );
|
||||
}
|
||||
|
||||
void PIOS_I2C_ER_IRQ_Handler(uint32_t i2c_id)
|
||||
{
|
||||
struct pios_i2c_adapter *i2c_adapter = (struct pios_i2c_adapter *)i2c_id;
|
||||
|
||||
bool valid = PIOS_I2C_validate(i2c_adapter);
|
||||
|
||||
PIOS_Assert(valid)
|
||||
i2c_irq_error_handler(i2c_adapter);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void i2c_irq_event_handler(struct pios_i2c_adapter *i2c_adapter){
|
||||
|
||||
i2c_adapter->cfg->regs->ISR
|
||||
uint32_t event = I2C_GetLastEvent(i2c_adapter->cfg->regs);
|
||||
uint32_t event = i2c_adapter->cfg->regs->ISR;
|
||||
|
||||
#if defined(PIOS_I2C_DIAGNOSTICS)
|
||||
/* Store event for diagnostics */
|
||||
i2c_evirq_history[i2c_evirq_history_pointer] = event;
|
||||
i2c_evirq_history_pointer = (i2c_evirq_history_pointer + 1) % I2C_LOG_DEPTH;
|
||||
#endif
|
||||
if (event & I2C_ERROR_FLAGS) {
|
||||
if (event & I2C_FLAG_NACKF) {
|
||||
#ifdef PIOS_I2C_DIAGNOSTICS
|
||||
i2c_nack_counter++;
|
||||
#endif
|
||||
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_NACKF);
|
||||
|
||||
#define EVENT_MASK 0x000700FF
|
||||
event &= EVENT_MASK;
|
||||
|
||||
|
||||
switch (event) { /* Mask out all the bits we don't care about */
|
||||
case (I2C_EVENT_MASTER_MODE_SELECT | 0x40):
|
||||
/* Unexplained event: EV5 + RxNE : Extraneous Rx. Probably a late NACK from previous read. */
|
||||
/* Clean up the extra Rx until the root cause is identified and just keep going */
|
||||
(void)I2C_ReceiveData(i2c_adapter->cfg->regs);
|
||||
/* Fall through */
|
||||
case I2C_EVENT_MASTER_MODE_SELECT: /* EV5 */
|
||||
switch (i2c_adapter->active_txn->rw) {
|
||||
case PIOS_I2C_TXN_READ:
|
||||
if (i2c_adapter->active_txn == i2c_adapter->last_txn) {
|
||||
/* Final transaction */
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STARTED_LAST_TXN_READ);
|
||||
} else if (i2c_adapter->active_txn < i2c_adapter->last_txn) {
|
||||
/* More transactions follow */
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STARTED_MORE_TXN_READ);
|
||||
} else {
|
||||
PIOS_DEBUG_Assert(0);
|
||||
}
|
||||
break;
|
||||
case PIOS_I2C_TXN_WRITE:
|
||||
if (i2c_adapter->active_txn == i2c_adapter->last_txn) {
|
||||
/* Final transaction */
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STARTED_LAST_TXN_WRITE);
|
||||
} else if (i2c_adapter->active_txn < i2c_adapter->last_txn) {
|
||||
/* More transactions follow */
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STARTED_MORE_TXN_WRITE);
|
||||
} else {
|
||||
PIOS_DEBUG_Assert(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PIOS_DEBUG_Assert(0);
|
||||
break;
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_NACK);
|
||||
} else { /* Mostly bus errors here */
|
||||
#ifdef PIOS_I2C_DIAGNOSTICS
|
||||
i2c_adapter_log_fault(PIOS_I2C_ERROR_INTERRUPT);
|
||||
#endif
|
||||
/* Fail hard on any errors for now */
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_BUS_ERROR);
|
||||
}
|
||||
break;
|
||||
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: /* EV6 */
|
||||
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: /* EV6 */
|
||||
switch (i2c_adapter->last_byte - i2c_adapter->active_byte + 1) {
|
||||
case 0:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_ADDR_SENT_LEN_EQ_0);
|
||||
break;
|
||||
case 1:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_ADDR_SENT_LEN_EQ_1);
|
||||
break;
|
||||
case 2:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_ADDR_SENT_LEN_EQ_2);
|
||||
break;
|
||||
default:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_ADDR_SENT_LEN_GT_2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x80: /* TxE only. TRA + MSL + BUSY have been cleared before we got here. */
|
||||
/* Ignore */
|
||||
{
|
||||
static volatile bool halt = FALSE;
|
||||
while (halt) {
|
||||
;
|
||||
return;
|
||||
}
|
||||
// I2C_FLAG_TCR and reload not handled right now. Transfers limited to 255 bytes
|
||||
if (event & (I2C_FLAG_TXIS | I2C_ISR_RXNE)) {
|
||||
if (i2c_adapter->active_byte <= i2c_adapter->last_byte) {
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_DONE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0: /* This triggers an FSM fault sometimes, but not having it stops things working */
|
||||
case 0x40: /* RxNE only. MSL + BUSY have already been cleared by HW. */
|
||||
case 0x44: /* RxNE + BTF. MSL + BUSY have already been cleared by HW. */
|
||||
case I2C_EVENT_MASTER_BYTE_RECEIVED: /* EV7 */
|
||||
case (I2C_EVENT_MASTER_BYTE_RECEIVED | 0x4): /* EV7 + BTF */
|
||||
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: /* EV8_2 */
|
||||
case 0x84: /* TxE + BTF. EV8_2 but TRA + MSL + BUSY have already been cleared by HW. */
|
||||
switch (i2c_adapter->last_byte - i2c_adapter->active_byte + 1) {
|
||||
case 0:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_DONE_LEN_EQ_0);
|
||||
break;
|
||||
case 1:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_DONE_LEN_EQ_1);
|
||||
break;
|
||||
case 2:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_DONE_LEN_EQ_2);
|
||||
break;
|
||||
default:
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_DONE_LEN_GT_2);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: /* EV8 */
|
||||
/* Ignore this event and wait for TRANSMITTED in case we can't keep up */
|
||||
goto skip_event;
|
||||
break;
|
||||
case 0x30084: /* Occurs between byte tranmistted and master mode selected */
|
||||
case 0x30000: /* Need to throw away this spurious event */
|
||||
case 0x30403 & EVENT_MASK: /* Detected this after got a NACK, probably stop bit */
|
||||
goto skip_event;
|
||||
break;
|
||||
default:
|
||||
i2c_adapter_log_fault(PIOS_I2C_ERROR_EVENT);
|
||||
#if defined(I2C_HALT_ON_ERRORS)
|
||||
PIOS_DEBUG_Assert(0);
|
||||
#endif
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_BUS_ERROR);
|
||||
break;
|
||||
if (event & I2C_ISR_TC) {
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_TRANSFER_DONE_NEXT_TXN);
|
||||
}
|
||||
|
||||
skip_event:
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
void i2c_irq_error_handler(struct pios_i2c_adapter *i2c_adapter)
|
||||
{
|
||||
#if defined(PIOS_I2C_DIAGNOSTICS)
|
||||
uint32_t event = I2C_GetLastEvent(i2c_adapter->cfg->regs);
|
||||
|
||||
i2c_erirq_history[i2c_erirq_history_pointer] = event;
|
||||
i2c_erirq_history_pointer = (i2c_erirq_history_pointer + 1) % 5;
|
||||
|
||||
#endif
|
||||
|
||||
if (event & I2C_FLAG_AF) {
|
||||
i2c_nack_counter++;
|
||||
|
||||
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_AF);
|
||||
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_NACK);
|
||||
} else { /* Mostly bus errors here */
|
||||
i2c_adapter_log_fault(PIOS_I2C_ERROR_INTERRUPT);
|
||||
|
||||
/* Fail hard on any errors for now */
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_BUS_ERROR);
|
||||
if (event & I2C_ISR_STOPF) {
|
||||
I2C_ClearFlag(i2c_adapter->cfg->regs, I2C_FLAG_STOPF);
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STOPPED);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user