Paparazzi UAS  v5.15_devel-81-gd13dafb
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
50 
51 // private I2C init structure
52 struct i2c_init {
53  semaphore_t *sem;
54  I2CConfig *cfg;
55 #ifdef STM32F7
56  uint8_t *dma_buf;
57 #endif
58 };
59 
60 
61 static void handle_i2c_thd(struct i2c_periph *p);
62 
63 // Timeout for I2C transaction
64 static const systime_t tmo = TIME_US2I(10000000 / PERIODIC_FREQUENCY);
65 
71 static void handle_i2c_thd(struct i2c_periph *p)
72 {
73  struct i2c_init *i = (struct i2c_init *) p->init_struct;
74 
75  // wait for a transaction to be pushed in the queue
76  chSemWait(i->sem);
77 
78  if (p->trans_insert_idx == p->trans_extract_idx) {
79  p->status = I2CIdle;
80  // no transaction pending
81  return;
82  }
83 
84  // Get next transation in queue
85  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
86 
88  msg_t status;
89  // submit i2c transaction (R/W or R only depending of len_w)
90  if (t->len_w > 0) {
91 #if defined STM32F7
92  // we do stupid mem copy because F7 needs a special RAM for DMA operation
93  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
94  status = i2cMasterTransmitTimeout(
95  (I2CDriver *)p->reg_addr,
96  (i2caddr_t)((t->slave_addr) >> 1),
97  (uint8_t *)i->dma_buf, (size_t)(t->len_w),
98  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
99  tmo);
100  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
101 #else
102  status = i2cMasterTransmitTimeout(
103  (I2CDriver *)p->reg_addr,
104  (i2caddr_t)((t->slave_addr) >> 1),
105  (uint8_t *)t->buf, (size_t)(t->len_w),
106  (uint8_t *)t->buf, (size_t)(t->len_r),
107  tmo);
108 #endif
109  } else {
110 #if defined STM32F7
111  // we do stupid mem copy because F7 needs a special RAM for DMA operation
112  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
113  status = i2cMasterReceiveTimeout(
114  (I2CDriver *)p->reg_addr,
115  (i2caddr_t)((t->slave_addr) >> 1),
116  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
117  tmo);
118  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
119 #else
120  status = i2cMasterReceiveTimeout(
121  (I2CDriver *)p->reg_addr,
122  (i2caddr_t)((t->slave_addr) >> 1),
123  (uint8_t *)t->buf, (size_t)(t->len_r),
124  tmo);
125 #endif
126  }
127 
128  chSysLock();
129  // end of transaction, handle fifo
130  p->trans_extract_idx++;
132  p->trans_extract_idx = 0;
133  }
134  p->status = I2CIdle;
135  chSysUnlock();
136 
137  // Set report status and errors
138  switch (status) {
139  case MSG_OK:
140  //if the function succeeded
141  t->status = I2CTransSuccess;
142  break;
143  case MSG_TIMEOUT:
144  //if a timeout occurred before operation end
145  // mark as failed and restart
146  t->status = I2CTransFailed;
147  i2cStart((I2CDriver *)p->reg_addr, i->cfg);
148  break;
149  case MSG_RESET:
150  //if one or more I2C errors occurred, the errors can
151  //be retrieved using @p i2cGetErrors().
152  t->status = I2CTransFailed;
153  i2cflags_t errors = i2cGetErrors((I2CDriver *)p->reg_addr);
154  if (errors & I2C_BUS_ERROR) {
156  }
157  if (errors & I2C_ARBITRATION_LOST) {
158  p->errors->arb_lost_cnt++;
159  }
160  if (errors & I2C_ACK_FAILURE) {
161  p->errors->ack_fail_cnt++;
162  }
163  if (errors & I2C_OVERRUN) {
164  p->errors->over_under_cnt++;
165  }
166  if (errors & I2C_PEC_ERROR) {
167  p->errors->pec_recep_cnt++;
168  }
169  if (errors & I2C_TIMEOUT) {
170  p->errors->timeout_tlow_cnt++;
171  }
172  if (errors & I2C_SMB_ALERT) {
173  p->errors->smbus_alert_cnt++;
174  }
175  break;
176  default:
177  break;
178  }
179 }
180 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
181 
182 #if USE_I2C1
183 // I2C1 config
184 PRINT_CONFIG_VAR(I2C1_CLOCK_SPEED)
185 static SEMAPHORE_DECL(i2c1_sem, 0);
186 static I2CConfig i2cfg1 = I2C1_CFG_DEF;
187 #if defined STM32F7
188 // We need a special buffer for DMA operations
189 static IN_DMA_SECTION(uint8_t i2c1_dma_buf[I2C_BUF_LEN]);
190 static struct i2c_init i2c1_init_s = {
191  .sem = &i2c1_sem,
192  .cfg = &i2cfg1,
193  .dma_buf = i2c1_dma_buf
194 };
195 #else
196 static struct i2c_init i2c1_init_s = {
197  .sem = &i2c1_sem,
198  .cfg = &i2cfg1
199 };
200 #endif
201 // Errors
202 struct i2c_errors i2c1_errors;
203 // Thread
204 static __attribute__((noreturn)) void thd_i2c1(void *arg);
205 static THD_WORKING_AREA(wa_thd_i2c1, I2C_THREAD_STACK_SIZE);
206 
207 /*
208  * I2C1 init
209  */
210 void i2c1_hw_init(void)
211 {
212  i2cStart(&I2CD1, &i2cfg1);
213  i2c1.reg_addr = &I2CD1;
214  i2c1.errors = &i2c1_errors;
215  i2c1.init_struct = &i2c1_init_s;
216  // Create thread
217  chThdCreateStatic(wa_thd_i2c1, sizeof(wa_thd_i2c1),
218  NORMALPRIO + 1, thd_i2c1, NULL);
219 }
220 
221 /*
222  * I2C1 thread
223  *
224  */
225 static void thd_i2c1(void *arg)
226 {
227  (void) arg;
228  chRegSetThreadName("i2c1");
229 
230  while (TRUE) {
231  handle_i2c_thd(&i2c1);
232  }
233 }
234 #endif /* USE_I2C1 */
235 
236 #if USE_I2C2
237 // I2C2 config
238 PRINT_CONFIG_VAR(I2C2_CLOCK_SPEED)
239 static SEMAPHORE_DECL(i2c2_sem, 0);
240 static I2CConfig i2cfg2 = I2C2_CFG_DEF;
241 #if defined STM32F7
242 // We need a special buffer for DMA operations
243 static IN_DMA_SECTION(uint8_t i2c2_dma_buf[I2C_BUF_LEN]);
244 static struct i2c_init i2c2_init_s = {
245  .sem = &i2c2_sem,
246  .cfg = &i2cfg2,
247  .dma_buf = i2c2_dma_buf
248 };
249 #else
250 static struct i2c_init i2c2_init_s = {
251  .sem = &i2c2_sem,
252  .cfg = &i2cfg2
253 };
254 #endif
255 // Errors
256 struct i2c_errors i2c2_errors;
257 // Thread
258 static __attribute__((noreturn)) void thd_i2c2(void *arg);
259 static THD_WORKING_AREA(wa_thd_i2c2, I2C_THREAD_STACK_SIZE);
260 
261 /*
262  * I2C2 init
263  */
264 void i2c2_hw_init(void)
265 {
266  i2cStart(&I2CD2, &i2cfg2);
267  i2c2.reg_addr = &I2CD2;
268  i2c2.errors = &i2c2_errors;
269  i2c2.init_struct = &i2c2_init_s;
270  // Create thread
271  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
272  NORMALPRIO + 1, thd_i2c2, NULL);
273 }
274 
275 /*
276  * I2C2 thread
277  *
278  */
279 static void thd_i2c2(void *arg)
280 {
281  (void) arg;
282  chRegSetThreadName("i2c2");
283 
284  while (TRUE) {
285  handle_i2c_thd(&i2c2);
286  }
287 }
288 #endif /* USE_I2C2 */
289 
290 #if USE_I2C3
291 // I2C3 config
292 PRINT_CONFIG_VAR(I2C3_CLOCK_SPEED)
293 static SEMAPHORE_DECL(i2c3_sem, 0);
294 static I2CConfig i2cfg3 = I2C3_CFG_DEF;
295 #if defined STM32F7
296 // We need a special buffer for DMA operations
297 static IN_DMA_SECTION(uint8_t i2c3_dma_buf[I2C_BUF_LEN]);
298 static struct i2c_init i2c3_init_s = {
299  .sem = &i2c3_sem,
300  .cfg = &i2cfg3,
301  .dma_buf = i2c3_dma_buf
302 };
303 #else
304 static struct i2c_init i2c3_init_s = {
305  .sem = &i2c3_sem,
306  .cfg = &i2cfg3
307 };
308 #endif
309 // Errors
310 struct i2c_errors i2c3_errors;
311 // Thread
312 static __attribute__((noreturn)) void thd_i2c3(void *arg);
313 static THD_WORKING_AREA(wa_thd_i2c3, I2C_THREAD_STACK_SIZE);
314 
315 /*
316  * I2C3 init
317  */
318 void i2c3_hw_init(void)
319 {
320  i2cStart(&I2CD3, &i2cfg3);
321  i2c3.reg_addr = &I2CD3;
322  i2c3.init_struct = NULL;
323  i2c3.errors = &i2c3_errors;
324  i2c3.init_struct = &i2c3_init_s;
325  // Create thread
326  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
327  NORMALPRIO + 1, thd_i2c3, NULL);
328 }
329 
330 /*
331  * I2C3 thread
332  *
333  */
334 static void thd_i2c3(void *arg)
335 {
336  (void) arg;
337  chRegSetThreadName("i2c3");
338 
339  while (TRUE) {
340  handle_i2c_thd(&i2c3);
341  }
342 }
343 #endif /* USE_I2C3 */
344 
345 #if USE_I2C4
346 // I2C4 config
347 PRINT_CONFIG_VAR(I2C4_CLOCK_SPEED)
348 static SEMAPHORE_DECL(i2c4_sem, 0);
349 static I2CConfig i2cfg4 = I2C4_CFG_DEF;
350 #if defined STM32F7
351 // We need a special buffer for DMA operations
352 static IN_DMA_SECTION(uint8_t i2c4_dma_buf[I2C_BUF_LEN]);
353 static struct i2c_init i2c4_init_s = {
354  .sem = &i2c4_sem,
355  .cfg = &i2cfg4,
356  .dma_buf = i2c4_dma_buf
357 };
358 #else
359 static struct i2c_init i2c4_init_s = {
360  .sem = &i2c4_sem,
361  .cfg = &i2cfg4
362 };
363 #endif
364 // Errors
365 struct i2c_errors i2c4_errors;
366 // Thread
367 static __attribute__((noreturn)) void thd_i2c4(void *arg);
368 static THD_WORKING_AREA(wa_thd_i2c4, 128);
369 
370 /*
371  * I2C4 init
372  */
373 void i2c4_hw_init(void)
374 {
375  i2cStart(&I2CD4, &i2cfg4);
376  i2c4.reg_addr = &I2CD4;
377  i2c4.init_struct = NULL;
378  i2c4.errors = &i2c4_errors;
379  i2c4.init_struct = &i2c4_init_s;
380  // Create thread
381  chThdCreateStatic(wa_thd_i2c4, sizeof(wa_thd_i2c4),
382  NORMALPRIO + 1, thd_i2c4, NULL);
383 }
384 
385 /*
386  * I2C4 thread
387  *
388  */
389 static void thd_i2c4(void *arg)
390 {
391  (void) arg;
392  chRegSetThreadName("i2c4");
393 
394  while (TRUE) {
395  handle_i2c_thd(&i2c4);
396  }
397 }
398 #endif /* USE_I2C4 */
399 
400 
406 void i2c_event(void) {}
407 
414 void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
415 
433 bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
434 {
435 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
436  // sys lock
437  chSysLock();
438  uint8_t temp;
439  temp = p->trans_insert_idx + 1;
440  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
441  if (temp == p->trans_extract_idx) {
442  // queue full
443  p->errors->queue_full_cnt++;
444  t->status = I2CTransFailed;
445  chSysUnlock();
446  return FALSE;
447  }
448 
449  t->status = I2CTransPending;
450 
451  /* put transacation in queue */
452  p->trans[p->trans_insert_idx] = t;
453  p->trans_insert_idx = temp;
454 
455  chSysUnlock();
456  chSemSignal(((struct i2c_init *)p->init_struct)->sem);
457  // transaction submitted
458  return TRUE;
459 #else
460  // if no I2C peripheral is used fill in with dummy function
461  (void)p;
462  (void)t;
463  return FALSE;
464 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
465 }
466 
472 bool i2c_idle(struct i2c_periph *p __attribute__((unused)))
473 {
474  return FALSE;
475 }
Specific RAM section for DMA usage on F7.
volatile uint16_t arb_lost_cnt
Definition: i2c.h:159
#define I2C_TRANSACTION_QUEUE_LEN
I2C transaction queue length.
Definition: i2c.h:133
I2C errors counter.
Definition: i2c.h:154
#define I2C_TIMEOUT
Definition: i2c_smbus.h:125
volatile uint16_t miss_start_stop_cnt
Definition: i2c.h:158
volatile uint8_t buf[I2C_BUF_LEN]
Transaction buffer With I2C_BUF_LEN number of bytes.
Definition: i2c.h:122
uint16_t len_r
Number of bytes to read/receive.
Definition: i2c.h:110
transaction successfully finished by I2C driver
Definition: i2c.h:57
#define I2C1_CFG_DEF
Definition: board.h:485
uint8_t trans_extract_idx
Definition: i2c.h:142
void i2c_init(struct i2c_periph *p)
Initialize I2C peripheral.
Definition: i2c.c:294
bool i2c_idle(struct i2c_periph *p)
i2c_idle() function
Definition: i2c_arch.c:472
Definition: i2c.h:66
volatile uint16_t queue_full_cnt
Definition: i2c.h:156
void i2c_setbitrate(struct i2c_periph *p, int bitrate)
i2c_setbitrate() function
Definition: i2c_arch.c:414
struct i2c_errors * errors
Definition: i2c.h:148
enum I2CStatus status
Definition: i2c.h:144
#define I2C4_CLOCK_SPEED
Definition: tawaki.h:536
#define FALSE
Definition: std.h:5
static SEMAPHORE_DECL(spi1_sem, 0)
Configure SPI peripherals.
void * reg_addr
Definition: i2c.h:146
uint8_t len_w
Number of bytes to write/transmit.
Definition: i2c.h:116
#define TRUE
Definition: std.h:4
uint8_t status
struct i2c_transaction * trans[I2C_TRANSACTION_QUEUE_LEN]
Definition: i2c.h:140
volatile uint16_t over_under_cnt
Definition: i2c.h:160
#define I2C4_CFG_DEF
Definition: tawaki.h:540
bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:433
transaction failed
Definition: i2c.h:58
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
I2C transaction structure.
Definition: i2c.h:93
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
void * init_struct
Definition: i2c.h:147
uint8_t slave_addr
Slave address.
Definition: i2c.h:104
I2C peripheral structure.
Definition: i2c.h:138
#define I2C2_CFG_DEF
Definition: board.h:501
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:76
unsigned char uint8_t
Definition: types.h:14
#define I2C_BUF_LEN
I2C buffer length.
Definition: i2c.h:84
static float p[2][2]
#define I2C_THREAD_STACK_SIZE
Definition: i2c_arch.c:46
volatile uint16_t smbus_alert_cnt
Definition: i2c.h:163
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:406
#define I2C1_CLOCK_SPEED
I2C defines.
Definition: board.h:476
uint8_t trans_insert_idx
Definition: i2c.h:141
volatile uint16_t pec_recep_cnt
Definition: i2c.h:161
#define I2C2_CLOCK_SPEED
Definition: board.h:492
transaction is pending in queue
Definition: i2c.h:55
volatile uint16_t ack_fail_cnt
Definition: i2c.h:157
volatile uint16_t timeout_tlow_cnt
Definition: i2c.h:162
Architecture independent I2C (Inter-Integrated Circuit Bus) API.