Paparazzi UAS  v6.2_unstable
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 #if defined(STM32F7XX) || defined(STM32H7XX)
60  uint8_t dma_buf[I2C_BUF_LEN];
61 #endif
62  char *name;
63  semaphore_t sem;
64  I2CConfig cfg;
65  struct i2c_errors errors;
66 };
67 
68 
69 static void handle_i2c_thd(struct i2c_periph *p);
70 
71 // Timeout for I2C transaction
72 static const systime_t tmo = TIME_US2I(10000000 / PERIODIC_FREQUENCY);
73 
79 static void handle_i2c_thd(struct i2c_periph *p)
80 {
81  struct i2c_init *i = (struct i2c_init *) p->init_struct;
82 
83  // wait for a transaction to be pushed in the queue
84  chSemWait(&i->sem);
85 
86  if (p->trans_insert_idx == p->trans_extract_idx) {
87  p->status = I2CIdle;
88  // no transaction pending
89  return;
90  }
91 
92  // Get next transation in queue
93  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
94 
95  p->status = I2CStartRequested;
96  msg_t status;
97  // submit i2c transaction (R/W or R only depending of len_w)
98  if (t->len_w > 0) {
99 #if defined(STM32F7XX) || defined(STM32H7XX)
100  // we do stupid mem copy because F7 needs a special RAM for DMA operation
101  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
102  cacheBufferFlush(i->dma_buf, t->len_w);
103  status = i2cMasterTransmitTimeout(
104  (I2CDriver *)p->reg_addr,
105  (i2caddr_t)((t->slave_addr) >> 1),
106  (uint8_t *)i->dma_buf, (size_t)(t->len_w),
107  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
108  tmo);
109  cacheBufferInvalidate(i->dma_buf, t->len_r);
110  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
111 #else
112  status = i2cMasterTransmitTimeout(
113  (I2CDriver *)p->reg_addr,
114  (i2caddr_t)((t->slave_addr) >> 1),
115  (uint8_t *)t->buf, (size_t)(t->len_w),
116  (uint8_t *)t->buf, (size_t)(t->len_r),
117  tmo);
118 #endif
119  } else {
120 #if defined(STM32F7XX) || defined(STM32H7XX)
121  // we do stupid mem copy because F7 needs a special RAM for DMA operation
122  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
123  status = i2cMasterReceiveTimeout(
124  (I2CDriver *)p->reg_addr,
125  (i2caddr_t)((t->slave_addr) >> 1),
126  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
127  tmo);
128  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
129 #else
130  status = i2cMasterReceiveTimeout(
131  (I2CDriver *)p->reg_addr,
132  (i2caddr_t)((t->slave_addr) >> 1),
133  (uint8_t *)t->buf, (size_t)(t->len_r),
134  tmo);
135 #endif
136  }
137 
138  chSysLock();
139  // end of transaction, handle fifo
140  p->trans_extract_idx++;
141  if (p->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN) {
142  p->trans_extract_idx = 0;
143  }
144  p->status = I2CIdle;
145  chSysUnlock();
146 
147  // Set report status and errors
148  switch (status) {
149  case MSG_OK:
150  //if the function succeeded
151  t->status = I2CTransSuccess;
152  break;
153  case MSG_TIMEOUT:
154  //if a timeout occurred before operation end
155  // mark as failed and restart
156  t->status = I2CTransFailed;
157  i2cStart((I2CDriver *)p->reg_addr, &i->cfg);
158  break;
159  case MSG_RESET:
160  //if one or more I2C errors occurred, the errors can
161  //be retrieved using @p i2cGetErrors().
162  t->status = I2CTransFailed;
163  i2cflags_t errors = i2cGetErrors((I2CDriver *)p->reg_addr);
164  if (errors & I2C_BUS_ERROR) {
165  p->errors->miss_start_stop_cnt++;
166  }
167  if (errors & I2C_ARBITRATION_LOST) {
168  p->errors->arb_lost_cnt++;
169  }
170  if (errors & I2C_ACK_FAILURE) {
171  p->errors->ack_fail_cnt++;
172  }
173  if (errors & I2C_OVERRUN) {
174  p->errors->over_under_cnt++;
175  }
176  if (errors & I2C_PEC_ERROR) {
177  p->errors->pec_recep_cnt++;
178  }
179  if (errors & I2C_TIMEOUT) {
180  p->errors->timeout_tlow_cnt++;
181  }
182  if (errors & I2C_SMB_ALERT) {
183  p->errors->smbus_alert_cnt++;
184  }
185  break;
186  default:
187  break;
188  }
189 }
190 
196 static void thd_i2c(void *arg)
197 {
198  struct i2c_periph *i2cp = (struct i2c_periph *)arg;
199  struct i2c_init *init_s = (struct i2c_init *)i2cp->init_struct;
200  chRegSetThreadName(init_s->name);
201 
202  while (TRUE) {
203  handle_i2c_thd(i2cp);
204  }
205 }
206 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
207 
208 #if USE_I2C1
209 PRINT_CONFIG_VAR(I2C1_CLOCK_SPEED)
210 // Local variables (in DMA safe memory)
211 static IN_DMA_SECTION(struct i2c_init i2c1_init_s) = {
212  .name = "i2c1",
213  .sem = __SEMAPHORE_DATA(i2c1_init_s.sem, 0),
214  .cfg = I2C1_CFG_DEF
215 };
216 static THD_WORKING_AREA(wa_thd_i2c1, I2C_THREAD_STACK_SIZE);
217 
218 /*
219  * I2C1 init
220  */
221 void i2c1_hw_init(void)
222 {
223  i2c1.idle = i2c_chibios_idle;
224  i2c1.submit = i2c_chibios_submit;
225  i2c1.setbitrate = i2c_chibios_setbitrate;
226 
227  i2cStart(&I2CD1, &i2c1_init_s.cfg);
228  i2c1.reg_addr = &I2CD1;
229  i2c1.errors = &i2c1_init_s.errors;
230  i2c1.init_struct = &i2c1_init_s;
231  // Create thread
232  chThdCreateStatic(wa_thd_i2c1, sizeof(wa_thd_i2c1),
233  NORMALPRIO + 1, thd_i2c, (void *)&i2c1);
234 }
235 #endif /* USE_I2C1 */
236 
237 #if USE_I2C2
238 PRINT_CONFIG_VAR(I2C2_CLOCK_SPEED)
239 // Local variables (in DMA safe memory)
240 static IN_DMA_SECTION(struct i2c_init i2c2_init_s) = {
241  .name = "i2c2",
242  .sem = __SEMAPHORE_DATA(i2c2_init_s.sem, 0),
243  .cfg = I2C2_CFG_DEF
244 };
245 static THD_WORKING_AREA(wa_thd_i2c2, I2C_THREAD_STACK_SIZE);
246 
247 /*
248  * I2C2 init
249  */
250 void i2c2_hw_init(void)
251 {
252  i2c2.idle = i2c_chibios_idle;
253  i2c2.submit = i2c_chibios_submit;
254  i2c2.setbitrate = i2c_chibios_setbitrate;
255 
256  i2cStart(&I2CD2, &i2c2_init_s.cfg);
257  i2c2.reg_addr = &I2CD2;
258  i2c2.errors = &i2c2_init_s.errors;
259  i2c2.init_struct = &i2c2_init_s;
260  // Create thread
261  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
262  NORMALPRIO + 1, thd_i2c, (void *)&i2c2);
263 }
264 #endif /* USE_I2C2 */
265 
266 #if USE_I2C3
267 PRINT_CONFIG_VAR(I2C3_CLOCK_SPEED)
268 // Local variables (in DMA safe memory)
269 static IN_DMA_SECTION(struct i2c_init i2c3_init_s) = {
270  .name = "i2c3",
271  .sem = __SEMAPHORE_DATA(i2c3_init_s.sem, 0),
272  .cfg = I2C3_CFG_DEF
273 };
274 static THD_WORKING_AREA(wa_thd_i2c3, I2C_THREAD_STACK_SIZE);
275 
276 /*
277  * I2C3 init
278  */
279 void i2c3_hw_init(void)
280 {
281  i2c3.idle = i2c_chibios_idle;
282  i2c3.submit = i2c_chibios_submit;
283  i2c3.setbitrate = i2c_chibios_setbitrate;
284 
285  i2cStart(&I2CD3, &i2c3_init_s.cfg);
286  i2c3.reg_addr = &I2CD3;
287  i2c3.errors = &i2c3_init_s.errors;
288  i2c3.init_struct = &i2c3_init_s;
289  // Create thread
290  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
291  NORMALPRIO + 1, thd_i2c, (void *)&i2c3);
292 }
293 #endif /* USE_I2C3 */
294 
295 #if USE_I2C4
296 PRINT_CONFIG_VAR(I2C4_CLOCK_SPEED)
297 // Local variables (in DMA safe memory)
298 static IN_DMA_SECTION(struct i2c_init i2c4_init_s) = {
299  .name = "i2c4",
300  .sem = __SEMAPHORE_DATA(i2c4_init_s.sem, 0),
301  .cfg = I2C4_CFG_DEF
302 };
303 static THD_WORKING_AREA(wa_thd_i2c4, I2C_THREAD_STACK_SIZE);
304 
305 /*
306  * I2C4 init
307  */
308 void i2c4_hw_init(void)
309 {
310  i2c4.idle = i2c_chibios_idle;
311  i2c4.submit = i2c_chibios_submit;
312  i2c4.setbitrate = i2c_chibios_setbitrate;
313 
314  i2cStart(&I2CD4, &i2c4_init_s.cfg);
315  i2c4.reg_addr = &I2CD4;
316  i2c4.errors = &i2c4_init_s.errors;
317  i2c4.init_struct = &i2c4_init_s;
318  // Create thread
319  chThdCreateStatic(wa_thd_i2c4, sizeof(wa_thd_i2c4),
320  NORMALPRIO + 1, thd_i2c, (void *)&i2c4);
321 }
322 #endif /* USE_I2C4 */
323 
324 
330 void i2c_event(void) {}
331 
338 static void i2c_chibios_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
339 
357 static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
358 {
359 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
360  // sys lock
361  chSysLock();
362  uint8_t temp;
363  temp = p->trans_insert_idx + 1;
364  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
365  if (temp == p->trans_extract_idx) {
366  // queue full
367  p->errors->queue_full_cnt++;
368  t->status = I2CTransFailed;
369  chSysUnlock();
370  return FALSE;
371  }
372 
373  t->status = I2CTransPending;
374 
375  /* put transacation in queue */
376  p->trans[p->trans_insert_idx] = t;
377  p->trans_insert_idx = temp;
378 
379  chSysUnlock();
380  chSemSignal(&((struct i2c_init *)p->init_struct)->sem);
381  // transaction submitted
382  return TRUE;
383 #else
384  // if no I2C peripheral is used fill in with dummy function
385  (void)p;
386  (void)t;
387  return FALSE;
388 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
389 }
390 
396 static bool i2c_chibios_idle(struct i2c_periph *p __attribute__((unused)))
397 {
398  return FALSE;
399 }
i2c_transaction::buf
volatile uint8_t buf[I2C_BUF_LEN]
Transaction buffer With I2C_BUF_LEN number of bytes.
Definition: i2c.h:122
uint8_t
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
i2c_chibios_submit
static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:357
i2c_transaction::len_r
uint16_t len_r
Number of bytes to read/receive.
Definition: i2c.h:110
I2C2_CLOCK_SPEED
#define I2C2_CLOCK_SPEED
Definition: common_board.h:469
I2CStartRequested
@ I2CStartRequested
Definition: i2c.h:67
status
uint8_t status
Definition: nps_radio_control_spektrum.c:101
I2C1_CLOCK_SPEED
#define I2C1_CLOCK_SPEED
Definition: common_board.h:448
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:330
I2C4_CLOCK_SPEED
#define I2C4_CLOCK_SPEED
Definition: common_board.h:509
I2C_TIMEOUT
#define I2C_TIMEOUT
Definition: i2c_smbus.h:125
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:338
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
I2C4_CFG_DEF
#define I2C4_CFG_DEF
Definition: common_board.h:513
I2C3_CFG_DEF
#define I2C3_CFG_DEF
Definition: common_board.h:493
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:85
I2C3_CLOCK_SPEED
#define I2C3_CLOCK_SPEED
Definition: common_board.h:489
i2c_transaction::status
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
i2c_periph::init_struct
void * init_struct
Definition: i2c.h:158
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
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:396
ram_arch.h
I2CTransPending
@ I2CTransPending
transaction is pending in queue
Definition: i2c.h:55
I2C2_CFG_DEF
#define I2C2_CFG_DEF
Definition: common_board.h:473
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
THD_WORKING_AREA
THD_WORKING_AREA(wa_thd_ap, THD_WORKING_AREA_MAIN)
i2c.h
I2C1_CFG_DEF
#define I2C1_CFG_DEF
Definition: common_board.h:452
p
static float p[2][2]
Definition: ins_alt_float.c:268