2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_I2C I2C Functions
6 * @brief STM32F30x Hardware dependent I2C functionality
10 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
11 * dRonin, http://dronin.org, Copyright (C) 2016
12 * Tau Labs, http://taulabs.org, Copyright (C) 2012-2014
13 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
14 * @brief I2C Enable/Disable routines
15 * @see The GNU Public License (GPL) Version 3
17 *****************************************************************************/
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 3 of the License, or
22 * (at your option) any later version.
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
29 * You should have received a copy of the GNU General Public License along
30 * with this program; if not, write to the Free Software Foundation, Inc.,
31 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 /* Project Includes */
37 #if defined(PIOS_INCLUDE_I2C)
39 #include <pios_i2c_priv.h>
41 enum i2c_adapter_state
{
42 I2C_STATE_FSM_FAULT
= 0, /* Must be zero so undefined transitions land here */
50 I2C_STATE_R_MORE_TXN_ADDR
,
51 I2C_STATE_R_MORE_TXN_PRE_ONE
,
52 I2C_STATE_R_MORE_TXN_PRE_FIRST
,
53 I2C_STATE_R_MORE_TXN_PRE_MIDDLE
,
54 I2C_STATE_R_MORE_TXN_PRE_LAST
,
55 I2C_STATE_R_MORE_TXN_POST_LAST
,
57 I2C_STATE_R_LAST_TXN_ADDR
,
58 I2C_STATE_R_LAST_TXN_PRE_ONE
,
59 I2C_STATE_R_LAST_TXN_PRE_FIRST
,
60 I2C_STATE_R_LAST_TXN_PRE_MIDDLE
,
61 I2C_STATE_R_LAST_TXN_PRE_LAST
,
62 I2C_STATE_R_LAST_TXN_POST_LAST
,
64 I2C_STATE_W_MORE_TXN_ADDR
,
65 I2C_STATE_W_MORE_TXN_MIDDLE
,
66 I2C_STATE_W_MORE_TXN_LAST
,
68 I2C_STATE_W_LAST_TXN_ADDR
,
69 I2C_STATE_W_LAST_TXN_MIDDLE
,
70 I2C_STATE_W_LAST_TXN_LAST
,
74 I2C_STATE_NUM_STATES
/* Must be last */
77 enum i2c_adapter_event
{
79 I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY
,
80 I2C_EVENT_TRANSMIT_BUFFER_EMPTY
,
81 I2C_EVENT_TRANSFER_COMPLETE
,
88 I2C_EVENT_NUM_EVENTS
/* Must be last */
91 /* dirty hack to keep compatible with enum in pios_i2c_priv.h */
92 #define I2C_STATE_WRITE_BYTE I2C_STATE_W_MORE_TXN_ADDR
93 #define I2C_STATE_READ_BYTE I2C_STATE_W_MORE_TXN_MIDDLE
94 #define I2C_STATE_TRANSFER_COMPLETE I2C_STATE_W_MORE_TXN_LAST
96 // #define I2C_HALT_ON_ERRORS
98 #if defined(PIOS_I2C_DIAGNOSTICS)
99 static struct pios_i2c_fault_history i2c_adapter_fault_history
;
101 static volatile uint32_t i2c_evirq_history
[I2C_LOG_DEPTH
];
102 static volatile uint8_t i2c_evirq_history_pointer
;
104 static volatile uint32_t i2c_erirq_history
[I2C_LOG_DEPTH
];
105 static volatile uint8_t i2c_erirq_history_pointer
;
107 static volatile uint8_t i2c_state_history
[I2C_LOG_DEPTH
];
108 static volatile uint8_t i2c_state_history_pointer
;
110 static volatile uint8_t i2c_state_event_history
[I2C_LOG_DEPTH
];
111 static volatile uint8_t i2c_state_event_history_pointer
;
113 static uint32_t i2c_fsm_fault_count
;
114 static uint32_t i2c_bad_event_counter
;
115 static uint32_t i2c_error_interrupt_counter
;
116 static uint32_t i2c_nack_counter
;
117 static uint32_t i2c_timeout_counter
;
120 static void go_fsm_fault(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
121 static void go_bus_error(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
122 static void go_stopped(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
123 static void go_starting(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
124 static void go_write_byte(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
125 static void go_read_byte(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
126 static void go_transfer_complete(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
127 static void go_nack(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
129 struct i2c_adapter_transition
{
130 void (*entry_fn
)(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
131 enum i2c_adapter_state next_state
[I2C_EVENT_NUM_EVENTS
];
134 static void i2c_adapter_process_auto(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
);
135 static void i2c_adapter_inject_event(struct pios_i2c_adapter
*i2c_adapter
, enum i2c_adapter_event event
, bool *woken
);
136 static void i2c_adapter_fsm_init(struct pios_i2c_adapter
*i2c_adapter
);
137 static void i2c_adapter_reset_bus(struct pios_i2c_adapter
*i2c_adapter
);
139 #if defined(PIOS_I2C_DIAGNOSTICS)
140 static void i2c_adapter_log_fault(struct pios_i2c_adapter
*i2c_adapter
, enum pios_i2c_error_type type
);
143 static const struct i2c_adapter_transition i2c_adapter_transitions
[I2C_STATE_NUM_STATES
] = {
144 [I2C_STATE_FSM_FAULT
] = {
145 .entry_fn
= go_fsm_fault
,
147 [I2C_EVENT_AUTO
] = I2C_STATE_STOPPED
,
150 [I2C_STATE_BUS_ERROR
] = {
151 .entry_fn
= go_bus_error
,
153 [I2C_EVENT_AUTO
] = I2C_STATE_STOPPED
,
157 [I2C_STATE_STOPPED
] = {
158 .entry_fn
= go_stopped
,
160 [I2C_EVENT_START
] = I2C_STATE_STARTING
,
161 [I2C_EVENT_BUS_ERROR
] = I2C_STATE_BUS_ERROR
,
165 [I2C_STATE_STARTING
] = {
166 .entry_fn
= go_starting
,
168 [I2C_EVENT_TRANSMIT_BUFFER_EMPTY
] = I2C_STATE_WRITE_BYTE
,
169 [I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY
] = I2C_STATE_READ_BYTE
,
170 [I2C_EVENT_NACK
] = I2C_STATE_NACK
,
171 [I2C_EVENT_BUS_ERROR
] = I2C_STATE_BUS_ERROR
,
175 [I2C_STATE_WRITE_BYTE
] = {
176 .entry_fn
= go_write_byte
,
178 [I2C_EVENT_TRANSMIT_BUFFER_EMPTY
] = I2C_STATE_WRITE_BYTE
,
179 [I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY
] = I2C_STATE_READ_BYTE
,
180 [I2C_EVENT_TRANSFER_COMPLETE
] = I2C_STATE_TRANSFER_COMPLETE
,
181 [I2C_EVENT_STOP
] = I2C_STATE_STOPPED
,
182 [I2C_EVENT_BUS_ERROR
] = I2C_STATE_BUS_ERROR
,
186 [I2C_STATE_READ_BYTE
] = {
187 .entry_fn
= go_read_byte
,
189 [I2C_EVENT_TRANSMIT_BUFFER_EMPTY
] = I2C_STATE_WRITE_BYTE
,
190 [I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY
] = I2C_STATE_READ_BYTE
,
191 [I2C_EVENT_TRANSFER_COMPLETE
] = I2C_STATE_TRANSFER_COMPLETE
,
192 [I2C_EVENT_STOP
] = I2C_STATE_STOPPED
,
193 [I2C_EVENT_BUS_ERROR
] = I2C_STATE_BUS_ERROR
,
197 [I2C_STATE_TRANSFER_COMPLETE
] = {
198 .entry_fn
= go_transfer_complete
,
200 [I2C_EVENT_AUTO
] = I2C_STATE_STARTING
,
201 [I2C_EVENT_BUS_ERROR
] = I2C_STATE_BUS_ERROR
,
208 [I2C_EVENT_AUTO
] = I2C_STATE_STOPPED
,
213 static void go_fsm_fault(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
215 #if defined(I2C_HALT_ON_ERRORS)
216 PIOS_DEBUG_Assert(0);
218 /* Note that this transfer has hit a bus error */
219 i2c_adapter
->bus_error
= true;
221 i2c_adapter_reset_bus(i2c_adapter
);
224 static void go_bus_error(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
226 /* Note that this transfer has hit a bus error */
227 i2c_adapter
->bus_error
= true;
229 i2c_adapter_reset_bus(i2c_adapter
);
232 static void go_stopped(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
)
234 I2C_ITConfig(i2c_adapter
->cfg
->regs
, I2C_IT_ERRI
| I2C_IT_TCI
| I2C_IT_NACKI
| I2C_IT_RXI
| I2C_IT_STOPI
| I2C_IT_TXI
, DISABLE
);
236 enum pios_i2c_transfer_result result
=
237 i2c_adapter
->bus_error
? PIOS_I2C_TRANSFER_BUS_ERROR
:
238 i2c_adapter
->nack
? PIOS_I2C_TRANSFER_NACK
:
239 PIOS_I2C_TRANSFER_OK
;
241 if (i2c_adapter
->transfer_result
) {
242 *(i2c_adapter
->transfer_result
) = result
;
245 pios_i2c_callback cb
= i2c_adapter
->callback
;
247 if (!cb
) { /* No callback? Signal that we are done */
248 #ifdef PIOS_INCLUDE_FREERTOS
249 signed portBASE_TYPE pxHigherPriorityTaskWoken
= pdFALSE
;
250 if (xSemaphoreGiveFromISR(i2c_adapter
->sem_ready
, &pxHigherPriorityTaskWoken
) != pdTRUE
) {
251 #if defined(I2C_HALT_ON_ERRORS)
252 PIOS_DEBUG_Assert(0);
255 if (pxHigherPriorityTaskWoken
== pdTRUE
) {
258 #endif /* PIOS_INCLUDE_FREERTOS */
261 #ifdef PIOS_INCLUDE_FREERTOS
263 signed portBASE_TYPE xHigherPriorityTaskWoken
= pdFALSE
;
264 xSemaphoreGiveFromISR(i2c_adapter
->sem_busy
, &xHigherPriorityTaskWoken
);
265 if (xHigherPriorityTaskWoken
== pdTRUE
) {
270 i2c_adapter
->busy
= 0;
272 #endif /* PIOS_INCLUDE_FREERTOS */
274 if (cb
&& cb(result
)) { /* User provided callback? Do it, but with bus unlocked */
279 static void go_starting(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
281 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
);
282 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
<= i2c_adapter
->last_txn
);
283 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
->len
<= 255); // FIXME: implement this using TCR
285 i2c_adapter
->active_byte
= &(i2c_adapter
->active_txn
->buf
[0]);
286 i2c_adapter
->last_byte
= &(i2c_adapter
->active_txn
->buf
[i2c_adapter
->active_txn
->len
- 1]);
288 I2C_ClearITPendingBit(i2c_adapter
->cfg
->regs
, I2C_IT_STOPI
| I2C_IT_NACKI
| I2C_IT_ERRI
);
289 I2C_ITConfig(i2c_adapter
->cfg
->regs
, I2C_IT_ERRI
| I2C_IT_TCI
| I2C_IT_NACKI
| I2C_IT_RXI
| I2C_IT_STOPI
| I2C_IT_TXI
, ENABLE
);
291 I2C_TransferHandling(
292 i2c_adapter
->cfg
->regs
,
293 (i2c_adapter
->active_txn
->addr
<< 1),
294 i2c_adapter
->active_txn
->len
,
295 i2c_adapter
->active_txn
== i2c_adapter
->last_txn
? I2C_AutoEnd_Mode
: I2C_SoftEnd_Mode
,
296 i2c_adapter
->active_txn
->rw
== PIOS_I2C_TXN_WRITE
? I2C_Generate_Start_Write
: I2C_Generate_Start_Read
);
299 static void go_write_byte(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
301 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
);
302 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
<= i2c_adapter
->last_txn
);
304 I2C_SendData(i2c_adapter
->cfg
->regs
, *(i2c_adapter
->active_byte
));
306 /* Move to the next byte */
307 i2c_adapter
->active_byte
++;
308 PIOS_DEBUG_Assert(i2c_adapter
->active_byte
<= i2c_adapter
->last_byte
);
311 static void go_read_byte(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
313 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
);
314 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
<= i2c_adapter
->last_txn
);
316 *(i2c_adapter
->active_byte
) = I2C_ReceiveData(i2c_adapter
->cfg
->regs
);
318 /* Move to the next byte */
319 i2c_adapter
->active_byte
++;
320 PIOS_DEBUG_Assert(i2c_adapter
->active_byte
<= i2c_adapter
->last_byte
);
323 static void go_transfer_complete(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
325 /* Move to the next transaction */
326 i2c_adapter
->active_txn
++;
327 PIOS_DEBUG_Assert(i2c_adapter
->active_txn
<= i2c_adapter
->last_txn
);
330 static void go_nack(struct pios_i2c_adapter
*i2c_adapter
, __attribute__((unused
)) bool *woken
)
332 i2c_adapter
->nack
= true;
333 I2C_ITConfig(i2c_adapter
->cfg
->regs
, I2C_IT_ERRI
| I2C_IT_TCI
| I2C_IT_NACKI
| I2C_IT_RXI
| I2C_IT_STOPI
| I2C_IT_TXI
, DISABLE
);
334 /* It seems that we don't need this with F3 i2c peripheral */
335 // I2C_AcknowledgeConfig(i2c_adapter->cfg->regs, DISABLE);
336 // I2C_GenerateSTOP(i2c_adapter->cfg->regs, ENABLE);
339 static void i2c_adapter_inject_event(struct pios_i2c_adapter
*i2c_adapter
, enum i2c_adapter_event event
, bool *woken
)
341 #if defined(PIOS_I2C_DIAGNOSTICS)
342 i2c_state_event_history
[i2c_state_event_history_pointer
] = event
;
343 i2c_state_event_history_pointer
= (i2c_state_event_history_pointer
+ 1) % I2C_LOG_DEPTH
;
345 i2c_state_history
[i2c_state_history_pointer
] = i2c_adapter
->curr_state
;
346 i2c_state_history_pointer
= (i2c_state_history_pointer
+ 1) % I2C_LOG_DEPTH
;
348 if (i2c_adapter_transitions
[i2c_adapter
->curr_state
].next_state
[event
] == I2C_STATE_FSM_FAULT
) {
349 i2c_adapter_log_fault(i2c_adapter
, PIOS_I2C_ERROR_FSM
);
353 * Move to the next state
355 * This is done prior to calling the new state's entry function to
356 * guarantee that the entry function never depends on the previous
357 * state. This way, it cannot ever know what the previous state was.
359 enum i2c_adapter_state prev_state
= i2c_adapter
->curr_state
;
364 i2c_adapter
->curr_state
= i2c_adapter_transitions
[i2c_adapter
->curr_state
].next_state
[event
];
366 /* Call the entry function (if any) for the next state. */
367 if (i2c_adapter_transitions
[i2c_adapter
->curr_state
].entry_fn
) {
368 i2c_adapter_transitions
[i2c_adapter
->curr_state
].entry_fn(i2c_adapter
, woken
);
371 /* Process any AUTO transitions in the FSM */
372 i2c_adapter_process_auto(i2c_adapter
, woken
);
375 static void i2c_adapter_process_auto(struct pios_i2c_adapter
*i2c_adapter
, bool *woken
)
377 enum i2c_adapter_state prev_state
= i2c_adapter
->curr_state
;
383 while (i2c_adapter_transitions
[i2c_adapter
->curr_state
].next_state
[I2C_EVENT_AUTO
]) {
384 i2c_adapter
->curr_state
= i2c_adapter_transitions
[i2c_adapter
->curr_state
].next_state
[I2C_EVENT_AUTO
];
386 /* Call the entry function (if any) for the next state. */
387 if (i2c_adapter_transitions
[i2c_adapter
->curr_state
].entry_fn
) {
388 i2c_adapter_transitions
[i2c_adapter
->curr_state
].entry_fn(i2c_adapter
, woken
);
393 static void i2c_adapter_fsm_init(struct pios_i2c_adapter
*i2c_adapter
)
395 i2c_adapter_reset_bus(i2c_adapter
);
396 i2c_adapter
->curr_state
= I2C_STATE_STOPPED
;
399 static void i2c_adapter_reset_bus(struct pios_i2c_adapter
*i2c_adapter
)
401 uint8_t retry_count
= 0;
402 uint8_t retry_count_clk
= 0;
403 static const uint8_t MAX_I2C_RETRY_COUNT
= 10;
405 /* Reset the I2C block */
406 I2C_DeInit(i2c_adapter
->cfg
->regs
);
408 /* Make sure the bus is free by clocking it until any slaves release the bus. */
409 GPIO_InitTypeDef scl_gpio_init
;
410 scl_gpio_init
= i2c_adapter
->cfg
->scl
.init
;
411 scl_gpio_init
.GPIO_Mode
= GPIO_Mode_OUT
;
412 GPIO_SetBits(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
);
413 GPIO_Init(i2c_adapter
->cfg
->scl
.gpio
, &scl_gpio_init
);
415 GPIO_InitTypeDef sda_gpio_init
;
416 sda_gpio_init
= i2c_adapter
->cfg
->sda
.init
;
417 sda_gpio_init
.GPIO_Mode
= GPIO_Mode_OUT
;
418 GPIO_SetBits(i2c_adapter
->cfg
->sda
.gpio
, i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
);
419 GPIO_Init(i2c_adapter
->cfg
->sda
.gpio
, &sda_gpio_init
);
421 /* Check SDA line to determine if slave is asserting bus and clock out if so, this may */
422 /* have to be repeated (due to further bus errors) but better than clocking 0xFF into an */
426 while (GPIO_ReadInputDataBit(i2c_adapter
->cfg
->sda
.gpio
, i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
) == Bit_RESET
&& (retry_count_clk
++ < MAX_I2C_RETRY_COUNT
)) {
428 /* Set clock high and wait for any clock stretching to finish. */
429 GPIO_SetBits(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
);
430 while (GPIO_ReadInputDataBit(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
) == Bit_RESET
&& (retry_count
++ < MAX_I2C_RETRY_COUNT
)) {
431 PIOS_DELAY_WaituS(1);
434 PIOS_DELAY_WaituS(2);
437 GPIO_ResetBits(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
);
438 PIOS_DELAY_WaituS(2);
440 /* Clock high again */
441 GPIO_SetBits(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
);
442 PIOS_DELAY_WaituS(2);
445 /* Generate a start then stop condition */
446 GPIO_SetBits(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
);
447 PIOS_DELAY_WaituS(2);
448 GPIO_ResetBits(i2c_adapter
->cfg
->sda
.gpio
, i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
);
449 PIOS_DELAY_WaituS(2);
450 GPIO_ResetBits(i2c_adapter
->cfg
->sda
.gpio
, i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
);
451 PIOS_DELAY_WaituS(2);
453 /* Set data and clock high and wait for any clock stretching to finish. */
454 GPIO_SetBits(i2c_adapter
->cfg
->sda
.gpio
, i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
);
455 GPIO_SetBits(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
);
458 while (GPIO_ReadInputDataBit(i2c_adapter
->cfg
->scl
.gpio
, i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
) == Bit_RESET
&& (retry_count
++ < MAX_I2C_RETRY_COUNT
)) {
459 PIOS_DELAY_WaituS(1);
462 /* Wait for data to be high */
464 while (GPIO_ReadInputDataBit(i2c_adapter
->cfg
->sda
.gpio
, i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
) != Bit_SET
&& (retry_count
++ < MAX_I2C_RETRY_COUNT
)) {
465 PIOS_DELAY_WaituS(1);
468 /* Bus signals are guaranteed to be high (ie. free) after this point */
469 /* Initialize the GPIO pins to the peripheral function */
470 if (i2c_adapter
->cfg
->remapSCL
) {
471 GPIO_PinAFConfig(i2c_adapter
->cfg
->scl
.gpio
,
472 __builtin_ctz(i2c_adapter
->cfg
->scl
.init
.GPIO_Pin
),
473 i2c_adapter
->cfg
->remapSCL
);
475 if (i2c_adapter
->cfg
->remapSDA
) {
476 GPIO_PinAFConfig(i2c_adapter
->cfg
->sda
.gpio
,
477 __builtin_ctz(i2c_adapter
->cfg
->sda
.init
.GPIO_Pin
),
478 i2c_adapter
->cfg
->remapSDA
);
480 GPIO_Init(i2c_adapter
->cfg
->scl
.gpio
, (GPIO_InitTypeDef
*)&(i2c_adapter
->cfg
->scl
.init
)); // Struct is const, function signature not
481 GPIO_Init(i2c_adapter
->cfg
->sda
.gpio
, (GPIO_InitTypeDef
*)&(i2c_adapter
->cfg
->sda
.init
));
483 RCC_I2CCLKConfig(i2c_adapter
->cfg
->regs
== I2C2
? RCC_I2C2CLK_SYSCLK
: RCC_I2C1CLK_SYSCLK
);
485 /* Reset the I2C block */
486 I2C_DeInit(i2c_adapter
->cfg
->regs
);
488 /* Initialize the I2C block */
489 I2C_Init(i2c_adapter
->cfg
->regs
, (I2C_InitTypeDef
*)&(i2c_adapter
->cfg
->init
));
491 /* Enable the I2C block */
492 I2C_Cmd(i2c_adapter
->cfg
->regs
, ENABLE
);
494 if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_BUSY
)) {
495 I2C_SoftwareResetCmd(i2c_adapter
->cfg
->regs
);
500 * Logs the last N state transitions and N IRQ events due to
502 * \param[in] i2c the adapter number to log an event for
504 #if defined(PIOS_I2C_DIAGNOSTICS)
505 void i2c_adapter_log_fault(__attribute__((unused
)) struct pios_i2c_adapter
*i2c_adapter
, enum pios_i2c_error_type type
)
507 i2c_adapter_fault_history
.type
= type
;
508 for (uint8_t i
= 0; i
< I2C_LOG_DEPTH
; i
++) {
509 i2c_adapter_fault_history
.evirq
[i
] =
510 i2c_evirq_history
[(I2C_LOG_DEPTH
+ i2c_evirq_history_pointer
- 1 - i
) % I2C_LOG_DEPTH
];
511 i2c_adapter_fault_history
.erirq
[i
] =
512 i2c_erirq_history
[(I2C_LOG_DEPTH
+ i2c_erirq_history_pointer
- 1 - i
) % I2C_LOG_DEPTH
];
513 i2c_adapter_fault_history
.event
[i
] =
514 i2c_state_event_history
[(I2C_LOG_DEPTH
+ i2c_state_event_history_pointer
- 1 - i
) % I2C_LOG_DEPTH
];
515 i2c_adapter_fault_history
.state
[i
] =
516 i2c_state_history
[(I2C_LOG_DEPTH
+ i2c_state_history_pointer
- 1 - i
) % I2C_LOG_DEPTH
];
519 case PIOS_I2C_ERROR_EVENT
:
520 i2c_bad_event_counter
++;
522 case PIOS_I2C_ERROR_FSM
:
523 i2c_fsm_fault_count
++;
525 case PIOS_I2C_ERROR_INTERRUPT
:
526 i2c_error_interrupt_counter
++;
530 #endif /* if defined(PIOS_I2C_DIAGNOSTICS) */
533 * Logs the last N state transitions and N IRQ events due to
535 * \param[out] data address where to copy the pios_i2c_fault_history structure to
536 * \param[out] counts three uint16 that receive the bad event, fsm, and error irq
539 void PIOS_I2C_GetDiagnostics(struct pios_i2c_fault_history
*data
, uint8_t *counts
)
541 #if defined(PIOS_I2C_DIAGNOSTICS)
542 memcpy(data
, &i2c_adapter_fault_history
, sizeof(i2c_adapter_fault_history
));
543 counts
[PIOS_I2C_BAD_EVENT_COUNTER
] = i2c_bad_event_counter
;
544 counts
[PIOS_I2C_FSM_FAULT_COUNT
] = i2c_fsm_fault_count
;
545 counts
[PIOS_I2C_ERROR_INTERRUPT_COUNTER
] = i2c_error_interrupt_counter
;
546 counts
[PIOS_I2C_NACK_COUNTER
] = i2c_nack_counter
;
547 counts
[PIOS_I2C_TIMEOUT_COUNTER
] = i2c_timeout_counter
;
549 struct pios_i2c_fault_history i2c_adapter_fault_history
;
550 i2c_adapter_fault_history
.type
= PIOS_I2C_ERROR_EVENT
;
552 memcpy(data
, &i2c_adapter_fault_history
, sizeof(i2c_adapter_fault_history
));
553 memset(counts
, 0, sizeof(*counts
) * PIOS_I2C_ERROR_COUNT_NUMELEM
);
557 static bool PIOS_I2C_validate(struct pios_i2c_adapter
*i2c_adapter
)
559 return i2c_adapter
->magic
== PIOS_I2C_DEV_MAGIC
;
562 #if defined(PIOS_INCLUDE_FREERTOS)
563 static struct pios_i2c_adapter
*PIOS_I2C_alloc(void)
565 struct pios_i2c_adapter
*i2c_adapter
;
567 i2c_adapter
= (struct pios_i2c_adapter
*)pios_malloc(sizeof(*i2c_adapter
));
572 i2c_adapter
->magic
= PIOS_I2C_DEV_MAGIC
;
576 static struct pios_i2c_adapter pios_i2c_adapters
[PIOS_I2C_MAX_DEVS
];
577 static uint8_t pios_i2c_num_adapters
;
578 static struct pios_i2c_adapter
*PIOS_I2C_alloc(void)
580 struct pios_i2c_adapter
*i2c_adapter
;
582 if (pios_i2c_num_adapters
>= PIOS_I2C_MAX_DEVS
) {
586 i2c_adapter
= &pios_i2c_adapters
[pios_i2c_num_adapters
++];
587 i2c_adapter
->magic
= PIOS_I2C_DEV_MAGIC
;
591 #endif /* if defined(PIOS_INCLUDE_CHIBIOS) && 0 */
595 * Initializes IIC driver
596 * \param[in] mode currently only mode 0 supported
597 * \return < 0 if initialisation failed
599 int32_t PIOS_I2C_Init(uint32_t *i2c_id
, const struct pios_i2c_adapter_cfg
*cfg
)
601 PIOS_DEBUG_Assert(i2c_id
);
602 PIOS_DEBUG_Assert(cfg
);
604 struct pios_i2c_adapter
*i2c_adapter
;
606 i2c_adapter
= (struct pios_i2c_adapter
*)PIOS_I2C_alloc();
611 /* Bind the configuration to the device instance */
612 i2c_adapter
->cfg
= cfg
;
614 vSemaphoreCreateBinary(i2c_adapter
->sem_ready
);
615 i2c_adapter
->sem_busy
= xSemaphoreCreateMutex();
617 /* Initialize the state machine */
618 i2c_adapter_fsm_init(i2c_adapter
);
620 *i2c_id
= (uint32_t)i2c_adapter
;
622 /* Configure and enable I2C interrupts */
623 NVIC_Init((NVIC_InitTypeDef
*)&(i2c_adapter
->cfg
->event
.init
));
624 NVIC_Init((NVIC_InitTypeDef
*)&(i2c_adapter
->cfg
->error
.init
));
633 int32_t PIOS_I2C_Transfer(uint32_t i2c_id
, const struct pios_i2c_txn txn_list
[], uint32_t num_txns
)
635 // FIXME: only supports transfer sizes up to 255 bytes
636 struct pios_i2c_adapter
*i2c_adapter
= (struct pios_i2c_adapter
*)i2c_id
;
637 enum pios_i2c_transfer_result result
= PIOS_I2C_TRANSFER_UNSPECIFIED_ERROR
;
639 bool valid
= PIOS_I2C_validate(i2c_adapter
);
643 PIOS_DEBUG_Assert(txn_list
);
644 PIOS_DEBUG_Assert(num_txns
);
646 bool semaphore_success
= true;
648 #ifdef PIOS_INCLUDE_FREERTOS
650 portTickType timeout
;
651 timeout
= i2c_adapter
->cfg
->transfer_timeout_ms
/ portTICK_RATE_MS
;
652 if (xSemaphoreTake(i2c_adapter
->sem_busy
, timeout
) == pdFALSE
) {
653 return PIOS_I2C_TRANSFER_BUSY
;
657 if (i2c_adapter
->busy
) {
659 return PIOS_I2C_TRANSFER_BUSY
;
661 i2c_adapter
->busy
= 1;
663 #endif /* PIOS_INCLUDE_FREERTOS */
665 PIOS_DEBUG_Assert(i2c_adapter
->curr_state
== I2C_STATE_STOPPED
);
667 i2c_adapter
->transfer_result
= &result
;
668 i2c_adapter
->last_txn
= &txn_list
[num_txns
- 1];
669 i2c_adapter
->active_txn
= &txn_list
[0];
670 i2c_adapter
->bus_error
= false;
671 i2c_adapter
->nack
= false;
673 #ifdef PIOS_INCLUDE_FREERTOS
674 /* Make sure the done/ready semaphore is consumed before we start */
675 semaphore_success
&= (xSemaphoreTake(i2c_adapter
->sem_ready
, timeout
) == pdTRUE
);
678 i2c_adapter
->callback
= NULL
;
681 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_START
, &dummy
);
683 /* Wait for the transfer to complete */
684 #ifdef PIOS_INCLUDE_FREERTOS
685 semaphore_success
&= (xSemaphoreTake(i2c_adapter
->sem_ready
, timeout
) == pdTRUE
);
686 xSemaphoreGive(i2c_adapter
->sem_ready
);
687 #endif /* PIOS_INCLUDE_FREERTOS */
689 /* After this point, the bus is already unlocked from ISR
690 * Touching i2c_adapter is not allowed */
691 #if defined(PIOS_I2C_DIAGNOSTICS)
692 if (!semaphore_success
) {
693 i2c_timeout_counter
++;
694 result
= PIOS_I2C_TRANSFER_TIMEOUT
;
700 static int32_t PIOS_I2C_Transfer_Callback_Internal(struct pios_i2c_adapter
*i2c_adapter
, const struct pios_i2c_txn txn_list
[], uint32_t num_txns
, pios_i2c_callback callback
)
702 PIOS_DEBUG_Assert(i2c_adapter
->curr_state
== I2C_STATE_STOPPED
);
704 i2c_adapter
->transfer_result
= 0;
705 i2c_adapter
->last_txn
= &txn_list
[num_txns
- 1];
706 i2c_adapter
->active_txn
= &txn_list
[0];
707 i2c_adapter
->bus_error
= false;
708 i2c_adapter
->nack
= false;
709 i2c_adapter
->callback
= callback
;
711 // Estimate bytes of transmission. Per txns: 1 adress byte + length
712 i2c_adapter
->transfer_timeout_ticks
= num_txns
;
713 for (uint32_t i
= 0; i
< num_txns
; i
++) {
714 i2c_adapter
->transfer_timeout_ticks
+= txn_list
[i
].len
;
716 // timeout if it takes eight times the expected time
717 i2c_adapter
->transfer_timeout_ticks
<<= 3;
720 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_START
, &dummy
);
725 int32_t PIOS_I2C_Transfer_Callback(uint32_t i2c_id
, const struct pios_i2c_txn txn_list
[], uint32_t num_txns
, pios_i2c_callback callback
)
727 // FIXME: only supports transfer sizes up to 255 bytes
728 struct pios_i2c_adapter
*i2c_adapter
= (struct pios_i2c_adapter
*)i2c_id
;
730 bool valid
= PIOS_I2C_validate(i2c_adapter
);
734 PIOS_DEBUG_Assert(txn_list
);
735 PIOS_DEBUG_Assert(num_txns
);
737 #ifdef PIOS_INCLUDE_FREERTOS
739 portTickType timeout
;
740 timeout
= i2c_adapter
->cfg
->transfer_timeout_ms
/ portTICK_RATE_MS
;
741 if (xSemaphoreTake(i2c_adapter
->sem_busy
, timeout
) == pdFALSE
) {
746 if (i2c_adapter
->busy
) {
750 i2c_adapter
->busy
= 1;
752 #endif /* PIOS_INCLUDE_FREERTOS */
754 return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter
, txn_list
, num_txns
, callback
);
757 int32_t PIOS_I2C_Transfer_CallbackFromISR(uint32_t i2c_id
, const struct pios_i2c_txn txn_list
[], uint32_t num_txns
, pios_i2c_callback callback
, bool *woken
)
759 // FIXME: only supports transfer sizes up to 255 bytes
760 struct pios_i2c_adapter
*i2c_adapter
= (struct pios_i2c_adapter
*)i2c_id
;
762 bool valid
= PIOS_I2C_validate(i2c_adapter
);
766 PIOS_DEBUG_Assert(txn_list
);
767 PIOS_DEBUG_Assert(num_txns
);
769 #ifdef PIOS_INCLUDE_FREERTOS
770 signed portBASE_TYPE xHigherPriorityTaskWoken
= pdFALSE
;
773 bool locked
= xSemaphoreTakeFromISR(i2c_adapter
->sem_busy
, &xHigherPriorityTaskWoken
) == pdTRUE
;
775 if (xHigherPriorityTaskWoken
== pdTRUE
) {
784 if (i2c_adapter
->busy
) {
788 i2c_adapter
->busy
= 1;
790 #endif /* PIOS_INCLUDE_FREERTOS */
792 return PIOS_I2C_Transfer_Callback_Internal(i2c_adapter
, txn_list
, num_txns
, callback
);
795 void PIOS_I2C_EV_IRQ_Handler(uint32_t i2c_id
)
797 struct pios_i2c_adapter
*i2c_adapter
= (struct pios_i2c_adapter
*)i2c_id
;
799 bool valid
= PIOS_I2C_validate(i2c_adapter
);
805 if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_RXNE
)) {
806 // flag will be cleared by event
807 #if defined(PIOS_I2C_DIAGNOSTICS)
808 i2c_evirq_history
[i2c_evirq_history_pointer
] = I2C_FLAG_RXNE
;
809 i2c_evirq_history_pointer
= (i2c_evirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
811 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY
, &woken
);
812 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_TXIS
)) {
813 // flag will be cleared by event
814 #if defined(PIOS_I2C_DIAGNOSTICS)
815 i2c_evirq_history
[i2c_evirq_history_pointer
] = I2C_FLAG_TXIS
;
816 i2c_evirq_history_pointer
= (i2c_evirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
818 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_TRANSMIT_BUFFER_EMPTY
, &woken
);
819 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_NACKF
)) {
820 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_NACKF
);
821 #if defined(PIOS_I2C_DIAGNOSTICS)
822 i2c_evirq_history
[i2c_evirq_history_pointer
] = I2C_FLAG_NACKF
;
823 i2c_evirq_history_pointer
= (i2c_evirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
826 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_NACK
, &woken
);
827 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_TC
)) {
828 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_TC
);
829 #if defined(PIOS_I2C_DIAGNOSTICS)
830 i2c_evirq_history
[i2c_evirq_history_pointer
] = I2C_FLAG_TC
;
831 i2c_evirq_history_pointer
= (i2c_evirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
833 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_TRANSFER_COMPLETE
, &woken
);
834 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_STOPF
)) {
835 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_STOPF
);
836 #if defined(PIOS_I2C_DIAGNOSTICS)
837 i2c_evirq_history
[i2c_evirq_history_pointer
] = I2C_FLAG_STOPF
;
838 i2c_evirq_history_pointer
= (i2c_evirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
840 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_STOP
, &woken
);
843 portEND_SWITCHING_ISR(woken
? pdTRUE
: pdFALSE
);
847 void PIOS_I2C_ER_IRQ_Handler(uint32_t i2c_id
)
849 struct pios_i2c_adapter
*i2c_adapter
= (struct pios_i2c_adapter
*)i2c_id
;
851 bool valid
= PIOS_I2C_validate(i2c_adapter
);
855 else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_BERR
)) {
856 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_BERR
);
857 #if defined(PIOS_I2C_DIAGNOSTICS)
858 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_BERR
;
859 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
861 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_ARLO
)) {
862 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_ARLO
);
863 #if defined(PIOS_I2C_DIAGNOSTICS)
864 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_ARLO
;
865 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
867 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_OVR
)) {
868 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_OVR
);
869 #if defined(PIOS_I2C_DIAGNOSTICS)
870 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_OVR
;
871 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
873 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_PECERR
)) {
874 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_PECERR
);
875 #if defined(PIOS_I2C_DIAGNOSTICS)
876 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_PECERR
;
877 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
879 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_TIMEOUT
)) {
880 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_TIMEOUT
);
881 #if defined(PIOS_I2C_DIAGNOSTICS)
882 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_TIMEOUT
;
883 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
885 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_ALERT
)) {
886 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_ALERT
);
887 #if defined(PIOS_I2C_DIAGNOSTICS)
888 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_ALERT
;
889 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
891 } else if (I2C_GetFlagStatus(i2c_adapter
->cfg
->regs
, I2C_FLAG_BUSY
)) {
892 I2C_ClearFlag(i2c_adapter
->cfg
->regs
, I2C_FLAG_BUSY
);
893 #if defined(PIOS_I2C_DIAGNOSTICS)
894 i2c_erirq_history
[i2c_erirq_history_pointer
] = I2C_FLAG_BUSY
;
895 i2c_erirq_history_pointer
= (i2c_erirq_history_pointer
+ 1) % I2C_LOG_DEPTH
;
899 #if defined(PIOS_I2C_DIAGNOSTICS)
900 i2c_adapter_log_fault(i2c_adapter
, PIOS_I2C_ERROR_INTERRUPT
);
903 /* Fail hard on any errors for now */
905 i2c_adapter_inject_event(i2c_adapter
, I2C_EVENT_BUS_ERROR
, &woken
);
907 portEND_SWITCHING_ISR(woken
? pdTRUE
: pdFALSE
);
910 #endif /* if defined(PIOS_INCLUDE_I2C) */