update credits
[librepilot.git] / flight / pios / stm32f30x / pios_i2c.c
blobf269f96bb33d853007ba3db6519fdd6481e0834b
1 /**
2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
4 * @{
5 * @addtogroup PIOS_I2C I2C Functions
6 * @brief STM32F30x Hardware dependent I2C functionality
7 * @{
9 * @file pios_i2c.c
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
27 * for more details.
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 */
35 #include "pios.h"
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 */
44 I2C_STATE_BUS_ERROR,
46 I2C_STATE_STOPPED,
47 I2C_STATE_STOPPING,
48 I2C_STATE_STARTING,
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,
72 I2C_STATE_NACK,
74 I2C_STATE_NUM_STATES /* Must be last */
77 enum i2c_adapter_event {
78 I2C_EVENT_START,
79 I2C_EVENT_RECEIVER_BUFFER_NOT_EMPTY,
80 I2C_EVENT_TRANSMIT_BUFFER_EMPTY,
81 I2C_EVENT_TRANSFER_COMPLETE,
82 I2C_EVENT_STOP,
83 I2C_EVENT_NACK,
84 I2C_EVENT_BUS_ERROR,
85 I2C_EVENT_STOPPED,
86 I2C_EVENT_AUTO,
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;
118 #endif
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);
141 #endif
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,
146 .next_state = {
147 [I2C_EVENT_AUTO] = I2C_STATE_STOPPED,
150 [I2C_STATE_BUS_ERROR] = {
151 .entry_fn = go_bus_error,
152 .next_state = {
153 [I2C_EVENT_AUTO] = I2C_STATE_STOPPED,
157 [I2C_STATE_STOPPED] = {
158 .entry_fn = go_stopped,
159 .next_state = {
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,
167 .next_state = {
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,
177 .next_state = {
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,
188 .next_state = {
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,
199 .next_state = {
200 [I2C_EVENT_AUTO] = I2C_STATE_STARTING,
201 [I2C_EVENT_BUS_ERROR] = I2C_STATE_BUS_ERROR,
205 [I2C_STATE_NACK] = {
206 .entry_fn = go_nack,
207 .next_state = {
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);
217 #endif
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);
253 #endif
255 if (pxHigherPriorityTaskWoken == pdTRUE) {
256 *woken = true;
258 #endif /* PIOS_INCLUDE_FREERTOS */
261 #ifdef PIOS_INCLUDE_FREERTOS
262 /* Unlock the bus */
263 signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
264 xSemaphoreGiveFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken);
265 if (xHigherPriorityTaskWoken == pdTRUE) {
266 *woken = true;
268 #else
269 PIOS_IRQ_Disable();
270 i2c_adapter->busy = 0;
271 PIOS_IRQ_Enable();
272 #endif /* PIOS_INCLUDE_FREERTOS */
274 if (cb && cb(result)) { /* User provided callback? Do it, but with bus unlocked */
275 *woken = true;
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);
351 #endif
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;
360 if (prev_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;
379 if (prev_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 */
423 /* ESC */
425 retry_count_clk = 0;
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)) {
427 retry_count = 0;
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);
436 /* Set clock low */
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);
457 retry_count = 0;
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 */
463 retry_count = 0;
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
501 * an error condition
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];
518 switch (type) {
519 case PIOS_I2C_ERROR_EVENT:
520 i2c_bad_event_counter++;
521 break;
522 case PIOS_I2C_ERROR_FSM:
523 i2c_fsm_fault_count++;
524 break;
525 case PIOS_I2C_ERROR_INTERRUPT:
526 i2c_error_interrupt_counter++;
527 break;
530 #endif /* if defined(PIOS_I2C_DIAGNOSTICS) */
533 * Logs the last N state transitions and N IRQ events due to
534 * an error condition
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
537 * counts
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;
548 #else
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);
554 #endif
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));
568 if (!i2c_adapter) {
569 return NULL;
572 i2c_adapter->magic = PIOS_I2C_DEV_MAGIC;
573 return i2c_adapter;
575 #else
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) {
583 return NULL;
586 i2c_adapter = &pios_i2c_adapters[pios_i2c_num_adapters++];
587 i2c_adapter->magic = PIOS_I2C_DEV_MAGIC;
589 return i2c_adapter;
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();
607 if (!i2c_adapter) {
608 goto out_fail;
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));
626 /* No error */
627 return 0;
629 out_fail:
630 return -1;
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);
641 PIOS_Assert(valid)
643 PIOS_DEBUG_Assert(txn_list);
644 PIOS_DEBUG_Assert(num_txns);
646 bool semaphore_success = true;
648 #ifdef PIOS_INCLUDE_FREERTOS
649 /* Lock the bus */
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;
655 #else
656 PIOS_IRQ_Disable();
657 if (i2c_adapter->busy) {
658 PIOS_IRQ_Enable();
659 return PIOS_I2C_TRANSFER_BUSY;
661 i2c_adapter->busy = 1;
662 PIOS_IRQ_Enable();
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);
676 #endif
678 i2c_adapter->callback = NULL;
680 bool dummy = false;
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;
696 #endif
697 return result;
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;
719 bool dummy = false;
720 i2c_adapter_inject_event(i2c_adapter, I2C_EVENT_START, &dummy);
722 return 0;
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);
732 PIOS_Assert(valid)
734 PIOS_DEBUG_Assert(txn_list);
735 PIOS_DEBUG_Assert(num_txns);
737 #ifdef PIOS_INCLUDE_FREERTOS
738 /* Lock the bus */
739 portTickType timeout;
740 timeout = i2c_adapter->cfg->transfer_timeout_ms / portTICK_RATE_MS;
741 if (xSemaphoreTake(i2c_adapter->sem_busy, timeout) == pdFALSE) {
742 return -2;
744 #else
745 PIOS_IRQ_Disable();
746 if (i2c_adapter->busy) {
747 PIOS_IRQ_Enable();
748 return -2;
750 i2c_adapter->busy = 1;
751 PIOS_IRQ_Enable();
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);
764 PIOS_Assert(valid)
766 PIOS_DEBUG_Assert(txn_list);
767 PIOS_DEBUG_Assert(num_txns);
769 #ifdef PIOS_INCLUDE_FREERTOS
770 signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
772 /* Lock the bus */
773 bool locked = xSemaphoreTakeFromISR(i2c_adapter->sem_busy, &xHigherPriorityTaskWoken) == pdTRUE;
775 if (xHigherPriorityTaskWoken == pdTRUE) {
776 *woken = true;
779 if (!locked) {
780 return -2;
782 #else
783 PIOS_IRQ_Disable();
784 if (i2c_adapter->busy) {
785 PIOS_IRQ_Enable();
786 return -2;
788 i2c_adapter->busy = 1;
789 PIOS_IRQ_Enable();
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);
801 PIOS_Assert(valid)
803 bool woken = false;
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;
810 #endif
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;
817 #endif
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;
824 ++i2c_nack_counter;
825 #endif
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;
832 #endif
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;
839 #endif
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);
853 PIOS_Assert(valid)
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;
860 #endif
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;
866 #endif
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;
872 #endif
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;
878 #endif
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;
884 #endif
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;
890 #endif
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;
896 #endif
899 #if defined(PIOS_I2C_DIAGNOSTICS)
900 i2c_adapter_log_fault(i2c_adapter, PIOS_I2C_ERROR_INTERRUPT);
901 #endif
903 /* Fail hard on any errors for now */
904 bool woken = false;
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) */
913 * @}
914 * @}