mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-02-18 08:54:15 +01:00
i2c: Move polling for bus stopped from ISR to task/mainloop
Occasionally, the I2C driver races with the STM32 I2C peripheral at the end of a bus cycle. This leaves the bus in an errored state and the stop condition is not properly asserted on the bus. The polling for the stopped condition was previously implemented in ISR context since it was expected to be nearly instananeous. In the error condition, however, the stop condition will never happen. The polling for this case is now done by the initiating task (or mainloop on the AHRS) to prevent the timeout condition from triggering the watchdog. git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1623 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
parent
65ad2caf8a
commit
7d5463e5e6
@ -57,6 +57,7 @@ enum i2c_adapter_event {
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_EQ_1,
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_EQ_2,
|
||||
I2C_EVENT_TRANSFER_DONE_LEN_GT_2,
|
||||
I2C_EVENT_STOPPED,
|
||||
I2C_EVENT_AUTO, /* FIXME: remove this */
|
||||
|
||||
I2C_EVENT_NUM_EVENTS /* Must be last */
|
||||
@ -95,6 +96,7 @@ struct i2c_adapter_transition {
|
||||
|
||||
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);
|
||||
|
||||
const static struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM_STATES] = {
|
||||
[I2C_STATE_FSM_FAULT] = {
|
||||
@ -111,7 +113,7 @@ const static struct i2c_adapter_transition i2c_adapter_transitions[I2C_STATE_NUM
|
||||
[I2C_STATE_STOPPING] = {
|
||||
.entry_fn = go_stopping,
|
||||
.next_state = {
|
||||
[I2C_EVENT_AUTO] = I2C_STATE_STOPPED,
|
||||
[I2C_EVENT_STOPPED] = I2C_STATE_STOPPED,
|
||||
},
|
||||
},
|
||||
|
||||
@ -291,22 +293,12 @@ static void go_fsm_fault (struct pios_i2c_adapter * i2c_adapter)
|
||||
}
|
||||
|
||||
static void go_stopping (struct pios_i2c_adapter * i2c_adapter)
|
||||
{
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
|
||||
/* Spin waiting for the stop bit to be cleared before continuing */
|
||||
#define I2C_CR1_STOP_REQUESTED 0x0200
|
||||
while (i2c_adapter->cfg->regs->CR1 & I2C_CR1_STOP_REQUESTED);
|
||||
}
|
||||
|
||||
static void go_stopped (struct pios_i2c_adapter * i2c_adapter)
|
||||
{
|
||||
#ifdef USE_FREERTOS
|
||||
signed portBASE_TYPE pxHigherPriorityTaskWoken = pdFALSE;
|
||||
#endif
|
||||
|
||||
I2C_ITConfig(i2c_adapter->cfg->regs, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR, DISABLE);
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, ENABLE);
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
if (xSemaphoreGiveFromISR(i2c_adapter->sem_ready, &pxHigherPriorityTaskWoken) != pdTRUE) {
|
||||
@ -316,6 +308,12 @@ static void go_stopped (struct pios_i2c_adapter * i2c_adapter)
|
||||
#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_ERR, DISABLE);
|
||||
I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, ENABLE);
|
||||
}
|
||||
|
||||
static void go_starting (struct pios_i2c_adapter * i2c_adapter)
|
||||
{
|
||||
PIOS_DEBUG_Assert(i2c_adapter->active_txn);
|
||||
@ -536,9 +534,21 @@ static void i2c_adapter_process_auto(struct pios_i2c_adapter * i2c_adapter)
|
||||
static void i2c_adapter_fsm_init(struct pios_i2c_adapter * i2c_adapter)
|
||||
{
|
||||
i2c_adapter->curr_state = I2C_STATE_STOPPED;
|
||||
//go_stopped(i2c_adapter);
|
||||
}
|
||||
|
||||
static bool i2c_adapter_wait_for_stopped(struct pios_i2c_adapter * i2c_adapter)
|
||||
{
|
||||
/*
|
||||
* Wait for the bus to return to the stopped state.
|
||||
* This was pulled out of the FSM due to occasional
|
||||
* failures at this transition which previously resulted
|
||||
* in spinning on this bit in the ISR forever.
|
||||
*/
|
||||
#define I2C_CR1_STOP_REQUESTED 0x0200
|
||||
while (i2c_adapter->cfg->regs->CR1 & I2C_CR1_STOP_REQUESTED) continue;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#include <pios_i2c_priv.h>
|
||||
|
||||
@ -553,6 +563,18 @@ static struct pios_i2c_adapter * find_i2c_adapter_by_id (uint8_t adapter)
|
||||
return &(pios_i2c_adapters[adapter]);
|
||||
}
|
||||
|
||||
/* Return true if the FSM is in a terminal state */
|
||||
static bool i2c_adapter_fsm_terminated(struct pios_i2c_adapter * i2c_adapter)
|
||||
{
|
||||
switch (i2c_adapter->curr_state) {
|
||||
case I2C_STATE_STOPPING:
|
||||
case I2C_STATE_STOPPED:
|
||||
return (true);
|
||||
default:
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes IIC driver
|
||||
* \param[in] mode currently only mode 0 supported
|
||||
@ -696,11 +718,15 @@ bool PIOS_I2C_Transfer(uint8_t i2c, const struct pios_i2c_txn txn_list[], uint32
|
||||
#ifdef USE_FREERTOS
|
||||
xSemaphoreTake(i2c_adapter->sem_ready, portMAX_DELAY);
|
||||
xSemaphoreGive(i2c_adapter->sem_ready);
|
||||
#else
|
||||
/* Spin waiting for the transfer to finish */
|
||||
while (i2c_adapter->curr_state != I2C_STATE_STOPPED);
|
||||
#endif /* USE_FREERTOS */
|
||||
|
||||
/* Spin waiting for the transfer to finish */
|
||||
while (!i2c_adapter_fsm_terminated(i2c_adapter));
|
||||
|
||||
if (i2c_adapter_wait_for_stopped(i2c_adapter)) {
|
||||
i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_STOPPED);
|
||||
}
|
||||
|
||||
#ifdef USE_FREERTOS
|
||||
/* Unlock the bus */
|
||||
xSemaphoreGive(i2c_adapter->sem_busy);
|
||||
|
Loading…
x
Reference in New Issue
Block a user