Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
i2c_arch.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 AggieAir, A Remote Sensing Unmanned Aerial System for Scientific Applications
3  * Utah State University, http://aggieair.usu.edu/
4  *
5  * Michal Podhradsky (michal.podhradsky@aggiemail.usu.edu)
6  * Calvin Coopmans (c.r.coopmans@ieee.org)
7  *
8  * Copyright (C) 2015 Gautier Hattenberger, Alexandre Bustico
9  *
10  * This file is part of paparazzi.
11  *
12  * paparazzi is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2, or (at your option)
15  * any later version.
16  *
17  * paparazzi is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with paparazzi; see the file COPYING. If not, write to
24  * the Free Software Foundation, 59 Temple Place - Suite 330,
25  * Boston, MA 02111-1307, USA.
26  */
34 #include "mcu_periph/i2c_arch.h"
35 #include "mcu_periph/i2c.h"
36 
37 #include BOARD_CONFIG
38 
39 #include <ch.h>
40 #include <hal.h>
41 #include "mcu_periph/ram_arch.h"
42 #include "string.h"
43 
44 // Default stack size
45 #ifndef I2C_THREAD_STACK_SIZE
46 #define I2C_THREAD_STACK_SIZE 512
47 #endif
48 
49 
50 static bool i2c_chibios_idle(struct i2c_periph *p) __attribute__((unused));
51 static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t) __attribute__((unused));
52 static void i2c_chibios_setbitrate(struct i2c_periph *p, int bitrate) __attribute__((unused));
53 
54 
55 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
56 
57 // private I2C init structure
58 struct i2c_init {
59  semaphore_t *sem;
60  I2CConfig *cfg;
61 #ifdef STM32F7
62  uint8_t *dma_buf;
63 #endif
64 };
65 
66 
67 static void handle_i2c_thd(struct i2c_periph *p);
68 
69 // Timeout for I2C transaction
70 static const systime_t tmo = TIME_US2I(10000000 / PERIODIC_FREQUENCY);
71 
77 static void handle_i2c_thd(struct i2c_periph *p)
78 {
79  struct i2c_init *i = (struct i2c_init *) p->init_struct;
80 
81  // wait for a transaction to be pushed in the queue
82  chSemWait(i->sem);
83 
84  if (p->trans_insert_idx == p->trans_extract_idx) {
85  p->status = I2CIdle;
86  // no transaction pending
87  return;
88  }
89 
90  // Get next transation in queue
91  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
92 
93  p->status = I2CStartRequested;
94  msg_t status;
95  // submit i2c transaction (R/W or R only depending of len_w)
96  if (t->len_w > 0) {
97 #if defined STM32F7
98  // we do stupid mem copy because F7 needs a special RAM for DMA operation
99  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
100  status = i2cMasterTransmitTimeout(
101  (I2CDriver *)p->reg_addr,
102  (i2caddr_t)((t->slave_addr) >> 1),
103  (uint8_t *)i->dma_buf, (size_t)(t->len_w),
104  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
105  tmo);
106  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
107 #else
108  status = i2cMasterTransmitTimeout(
109  (I2CDriver *)p->reg_addr,
110  (i2caddr_t)((t->slave_addr) >> 1),
111  (uint8_t *)t->buf, (size_t)(t->len_w),
112  (uint8_t *)t->buf, (size_t)(t->len_r),
113  tmo);
114 #endif
115  } else {
116 #if defined STM32F7
117  // we do stupid mem copy because F7 needs a special RAM for DMA operation
118  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
119  status = i2cMasterReceiveTimeout(
120  (I2CDriver *)p->reg_addr,
121  (i2caddr_t)((t->slave_addr) >> 1),
122  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
123  tmo);
124  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
125 #else
126  status = i2cMasterReceiveTimeout(
127  (I2CDriver *)p->reg_addr,
128  (i2caddr_t)((t->slave_addr) >> 1),
129  (uint8_t *)t->buf, (size_t)(t->len_r),
130  tmo);
131 #endif
132  }
133 
134  chSysLock();
135  // end of transaction, handle fifo
136  p->trans_extract_idx++;
137  if (p->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN) {
138  p->trans_extract_idx = 0;
139  }
140  p->status = I2CIdle;
141  chSysUnlock();
142 
143  // Set report status and errors
144  switch (status) {
145  case MSG_OK:
146  //if the function succeeded
147  t->status = I2CTransSuccess;
148  break;
149  case MSG_TIMEOUT:
150  //if a timeout occurred before operation end
151  // mark as failed and restart
152  t->status = I2CTransFailed;
153  i2cStart((I2CDriver *)p->reg_addr, i->cfg);
154  break;
155  case MSG_RESET:
156  //if one or more I2C errors occurred, the errors can
157  //be retrieved using @p i2cGetErrors().
158  t->status = I2CTransFailed;
159  i2cflags_t errors = i2cGetErrors((I2CDriver *)p->reg_addr);
160  if (errors & I2C_BUS_ERROR) {
161  p->errors->miss_start_stop_cnt++;
162  }
163  if (errors & I2C_ARBITRATION_LOST) {
164  p->errors->arb_lost_cnt++;
165  }
166  if (errors & I2C_ACK_FAILURE) {
167  p->errors->ack_fail_cnt++;
168  }
169  if (errors & I2C_OVERRUN) {
170  p->errors->over_under_cnt++;
171  }
172  if (errors & I2C_PEC_ERROR) {
173  p->errors->pec_recep_cnt++;
174  }
175  if (errors & I2C_TIMEOUT) {
176  p->errors->timeout_tlow_cnt++;
177  }
178  if (errors & I2C_SMB_ALERT) {
179  p->errors->smbus_alert_cnt++;
180  }
181  break;
182  default:
183  break;
184  }
185 }
186 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
187 
188 #if USE_I2C1
189 // I2C1 config
190 PRINT_CONFIG_VAR(I2C1_CLOCK_SPEED)
191 static SEMAPHORE_DECL(i2c1_sem, 0);
192 static I2CConfig i2cfg1 = I2C1_CFG_DEF;
193 #if defined STM32F7
194 // We need a special buffer for DMA operations
195 static IN_DMA_SECTION(uint8_t i2c1_dma_buf[I2C_BUF_LEN]);
196 static struct i2c_init i2c1_init_s = {
197  .sem = &i2c1_sem,
198  .cfg = &i2cfg1,
199  .dma_buf = i2c1_dma_buf
200 };
201 #else
202 static struct i2c_init i2c1_init_s = {
203  .sem = &i2c1_sem,
204  .cfg = &i2cfg1
205 };
206 #endif
207 // Errors
208 struct i2c_errors i2c1_errors;
209 // Thread
210 static __attribute__((noreturn)) void thd_i2c1(void *arg);
211 static THD_WORKING_AREA(wa_thd_i2c1, I2C_THREAD_STACK_SIZE);
212 
213 /*
214  * I2C1 init
215  */
216 void i2c1_hw_init(void)
217 {
218  i2c1.idle = i2c_chibios_idle;
219  i2c1.submit = i2c_chibios_submit;
220  i2c1.setbitrate = i2c_chibios_setbitrate;
221 
222  i2cStart(&I2CD1, &i2cfg1);
223  i2c1.reg_addr = &I2CD1;
224  i2c1.errors = &i2c1_errors;
225  i2c1.init_struct = &i2c1_init_s;
226  // Create thread
227  chThdCreateStatic(wa_thd_i2c1, sizeof(wa_thd_i2c1),
228  NORMALPRIO + 1, thd_i2c1, NULL);
229 }
230 
231 /*
232  * I2C1 thread
233  *
234  */
235 static void thd_i2c1(void *arg)
236 {
237  (void) arg;
238  chRegSetThreadName("i2c1");
239 
240  while (TRUE) {
241  handle_i2c_thd(&i2c1);
242  }
243 }
244 #endif /* USE_I2C1 */
245 
246 #if USE_I2C2
247 // I2C2 config
248 PRINT_CONFIG_VAR(I2C2_CLOCK_SPEED)
249 static SEMAPHORE_DECL(i2c2_sem, 0);
250 static I2CConfig i2cfg2 = I2C2_CFG_DEF;
251 #if defined STM32F7
252 // We need a special buffer for DMA operations
253 static IN_DMA_SECTION(uint8_t i2c2_dma_buf[I2C_BUF_LEN]);
254 static struct i2c_init i2c2_init_s = {
255  .sem = &i2c2_sem,
256  .cfg = &i2cfg2,
257  .dma_buf = i2c2_dma_buf
258 };
259 #else
260 static struct i2c_init i2c2_init_s = {
261  .sem = &i2c2_sem,
262  .cfg = &i2cfg2
263 };
264 #endif
265 // Errors
266 struct i2c_errors i2c2_errors;
267 // Thread
268 static __attribute__((noreturn)) void thd_i2c2(void *arg);
269 static THD_WORKING_AREA(wa_thd_i2c2, I2C_THREAD_STACK_SIZE);
270 
271 /*
272  * I2C2 init
273  */
274 void i2c2_hw_init(void)
275 {
276  i2c2.idle = i2c_chibios_idle;
277  i2c2.submit = i2c_chibios_submit;
278  i2c2.setbitrate = i2c_chibios_setbitrate;
279 
280  i2cStart(&I2CD2, &i2cfg2);
281  i2c2.reg_addr = &I2CD2;
282  i2c2.errors = &i2c2_errors;
283  i2c2.init_struct = &i2c2_init_s;
284  // Create thread
285  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
286  NORMALPRIO + 1, thd_i2c2, NULL);
287 }
288 
289 /*
290  * I2C2 thread
291  *
292  */
293 static void thd_i2c2(void *arg)
294 {
295  (void) arg;
296  chRegSetThreadName("i2c2");
297 
298  while (TRUE) {
299  handle_i2c_thd(&i2c2);
300  }
301 }
302 #endif /* USE_I2C2 */
303 
304 #if USE_I2C3
305 // I2C3 config
306 PRINT_CONFIG_VAR(I2C3_CLOCK_SPEED)
307 static SEMAPHORE_DECL(i2c3_sem, 0);
308 static I2CConfig i2cfg3 = I2C3_CFG_DEF;
309 #if defined STM32F7
310 // We need a special buffer for DMA operations
311 static IN_DMA_SECTION(uint8_t i2c3_dma_buf[I2C_BUF_LEN]);
312 static struct i2c_init i2c3_init_s = {
313  .sem = &i2c3_sem,
314  .cfg = &i2cfg3,
315  .dma_buf = i2c3_dma_buf
316 };
317 #else
318 static struct i2c_init i2c3_init_s = {
319  .sem = &i2c3_sem,
320  .cfg = &i2cfg3
321 };
322 #endif
323 // Errors
324 struct i2c_errors i2c3_errors;
325 // Thread
326 static __attribute__((noreturn)) void thd_i2c3(void *arg);
327 static THD_WORKING_AREA(wa_thd_i2c3, I2C_THREAD_STACK_SIZE);
328 
329 /*
330  * I2C3 init
331  */
332 void i2c3_hw_init(void)
333 {
334  i2c3.idle = i2c_chibios_idle;
335  i2c3.submit = i2c_chibios_submit;
336  i2c3.setbitrate = i2c_chibios_setbitrate;
337 
338  i2cStart(&I2CD3, &i2cfg3);
339  i2c3.reg_addr = &I2CD3;
340  i2c3.init_struct = NULL;
341  i2c3.errors = &i2c3_errors;
342  i2c3.init_struct = &i2c3_init_s;
343  // Create thread
344  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
345  NORMALPRIO + 1, thd_i2c3, NULL);
346 }
347 
348 /*
349  * I2C3 thread
350  *
351  */
352 static void thd_i2c3(void *arg)
353 {
354  (void) arg;
355  chRegSetThreadName("i2c3");
356 
357  while (TRUE) {
358  handle_i2c_thd(&i2c3);
359  }
360 }
361 #endif /* USE_I2C3 */
362 
363 #if USE_I2C4
364 // I2C4 config
365 PRINT_CONFIG_VAR(I2C4_CLOCK_SPEED)
366 static SEMAPHORE_DECL(i2c4_sem, 0);
367 static I2CConfig i2cfg4 = I2C4_CFG_DEF;
368 #if defined STM32F7
369 // We need a special buffer for DMA operations
370 static IN_DMA_SECTION(uint8_t i2c4_dma_buf[I2C_BUF_LEN]);
371 static struct i2c_init i2c4_init_s = {
372  .sem = &i2c4_sem,
373  .cfg = &i2cfg4,
374  .dma_buf = i2c4_dma_buf
375 };
376 #else
377 static struct i2c_init i2c4_init_s = {
378  .sem = &i2c4_sem,
379  .cfg = &i2cfg4
380 };
381 #endif
382 // Errors
383 struct i2c_errors i2c4_errors;
384 // Thread
385 static __attribute__((noreturn)) void thd_i2c4(void *arg);
386 static THD_WORKING_AREA(wa_thd_i2c4, 128);
387 
388 /*
389  * I2C4 init
390  */
391 void i2c4_hw_init(void)
392 {
393  i2c4.idle = i2c_chibios_idle;
394  i2c4.submit = i2c_chibios_submit;
395  i2c4.setbitrate = i2c_chibios_setbitrate;
396 
397  i2cStart(&I2CD4, &i2cfg4);
398  i2c4.reg_addr = &I2CD4;
399  i2c4.init_struct = NULL;
400  i2c4.errors = &i2c4_errors;
401  i2c4.init_struct = &i2c4_init_s;
402  // Create thread
403  chThdCreateStatic(wa_thd_i2c4, sizeof(wa_thd_i2c4),
404  NORMALPRIO + 1, thd_i2c4, NULL);
405 }
406 
407 /*
408  * I2C4 thread
409  *
410  */
411 static void thd_i2c4(void *arg)
412 {
413  (void) arg;
414  chRegSetThreadName("i2c4");
415 
416  while (TRUE) {
417  handle_i2c_thd(&i2c4);
418  }
419 }
420 #endif /* USE_I2C4 */
421 
422 
428 void i2c_event(void) {}
429 
436 static void i2c_chibios_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
437 
455 static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
456 {
457 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
458  // sys lock
459  chSysLock();
460  uint8_t temp;
461  temp = p->trans_insert_idx + 1;
462  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
463  if (temp == p->trans_extract_idx) {
464  // queue full
465  p->errors->queue_full_cnt++;
466  t->status = I2CTransFailed;
467  chSysUnlock();
468  return FALSE;
469  }
470 
471  t->status = I2CTransPending;
472 
473  /* put transacation in queue */
474  p->trans[p->trans_insert_idx] = t;
475  p->trans_insert_idx = temp;
476 
477  chSysUnlock();
478  chSemSignal(((struct i2c_init *)p->init_struct)->sem);
479  // transaction submitted
480  return TRUE;
481 #else
482  // if no I2C peripheral is used fill in with dummy function
483  (void)p;
484  (void)t;
485  return FALSE;
486 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
487 }
488 
494 static bool i2c_chibios_idle(struct i2c_periph *p __attribute__((unused)))
495 {
496  return FALSE;
497 }
i2c_transaction::buf
volatile uint8_t buf[I2C_BUF_LEN]
Transaction buffer With I2C_BUF_LEN number of bytes.
Definition: i2c.h:122
I2C2_CLOCK_SPEED
#define I2C2_CLOCK_SPEED
Definition: board.h:513
SEMAPHORE_DECL
static SEMAPHORE_DECL(spi1_sem, 0)
Configure SPI peripherals.
i2c_chibios_submit
static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:455
i2c_transaction::len_r
uint16_t len_r
Number of bytes to read/receive.
Definition: i2c.h:110
I2CStartRequested
@ I2CStartRequested
Definition: i2c.h:67
status
uint8_t status
Definition: nps_radio_control_spektrum.c:101
i2c_init
void i2c_init(struct i2c_periph *p)
Initialize I2C peripheral.
Definition: i2c.c:310
i2c_event
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:428
I2C1_CLOCK_SPEED
#define I2C1_CLOCK_SPEED
I2C defines.
Definition: board.h:497
I2C_TIMEOUT
#define I2C_TIMEOUT
Definition: i2c_smbus.h:125
I2C4_CFG_DEF
#define I2C4_CFG_DEF
Definition: nucleo144_f767zi.h:701
I2CTransFailed
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
i2c_errors
I2C errors counter.
Definition: i2c.h:165
i2c_chibios_setbitrate
static void i2c_chibios_setbitrate(struct i2c_periph *p, int bitrate)
i2c_setbitrate() function
Definition: i2c_arch.c:436
i2c_transaction::len_w
uint8_t len_w
Number of bytes to write/transmit.
Definition: i2c.h:116
I2CTransSuccess
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
I2C3_CLOCK_SPEED
#define I2C3_CLOCK_SPEED
Definition: crazyflie.h:238
I2C_BUF_LEN
#define I2C_BUF_LEN
I2C buffer length.
Definition: i2c.h:84
IN_DMA_SECTION
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:76
I2C1_CFG_DEF
#define I2C1_CFG_DEF
Definition: board.h:506
uint8_t
unsigned char uint8_t
Definition: types.h:14
THD_WORKING_AREA
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
i2c_transaction::status
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
I2CIdle
@ I2CIdle
Definition: i2c.h:66
i2c_transaction
I2C transaction structure.
Definition: i2c.h:93
i2c_transaction::slave_addr
uint8_t slave_addr
Slave address.
Definition: i2c.h:104
I2C4_CLOCK_SPEED
#define I2C4_CLOCK_SPEED
Definition: nucleo144_f767zi.h:697
I2C_TRANSACTION_QUEUE_LEN
#define I2C_TRANSACTION_QUEUE_LEN
I2C transaction queue length.
Definition: i2c.h:133
i2c_chibios_idle
static bool i2c_chibios_idle(struct i2c_periph *p)
i2c_idle() function
Definition: i2c_arch.c:494
ram_arch.h
I2CTransPending
@ I2CTransPending
transaction is pending in queue
Definition: i2c.h:55
I2C2_CFG_DEF
#define I2C2_CFG_DEF
Definition: board.h:522
FALSE
#define FALSE
Definition: std.h:5
TRUE
#define TRUE
Definition: std.h:4
i2c_periph
Definition: i2c.h:144
I2C_THREAD_STACK_SIZE
#define I2C_THREAD_STACK_SIZE
Definition: i2c_arch.c:46
i2c.h
I2C3_CFG_DEF
#define I2C3_CFG_DEF
Definition: crazyflie.h:247
p
static float p[2][2]
Definition: ins_alt_float.c:268