Paparazzi UAS  v6.3_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  ioline_t line_sda;
67  ioline_t line_scl;
68 };
69 
70 
71 static void handle_i2c_thd(struct i2c_periph *p);
72 
73 // Timeout for I2C transaction
74 static const systime_t tmo = TIME_US2I(10000000 / PERIODIC_FREQUENCY);
75 
76 static iomode_t palReadLineMode(ioline_t line)
77 {
78  ioportid_t port = PAL_PORT(line);
79  uint8_t pad = PAL_PAD(line);
80  iomode_t ret = 0;
81  ret |= (port->MODER >> (pad*2)) & 0x3;
82  ret |= ((port->OTYPER >> pad)&1) << 2;
83  ret |= ((port->OSPEEDR >> (pad*2))&3) << 3;
84  ret |= ((port->PUPDR >> (pad*2))&3) << 5;
85  if (pad < 8) {
86  ret |= ((port->AFRL >> (pad*4))&0xF) << 7;
87  } else {
88  ret |= ((port->AFRH >> ((pad-8)*4))&0xF) << 7;
89  }
90  return ret;
91 }
92 
93 /* Clear a stuck bus */
94 static void i2c_clear_bus(struct i2c_init *i)
95 {
96  const iomode_t mode_saved = palReadLineMode(i->line_scl);
97  palSetLineMode(i->line_scl, PAL_MODE_OUTPUT_PUSHPULL);
98  for(uint8_t j = 0; j < 20; j++) {
99  palToggleLine(i->line_scl);
100  chThdSleepMicroseconds(10);
101  }
102  palSetLineMode(i->line_scl, mode_saved);
103 }
104 
105 static uint8_t i2c_read_sda(struct i2c_init *i)
106 {
107  const iomode_t mode_saved = palReadLineMode(i->line_sda);
108  palSetLineMode(i->line_sda, PAL_MODE_INPUT);
109  uint8_t ret = palReadLine(i->line_sda);
110  palSetLineMode(i->line_sda, mode_saved);
111  return ret;
112 }
113 
119 static void handle_i2c_thd(struct i2c_periph *p)
120 {
121  struct i2c_init *i = (struct i2c_init *) p->init_struct;
122 
123  // wait for a transaction to be pushed in the queue
124  chSemWait(&i->sem);
125 
126  if (p->trans_insert_idx == p->trans_extract_idx) {
127  p->status = I2CIdle;
128  // no transaction pending
129  return;
130  }
131 
132  // Get next transation in queue
133  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
134 
135  p->status = I2CStartRequested;
136  msg_t status;
137  // submit i2c transaction (R/W or R only depending of len_w)
138  if (t->len_w > 0) {
139 #if defined(STM32F7XX) || defined(STM32H7XX)
140  // we do stupid mem copy because F7 needs a special RAM for DMA operation
141  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
142  cacheBufferFlush(i->dma_buf, t->len_w);
143  status = i2cMasterTransmitTimeout(
144  (I2CDriver *)p->reg_addr,
145  (i2caddr_t)((t->slave_addr) >> 1),
146  (uint8_t *)i->dma_buf, (size_t)(t->len_w),
147  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
148  tmo);
149  cacheBufferInvalidate(i->dma_buf, t->len_r);
150  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
151 #else
152  status = i2cMasterTransmitTimeout(
153  (I2CDriver *)p->reg_addr,
154  (i2caddr_t)((t->slave_addr) >> 1),
155  (uint8_t *)t->buf, (size_t)(t->len_w),
156  (uint8_t *)t->buf, (size_t)(t->len_r),
157  tmo);
158 #endif
159  } else {
160 #if defined(STM32F7XX) || defined(STM32H7XX)
161  // we do stupid mem copy because F7 needs a special RAM for DMA operation
162  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
163  status = i2cMasterReceiveTimeout(
164  (I2CDriver *)p->reg_addr,
165  (i2caddr_t)((t->slave_addr) >> 1),
166  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
167  tmo);
168  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
169 #else
170  status = i2cMasterReceiveTimeout(
171  (I2CDriver *)p->reg_addr,
172  (i2caddr_t)((t->slave_addr) >> 1),
173  (uint8_t *)t->buf, (size_t)(t->len_r),
174  tmo);
175 #endif
176  }
177 
178  chSysLock();
179  // end of transaction, handle fifo
180  p->trans_extract_idx++;
181  if (p->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN) {
182  p->trans_extract_idx = 0;
183  }
184  p->status = I2CIdle;
185  chSysUnlock();
186 
187  // Set report status and errors
188  switch (status) {
189  case MSG_OK:
190  //if the function succeeded
191  t->status = I2CTransSuccess;
192  break;
193  case MSG_TIMEOUT:
194  //if a timeout occurred before operation end
195  // mark as failed
196  t->status = I2CTransFailed;
197  p->errors->unexpected_event_cnt++;
198  // Clear the bus if kept busy
199  if(i2c_read_sda(i) == 0) {
200  i2c_clear_bus(i);
201  }
202  i2cStart((I2CDriver *)p->reg_addr, &i->cfg);
203  break;
204  case MSG_RESET:
205  //if one or more I2C errors occurred, the errors can
206  //be retrieved using @p i2cGetErrors().
207  t->status = I2CTransFailed;
208  i2cflags_t errors = i2cGetErrors((I2CDriver *)p->reg_addr);
209  if (errors & I2C_BUS_ERROR) {
210  p->errors->miss_start_stop_cnt++;
211  }
212  if (errors & I2C_ARBITRATION_LOST) {
213  p->errors->arb_lost_cnt++;
214  }
215  if (errors & I2C_ACK_FAILURE) {
216  p->errors->ack_fail_cnt++;
217  }
218  if (errors & I2C_OVERRUN) {
219  p->errors->over_under_cnt++;
220  }
221  if (errors & I2C_PEC_ERROR) {
222  p->errors->pec_recep_cnt++;
223  }
224  if (errors & I2C_TIMEOUT) {
225  p->errors->timeout_tlow_cnt++;
226  }
227  if (errors & I2C_SMB_ALERT) {
228  p->errors->smbus_alert_cnt++;
229  }
230  break;
231  default:
232  break;
233  }
234 }
235 
241 static void thd_i2c(void *arg)
242 {
243  struct i2c_periph *i2cp = (struct i2c_periph *)arg;
244  struct i2c_init *init_s = (struct i2c_init *)i2cp->init_struct;
245  chRegSetThreadName(init_s->name);
246 
247  while (TRUE) {
248  handle_i2c_thd(i2cp);
249  }
250 }
251 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
252 
253 #if USE_I2C1
254 PRINT_CONFIG_VAR(I2C1_CLOCK_SPEED)
255 // Local variables (in DMA safe memory)
256 static IN_DMA_SECTION(struct i2c_init i2c1_init_s) = {
257  .name = "i2c1",
258  .sem = __SEMAPHORE_DATA(i2c1_init_s.sem, 0),
259  .cfg = I2C1_CFG_DEF,
260  .line_sda = LINE_I2C1_SDA,
261  .line_scl = LINE_I2C1_SCL
262 };
263 static THD_WORKING_AREA(wa_thd_i2c1, I2C_THREAD_STACK_SIZE);
264 
265 /*
266  * I2C1 init
267  */
268 void i2c1_hw_init(void)
269 {
270  i2c1.idle = i2c_chibios_idle;
271  i2c1.submit = i2c_chibios_submit;
272  i2c1.setbitrate = i2c_chibios_setbitrate;
273 
274  i2cStart(&I2CD1, &i2c1_init_s.cfg);
275  i2c1.reg_addr = &I2CD1;
276  i2c1.errors = &i2c1_init_s.errors;
277  i2c1.init_struct = &i2c1_init_s;
278  // Create thread
279  chThdCreateStatic(wa_thd_i2c1, sizeof(wa_thd_i2c1),
280  NORMALPRIO + 1, thd_i2c, (void *)&i2c1);
281 }
282 #endif /* USE_I2C1 */
283 
284 #if USE_I2C2
285 PRINT_CONFIG_VAR(I2C2_CLOCK_SPEED)
286 // Local variables (in DMA safe memory)
287 static IN_DMA_SECTION(struct i2c_init i2c2_init_s) = {
288  .name = "i2c2",
289  .sem = __SEMAPHORE_DATA(i2c2_init_s.sem, 0),
290  .cfg = I2C2_CFG_DEF,
291  .line_sda = LINE_I2C2_SDA,
292  .line_scl = LINE_I2C2_SCL
293 };
294 static THD_WORKING_AREA(wa_thd_i2c2, I2C_THREAD_STACK_SIZE);
295 
296 /*
297  * I2C2 init
298  */
299 void i2c2_hw_init(void)
300 {
301  i2c2.idle = i2c_chibios_idle;
302  i2c2.submit = i2c_chibios_submit;
303  i2c2.setbitrate = i2c_chibios_setbitrate;
304 
305  i2cStart(&I2CD2, &i2c2_init_s.cfg);
306  i2c2.reg_addr = &I2CD2;
307  i2c2.errors = &i2c2_init_s.errors;
308  i2c2.init_struct = &i2c2_init_s;
309  // Create thread
310  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
311  NORMALPRIO + 1, thd_i2c, (void *)&i2c2);
312 }
313 #endif /* USE_I2C2 */
314 
315 #if USE_I2C3
316 PRINT_CONFIG_VAR(I2C3_CLOCK_SPEED)
317 // Local variables (in DMA safe memory)
318 static IN_DMA_SECTION(struct i2c_init i2c3_init_s) = {
319  .name = "i2c3",
320  .sem = __SEMAPHORE_DATA(i2c3_init_s.sem, 0),
321  .cfg = I2C3_CFG_DEF,
322  .line_sda = LINE_I2C3_SDA,
323  .line_scl = LINE_I2C3_SCL
324 };
325 static THD_WORKING_AREA(wa_thd_i2c3, I2C_THREAD_STACK_SIZE);
326 
327 /*
328  * I2C3 init
329  */
330 void i2c3_hw_init(void)
331 {
332  i2c3.idle = i2c_chibios_idle;
333  i2c3.submit = i2c_chibios_submit;
334  i2c3.setbitrate = i2c_chibios_setbitrate;
335 
336  i2cStart(&I2CD3, &i2c3_init_s.cfg);
337  i2c3.reg_addr = &I2CD3;
338  i2c3.errors = &i2c3_init_s.errors;
339  i2c3.init_struct = &i2c3_init_s;
340  // Create thread
341  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
342  NORMALPRIO + 1, thd_i2c, (void *)&i2c3);
343 }
344 #endif /* USE_I2C3 */
345 
346 #if USE_I2C4
347 PRINT_CONFIG_VAR(I2C4_CLOCK_SPEED)
348 // Local variables (in DMA safe memory)
349 static IN_DMA_SECTION(struct i2c_init i2c4_init_s) = {
350  .name = "i2c4",
351  .sem = __SEMAPHORE_DATA(i2c4_init_s.sem, 0),
352  .cfg = I2C4_CFG_DEF,
353  .line_sda = LINE_I2C4_SDA,
354  .line_scl = LINE_I2C4_SCL
355 };
356 static THD_WORKING_AREA(wa_thd_i2c4, I2C_THREAD_STACK_SIZE);
357 
358 /*
359  * I2C4 init
360  */
361 void i2c4_hw_init(void)
362 {
363  i2c4.idle = i2c_chibios_idle;
364  i2c4.submit = i2c_chibios_submit;
365  i2c4.setbitrate = i2c_chibios_setbitrate;
366 
367  i2cStart(&I2CD4, &i2c4_init_s.cfg);
368  i2c4.reg_addr = &I2CD4;
369  i2c4.errors = &i2c4_init_s.errors;
370  i2c4.init_struct = &i2c4_init_s;
371  // Create thread
372  chThdCreateStatic(wa_thd_i2c4, sizeof(wa_thd_i2c4),
373  NORMALPRIO + 1, thd_i2c, (void *)&i2c4);
374 }
375 #endif /* USE_I2C4 */
376 
377 
383 void i2c_event(void) {}
384 
391 static void i2c_chibios_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
392 
410 static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
411 {
412 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
413  // sys lock
414  chSysLock();
415  uint8_t temp;
416  temp = p->trans_insert_idx + 1;
417  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
418  if (temp == p->trans_extract_idx) {
419  // queue full
420  p->errors->queue_full_cnt++;
421  t->status = I2CTransFailed;
422  chSysUnlock();
423  return FALSE;
424  }
425 
426  t->status = I2CTransPending;
427 
428  /* put transacation in queue */
429  p->trans[p->trans_insert_idx] = t;
430  p->trans_insert_idx = temp;
431 
432  chSysUnlock();
433  chSemSignal(&((struct i2c_init *)p->init_struct)->sem);
434  // transaction submitted
435  return TRUE;
436 #else
437  // if no I2C peripheral is used fill in with dummy function
438  (void)p;
439  (void)t;
440  return FALSE;
441 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
442 }
443 
449 static bool i2c_chibios_idle(struct i2c_periph *p __attribute__((unused)))
450 {
451  return FALSE;
452 }
#define LINE_I2C1_SDA
Definition: board.h:761
#define LINE_I2C2_SDA
Definition: board.h:765
#define LINE_I2C2_SCL
Definition: board.h:764
#define LINE_I2C1_SCL
Definition: board.h:762
#define I2C_THREAD_STACK_SIZE
Definition: i2c_arch.c:46
static bool i2c_chibios_idle(struct i2c_periph *p)
i2c_idle() function
Definition: i2c_arch.c:449
static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:410
static void i2c_chibios_setbitrate(struct i2c_periph *p, int bitrate)
i2c_setbitrate() function
Definition: i2c_arch.c:391
#define I2C1_CLOCK_SPEED
Definition: common_board.h:468
#define I2C3_CFG_DEF
Definition: common_board.h:512
#define I2C4_CFG_DEF
Definition: common_board.h:532
#define I2C1_CFG_DEF
Definition: common_board.h:472
#define I2C3_CLOCK_SPEED
Definition: common_board.h:508
#define I2C2_CLOCK_SPEED
Definition: common_board.h:488
#define I2C2_CFG_DEF
Definition: common_board.h:492
#define I2C4_CLOCK_SPEED
Definition: common_board.h:528
#define LINE_I2C3_SCL
Definition: board.h:254
#define LINE_I2C3_SDA
Definition: board.h:279
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
void * init_struct
Definition: i2c.h:158
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
uint8_t slave_addr
Slave address.
Definition: i2c.h:104
uint8_t len_w
Number of bytes to write/transmit.
Definition: i2c.h:116
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:383
#define I2C_TRANSACTION_QUEUE_LEN
I2C transaction queue length.
Definition: i2c.h:133
#define I2C_BUF_LEN
I2C buffer length.
Definition: i2c.h:84
void i2c_init(struct i2c_periph *p)
Initialize I2C peripheral.
Definition: i2c.c:310
@ I2CIdle
Definition: i2c.h:66
@ I2CStartRequested
Definition: i2c.h:67
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
@ I2CTransPending
transaction is pending in queue
Definition: i2c.h:55
I2C errors counter.
Definition: i2c.h:165
I2C transaction structure.
Definition: i2c.h:93
Architecture independent I2C (Inter-Integrated Circuit Bus) API.
#define I2C_TIMEOUT
Definition: i2c_smbus.h:125
static float p[2][2]
THD_WORKING_AREA(wa_thd_ap, THD_WORKING_AREA_MAIN)
uint8_t status
#define LINE_I2C4_SCL
Definition: board.h:290
#define LINE_I2C4_SDA
Definition: board.h:291
Specific RAM section for DMA usage on F7.
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:85
#define TRUE
Definition: std.h:4
#define FALSE
Definition: std.h:5
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98