Paparazzi UAS  v5.12_stable-4-g9b43e9b
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 
45 #if USE_I2C1 || USE_I2C2 || USE_I2C3
46 
47 // private I2C init structure
48 struct i2c_init {
49  semaphore_t *sem;
50  I2CConfig *cfg;
51 #ifdef STM32F7
52  uint8_t *dma_buf;
53 #endif
54 };
55 
56 
57 static void handle_i2c_thd(struct i2c_periph *p);
58 
59 // Timeout for I2C transaction
60 static const systime_t tmo = US2ST(1000000/PERIODIC_FREQUENCY);
61 
67 static void handle_i2c_thd(struct i2c_periph *p)
68 {
69  struct i2c_init *i = (struct i2c_init *) p->init_struct;
70 
71  // wait for a transaction to be pushed in the queue
72  chSemWait (i->sem);
73 
74  if (p->trans_insert_idx == p->trans_extract_idx) {
75  p->status = I2CIdle;
76  // no transaction pending
77  return;
78  }
79 
80  // Get next transation in queue
81  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
82 
84  msg_t status;
85  // submit i2c transaction (R/W or R only depending of len_w)
86  if (t->len_w > 0) {
87 #if defined STM32F7
88  // we do stupid mem copy because F7 needs a special RAM for DMA operation
89  memcpy(i->dma_buf, (void*)t->buf, (size_t)(t->len_w));
90  status = i2cMasterTransmitTimeout(
91  (I2CDriver*)p->reg_addr,
92  (i2caddr_t)((t->slave_addr)>>1),
93  (uint8_t*)i->dma_buf, (size_t)(t->len_w),
94  (uint8_t*)i->dma_buf, (size_t)(t->len_r),
95  tmo);
96  memcpy((void*)t->buf, i->dma_buf, (size_t)(t->len_r));
97 #else
98  status = i2cMasterTransmitTimeout(
99  (I2CDriver*)p->reg_addr,
100  (i2caddr_t)((t->slave_addr)>>1),
101  (uint8_t*)t->buf, (size_t)(t->len_w),
102  (uint8_t*)t->buf, (size_t)(t->len_r),
103  tmo);
104 #endif
105  } else {
106 #if defined STM32F7
107  // we do stupid mem copy because F7 needs a special RAM for DMA operation
108  memcpy(i->dma_buf, (void*)t->buf, (size_t)(t->len_w));
109  status = i2cMasterReceiveTimeout(
110  (I2CDriver*)p->reg_addr,
111  (i2caddr_t)((t->slave_addr)>>1),
112  (uint8_t*)i->dma_buf, (size_t)(t->len_r),
113  tmo);
114  memcpy((void*)t->buf, i->dma_buf, (size_t)(t->len_r));
115 #else
116  status = i2cMasterReceiveTimeout(
117  (I2CDriver*)p->reg_addr,
118  (i2caddr_t)((t->slave_addr)>>1),
119  (uint8_t*)t->buf, (size_t)(t->len_r),
120  tmo);
121 #endif
122  }
123 
124  chSysLock();
125  // end of transaction, handle fifo
126  p->trans_extract_idx++;
128  p->trans_extract_idx = 0;
129  }
130  p->status = I2CIdle;
131  chSysUnlock();
132 
133  // Set report status and errors
134  switch (status) {
135  case MSG_OK:
136  //if the function succeeded
137  t->status = I2CTransSuccess;
138  break;
139  case MSG_TIMEOUT:
140  //if a timeout occurred before operation end
141  // mark as failed and restart
142  t->status = I2CTransFailed;
143  i2cStart((I2CDriver*)p->reg_addr, i->cfg);
144  break;
145  case MSG_RESET:
146  //if one or more I2C errors occurred, the errors can
147  //be retrieved using @p i2cGetErrors().
148  t->status = I2CTransFailed;
149  i2cflags_t errors = i2cGetErrors((I2CDriver*)p->reg_addr);
150  if (errors & I2C_BUS_ERROR) {
152  }
153  if (errors & I2C_ARBITRATION_LOST) {
154  p->errors->arb_lost_cnt++;
155  }
156  if (errors & I2C_ACK_FAILURE) {
157  p->errors->ack_fail_cnt++;
158  }
159  if (errors & I2C_OVERRUN) {
160  p->errors->over_under_cnt++;
161  }
162  if (errors & I2C_PEC_ERROR) {
163  p->errors->pec_recep_cnt++;
164  }
165  if (errors & I2C_TIMEOUT) {
166  p->errors->timeout_tlow_cnt++;
167  }
168  if (errors & I2C_SMB_ALERT) {
169  p->errors->smbus_alert_cnt++;
170  }
171  break;
172  default:
173  break;
174  }
175 }
176 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 */
177 
178 #if USE_I2C1
179 // I2C1 config
180 PRINT_CONFIG_VAR(I2C1_CLOCK_SPEED)
181 static SEMAPHORE_DECL(i2c1_sem, 0);
182 static I2CConfig i2cfg1 = I2C1_CFG_DEF;
183 #if defined STM32F7
184 // We need a special buffer for DMA operations
185 static IN_DMA_SECTION(uint8_t i2c1_dma_buf[I2C_BUF_LEN]);
186 static struct i2c_init i2c1_init_s = {
187  .sem = &i2c1_sem,
188  .cfg = &i2cfg1,
189  .dma_buf = i2c1_dma_buf
190 };
191 #else
192 static struct i2c_init i2c1_init_s = {
193  .sem = &i2c1_sem,
194  .cfg = &i2cfg1
195 };
196 #endif
197 // Errors
198 struct i2c_errors i2c1_errors;
199 // Thread
200 static __attribute__((noreturn)) void thd_i2c1(void *arg);
201 static THD_WORKING_AREA(wa_thd_i2c1, 1024);
202 
203 /*
204  * I2C1 init
205  */
206 void i2c1_hw_init(void)
207 {
208  i2cStart(&I2CD1, &i2cfg1);
209  i2c1.reg_addr = &I2CD1;
210  i2c1.errors = &i2c1_errors;
211  i2c1.init_struct = &i2c1_init_s;
212  // Create thread
213  chThdCreateStatic(wa_thd_i2c1, sizeof(wa_thd_i2c1),
214  NORMALPRIO+1, thd_i2c1, NULL);
215 }
216 
217 /*
218  * I2C1 thread
219  *
220  */
221 static void thd_i2c1(void *arg)
222 {
223  (void) arg;
224  chRegSetThreadName("i2c1");
225 
226  while (TRUE) {
227  handle_i2c_thd(&i2c1);
228  }
229 }
230 #endif /* USE_I2C1 */
231 
232 #if USE_I2C2
233 // I2C2 config
234 PRINT_CONFIG_VAR(I2C2_CLOCK_SPEED)
235 static SEMAPHORE_DECL(i2c2_sem, 0);
236 static I2CConfig i2cfg2 = I2C2_CFG_DEF;
237 #if defined STM32F7
238 // We need a special buffer for DMA operations
239 static IN_DMA_SECTION(uint8_t i2c2_dma_buf[I2C_BUF_LEN]);
240 static struct i2c_init i2c2_init_s = {
241  .sem = &i2c2_sem,
242  .cfg = &i2cfg2,
243  .dma_buf = i2c2_dma_buf
244 };
245 #else
246 static struct i2c_init i2c2_init_s = {
247  .sem = &i2c2_sem,
248  .cfg = &i2cfg2
249 };
250 #endif
251 // Errors
252 struct i2c_errors i2c2_errors;
253 // Thread
254 static __attribute__((noreturn)) void thd_i2c2(void *arg);
255 static THD_WORKING_AREA(wa_thd_i2c2, 1024);
256 
257 /*
258  * I2C2 init
259  */
260 void i2c2_hw_init(void)
261 {
262  i2cStart(&I2CD2, &i2cfg2);
263  i2c2.reg_addr = &I2CD2;
264  i2c2.init_struct = NULL;
265  i2c2.errors = &i2c2_errors;
266  i2c2.init_struct = &i2c2_init_s;
267  // Create thread
268  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
269  NORMALPRIO+1, thd_i2c2, NULL);
270 }
271 
272 /*
273  * I2C2 thread
274  *
275  */
276 static void thd_i2c2(void *arg)
277 {
278  (void) arg;
279  chRegSetThreadName("i2c2");
280 
281  while (TRUE) {
282  handle_i2c_thd(&i2c2);
283  }
284 }
285 #endif /* USE_I2C2 */
286 
287 #if USE_I2C3
288 // I2C3 config
289 PRINT_CONFIG_VAR(I2C3_CLOCK_SPEED)
290 static SEMAPHORE_DECL(i2c3_sem, 0);
291 static I2CConfig i2cfg3 = I2C3_CFG_DEF;
292 #if defined STM32F7
293 // We need a special buffer for DMA operations
294 static IN_DMA_SECTION(uint8_t i2c3_dma_buf[I2C_BUF_LEN]);
295 static struct i2c_init i2c3_init_s = {
296  .sem = &i2c3_sem,
297  .cfg = &i2cfg3,
298  .dma_buf = i2c3_dma_buf
299 };
300 #else
301 static struct i2c_init i2c3_init_s = {
302  .sem = &i2c3_sem,
303  .cfg = &i2cfg3
304 };
305 #endif
306 // Errors
307 struct i2c_errors i2c3_errors;
308 // Thread
309 static __attribute__((noreturn)) void thd_i2c3(void *arg);
310 static THD_WORKING_AREA(wa_thd_i2c3, 1024);
311 
312 /*
313  * I2C3 init
314  */
315 void i2c3_hw_init(void)
316 {
317  i2cStart(&I2CD3, &i2cfg3);
318  i2c3.reg_addr = &I2CD3;
319  i2c3.init_struct = NULL;
320  i2c3.errors = &i2c3_errors;
321  i2c3.init_struct = &i2c3_init_s;
322  // Create thread
323  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
324  NORMALPRIO+1, thd_i2c3, NULL);
325 }
326 
327 /*
328  * I2C3 thread
329  *
330  */
331 static void thd_i2c3(void *arg)
332 {
333  (void) arg;
334  chRegSetThreadName("i2c3");
335 
336  while (TRUE) {
337  handle_i2c_thd(&i2c3);
338  }
339 }
340 #endif /* USE_I2C3 */
341 
342 
348 void i2c_event(void) {}
349 
356 void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
357 
375 bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
376 {
377 #if USE_I2C1 || USE_I2C2 || USE_I2C3
378  // sys lock
379  chSysLock();
380  uint8_t temp;
381  temp = p->trans_insert_idx + 1;
382  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
383  if (temp == p->trans_extract_idx) {
384  // queue full
385  p->errors->queue_full_cnt++;
386  t->status = I2CTransFailed;
387  chSysUnlock();
388  return FALSE;
389  }
390 
391  t->status = I2CTransPending;
392 
393  /* put transacation in queue */
394  p->trans[p->trans_insert_idx] = t;
395  p->trans_insert_idx = temp;
396 
397  chSysUnlock();
398  chSemSignal (((struct i2c_init *)p->init_struct)->sem);
399  // transaction submitted
400  return TRUE;
401 #else
402  // if no I2C peripheral is used fill in with dummy function
403  (void)p;
404  (void)t;
405  return FALSE;
406 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 */
407 }
408 
414 bool i2c_idle(struct i2c_periph *p __attribute__((unused)))
415 {
416  return FALSE;
417 }
Specific RAM section for DMA usage on F7.
volatile uint16_t arb_lost_cnt
Definition: i2c.h:159
status
Definition: anemotaxis.c:10
#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:954
uint8_t trans_extract_idx
Definition: i2c.h:142
void i2c_init(struct i2c_periph *p)
Initialize I2C peripheral.
Definition: i2c.c:245
bool i2c_idle(struct i2c_periph *p)
i2c_idle() function
Definition: i2c_arch.c:414
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:356
struct i2c_errors * errors
Definition: i2c.h:148
enum I2CStatus status
Definition: i2c.h:144
#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
struct i2c_transaction * trans[I2C_TRANSACTION_QUEUE_LEN]
Definition: i2c.h:140
volatile uint16_t over_under_cnt
Definition: i2c.h:160
bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:375
transaction failed
Definition: i2c.h:58
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:970
#define IN_DMA_SECTION(var)
Definition: ram_arch.h:67
unsigned char uint8_t
Definition: types.h:14
#define I2C_BUF_LEN
I2C buffer length.
Definition: i2c.h:84
static float p[2][2]
volatile uint16_t smbus_alert_cnt
Definition: i2c.h:163
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:348
#define I2C1_CLOCK_SPEED
I2C defines.
Definition: board.h:945
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:961
transaction is pending in queue
Definition: i2c.h:55
static THD_WORKING_AREA(wa_thd_spi1, 1024)
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.