Paparazzi UAS  v7.0_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  i2cAcquireBus((I2CDriver *)p->reg_addr);
127 
128  if (p->trans_insert_idx == p->trans_extract_idx) {
129  p->status = I2CIdle;
130  // no transaction pending
131  return;
132  }
133 
134  // Get next transation in queue
135  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
136 
137  p->status = I2CStartRequested;
138  msg_t status;
139  // submit i2c transaction (R/W or R only depending of len_w)
140  if (t->len_w > 0) {
141 #if defined(STM32F7XX) || defined(STM32H7XX)
142  // we do stupid mem copy because F7 needs a special RAM for DMA operation
143  memcpy(i->dma_buf, (void *)t->buf, (size_t)(t->len_w));
144  cacheBufferFlush(i->dma_buf, t->len_w);
145  status = i2cMasterTransmitTimeout(
146  (I2CDriver *)p->reg_addr,
147  (i2caddr_t)((t->slave_addr) >> 1),
148  (uint8_t *)i->dma_buf, (size_t)(t->len_w),
149  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
150  tmo);
151  cacheBufferInvalidate(i->dma_buf, t->len_r);
152  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
153 #else
154  status = i2cMasterTransmitTimeout(
155  (I2CDriver *)p->reg_addr,
156  (i2caddr_t)((t->slave_addr) >> 1),
157  (uint8_t *)t->buf, (size_t)(t->len_w),
158  (uint8_t *)t->buf, (size_t)(t->len_r),
159  tmo);
160 #endif
161  } else {
162 #if defined(STM32F7XX) || defined(STM32H7XX)
163  // we do stupid mem copy because F7 needs a special RAM for DMA operation
164  status = i2cMasterReceiveTimeout(
165  (I2CDriver *)p->reg_addr,
166  (i2caddr_t)((t->slave_addr) >> 1),
167  (uint8_t *)i->dma_buf, (size_t)(t->len_r),
168  tmo);
169  cacheBufferInvalidate(i->dma_buf, t->len_r);
170  memcpy((void *)t->buf, i->dma_buf, (size_t)(t->len_r));
171 #else
172  status = i2cMasterReceiveTimeout(
173  (I2CDriver *)p->reg_addr,
174  (i2caddr_t)((t->slave_addr) >> 1),
175  (uint8_t *)t->buf, (size_t)(t->len_r),
176  tmo);
177 #endif
178  }
179 
180  chSysLock();
181  // end of transaction, handle fifo
182  p->trans_extract_idx++;
183  if (p->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN) {
184  p->trans_extract_idx = 0;
185  }
186  p->status = I2CIdle;
187  chSysUnlock();
188 
189  // Set report status and errors
190  switch (status) {
191  case MSG_OK:
192  //if the function succeeded
193  t->status = I2CTransSuccess;
194  break;
195  case MSG_TIMEOUT:
196  //if a timeout occurred before operation end
197  // mark as failed
198  t->status = I2CTransFailed;
199  p->errors->unexpected_event_cnt++;
200  // Clear the bus if kept busy
201  if(i2c_read_sda(i) == 0) {
202  i2c_clear_bus(i);
203  }
204  i2cStart((I2CDriver *)p->reg_addr, &i->cfg);
205  break;
206  case MSG_RESET:
207  //if one or more I2C errors occurred, the errors can
208  //be retrieved using @p i2cGetErrors().
209  t->status = I2CTransFailed;
210  i2cflags_t errors = i2cGetErrors((I2CDriver *)p->reg_addr);
211  if (errors & I2C_BUS_ERROR) {
212  p->errors->miss_start_stop_cnt++;
213  }
214  if (errors & I2C_ARBITRATION_LOST) {
215  p->errors->arb_lost_cnt++;
216  }
217  if (errors & I2C_ACK_FAILURE) {
218  p->errors->ack_fail_cnt++;
219  }
220  if (errors & I2C_OVERRUN) {
221  p->errors->over_under_cnt++;
222  }
223  if (errors & I2C_PEC_ERROR) {
224  p->errors->pec_recep_cnt++;
225  }
226  if (errors & I2C_TIMEOUT) {
227  p->errors->timeout_tlow_cnt++;
228  }
229  if (errors & I2C_SMB_ALERT) {
230  p->errors->smbus_alert_cnt++;
231  }
232  break;
233  default:
234  break;
235  }
236 
237  i2cReleaseBus((I2CDriver *)p->reg_addr);
238 }
239 
245 static void thd_i2c(void *arg)
246 {
247  struct i2c_periph *i2cp = (struct i2c_periph *)arg;
248  struct i2c_init *init_s = (struct i2c_init *)i2cp->init_struct;
249  chRegSetThreadName(init_s->name);
250 
251  while (TRUE) {
252  handle_i2c_thd(i2cp);
253  }
254 }
255 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
256 
257 #if USE_I2C1
259 // Local variables (in DMA safe memory)
260 static IN_DMA_SECTION(struct i2c_init i2c1_init_s) = {
261  .name = "i2c1",
262  .sem = __SEMAPHORE_DATA(i2c1_init_s.sem, 0),
263  .cfg = I2C1_CFG_DEF,
264  .line_sda = LINE_I2C1_SDA,
265  .line_scl = LINE_I2C1_SCL
266 };
267 static THD_WORKING_AREA(wa_thd_i2c1, I2C_THREAD_STACK_SIZE);
268 
269 /*
270  * I2C1 init
271  */
272 void i2c1_hw_init(void)
273 {
274  i2c1.idle = i2c_chibios_idle;
275  i2c1.submit = i2c_chibios_submit;
276  i2c1.setbitrate = i2c_chibios_setbitrate;
277 
278  i2cStart(&I2CD1, &i2c1_init_s.cfg);
279  i2c1.reg_addr = &I2CD1;
280  i2c1.errors = &i2c1_init_s.errors;
281  i2c1.init_struct = &i2c1_init_s;
282  // Create thread
283  chThdCreateStatic(wa_thd_i2c1, sizeof(wa_thd_i2c1),
284  NORMALPRIO + 1, thd_i2c, (void *)&i2c1);
285 }
286 #endif /* USE_I2C1 */
287 
288 #if USE_I2C2
290 // Local variables (in DMA safe memory)
291 static IN_DMA_SECTION(struct i2c_init i2c2_init_s) = {
292  .name = "i2c2",
293  .sem = __SEMAPHORE_DATA(i2c2_init_s.sem, 0),
294  .cfg = I2C2_CFG_DEF,
295  .line_sda = LINE_I2C2_SDA,
296  .line_scl = LINE_I2C2_SCL
297 };
298 static THD_WORKING_AREA(wa_thd_i2c2, I2C_THREAD_STACK_SIZE);
299 
300 /*
301  * I2C2 init
302  */
303 void i2c2_hw_init(void)
304 {
305  i2c2.idle = i2c_chibios_idle;
306  i2c2.submit = i2c_chibios_submit;
307  i2c2.setbitrate = i2c_chibios_setbitrate;
308 
309  i2cStart(&I2CD2, &i2c2_init_s.cfg);
310  i2c2.reg_addr = &I2CD2;
311  i2c2.errors = &i2c2_init_s.errors;
312  i2c2.init_struct = &i2c2_init_s;
313  // Create thread
314  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
315  NORMALPRIO + 1, thd_i2c, (void *)&i2c2);
316 }
317 #endif /* USE_I2C2 */
318 
319 #if USE_I2C3
321 // Local variables (in DMA safe memory)
322 static IN_DMA_SECTION(struct i2c_init i2c3_init_s) = {
323  .name = "i2c3",
324  .sem = __SEMAPHORE_DATA(i2c3_init_s.sem, 0),
325  .cfg = I2C3_CFG_DEF,
326  .line_sda = LINE_I2C3_SDA,
327  .line_scl = LINE_I2C3_SCL
328 };
329 static THD_WORKING_AREA(wa_thd_i2c3, I2C_THREAD_STACK_SIZE);
330 
331 /*
332  * I2C3 init
333  */
334 void i2c3_hw_init(void)
335 {
336  i2c3.idle = i2c_chibios_idle;
337  i2c3.submit = i2c_chibios_submit;
338  i2c3.setbitrate = i2c_chibios_setbitrate;
339 
340  i2cStart(&I2CD3, &i2c3_init_s.cfg);
341  i2c3.reg_addr = &I2CD3;
342  i2c3.errors = &i2c3_init_s.errors;
343  i2c3.init_struct = &i2c3_init_s;
344  // Create thread
345  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
346  NORMALPRIO + 1, thd_i2c, (void *)&i2c3);
347 }
348 #endif /* USE_I2C3 */
349 
350 #if USE_I2C4
352 
353 #if defined(STM32H7XX)
354 // Local variables (in DMA safe memory)
355 static IN_BDMA_SECTION(struct i2c_init i2c4_init_s) = {
356 #else
357 // Local variables (in DMA safe memory)
358 static IN_DMA_SECTION(struct i2c_init i2c4_init_s) = {
359 #endif
360  .name = "i2c4",
361  .sem = __SEMAPHORE_DATA(i2c4_init_s.sem, 0),
362  .cfg = I2C4_CFG_DEF,
363  .line_sda = LINE_I2C4_SDA,
364  .line_scl = LINE_I2C4_SCL
365 };
366 static THD_WORKING_AREA(wa_thd_i2c4, I2C_THREAD_STACK_SIZE);
367 
368 /*
369  * I2C4 init
370  */
371 void i2c4_hw_init(void)
372 {
373  i2c4.idle = i2c_chibios_idle;
374  i2c4.submit = i2c_chibios_submit;
375  i2c4.setbitrate = i2c_chibios_setbitrate;
376 
377  i2cStart(&I2CD4, &i2c4_init_s.cfg);
378  i2c4.reg_addr = &I2CD4;
379  i2c4.errors = &i2c4_init_s.errors;
380  i2c4.init_struct = &i2c4_init_s;
381  // Create thread
382  chThdCreateStatic(wa_thd_i2c4, sizeof(wa_thd_i2c4),
383  NORMALPRIO + 1, thd_i2c, (void *)&i2c4);
384 }
385 #endif /* USE_I2C4 */
386 
387 
393 void i2c_event(void) {}
394 
401 static void i2c_chibios_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
402 
420 static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
421 {
422 #if USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4
423  // sys lock
424  chSysLock();
425  uint8_t temp;
426  temp = p->trans_insert_idx + 1;
427  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
428  if (temp == p->trans_extract_idx) {
429  // queue full
430  p->errors->queue_full_cnt++;
431  t->status = I2CTransFailed;
432  chSysUnlock();
433  return FALSE;
434  }
435 
436  t->status = I2CTransPending;
437 
438  /* put transacation in queue */
439  p->trans[p->trans_insert_idx] = t;
440  p->trans_insert_idx = temp;
441 
442  chSysUnlock();
443  chSemSignal(&((struct i2c_init *)p->init_struct)->sem);
444  // transaction submitted
445  return TRUE;
446 #else
447  // if no I2C peripheral is used fill in with dummy function
448  (void)p;
449  (void)t;
450  return FALSE;
451 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
452 }
453 
459 static bool i2c_chibios_idle(struct i2c_periph *p __attribute__((unused)))
460 {
461  return FALSE;
462 }
#define LINE_I2C1_SDA
Definition: board.h:773
#define LINE_I2C2_SDA
Definition: board.h:777
#define LINE_I2C2_SCL
Definition: board.h:776
#define LINE_I2C1_SCL
Definition: board.h:774
#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:459
static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:420
static void i2c_chibios_setbitrate(struct i2c_periph *p, int bitrate)
i2c_setbitrate() function
Definition: i2c_arch.c:401
#define I2C1_CLOCK_SPEED
Definition: common_board.h:548
#define I2C3_CFG_DEF
Definition: common_board.h:592
#define I2C4_CFG_DEF
Definition: common_board.h:612
#define I2C1_CFG_DEF
Definition: common_board.h:552
#define I2C3_CLOCK_SPEED
Definition: common_board.h:588
#define I2C2_CLOCK_SPEED
Definition: common_board.h:568
#define I2C2_CFG_DEF
Definition: common_board.h:572
#define I2C4_CLOCK_SPEED
Definition: common_board.h:608
#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:393
#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
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
Specific RAM section for DMA usage on F7.
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:87
#define IN_BDMA_SECTION(var)
Definition: ram_arch.h:91
#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