From 55d52ceab02656a59d53001cf84cb4544708d296 Mon Sep 17 00:00:00 2001 From: Alessio Morale Date: Tue, 17 Jun 2014 00:50:26 +0200 Subject: [PATCH] OP-1275 Working initial PIOS_I2C implementation --- flight/pios/stm32f0x/pios_i2c.c | 831 +++++++------------------------- 1 file changed, 175 insertions(+), 656 deletions(-) diff --git a/flight/pios/stm32f0x/pios_i2c.c b/flight/pios/stm32f0x/pios_i2c.c index ef1e7f7ac..42df0b22b 100644 --- a/flight/pios/stm32f0x/pios_i2c.c +++ b/flight/pios/stm32f0x/pios_i2c.c @@ -37,33 +37,71 @@ #endif #include +/* 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 @@ -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; } }