1
0
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:
stac 2010-09-15 14:20:55 +00:00 committed by stac
parent 65ad2caf8a
commit 7d5463e5e6

View File

@ -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);