Paparazzi UAS  v5.14.0_stable-0-g3f680d1
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 = TIME_US2I(10000000 / 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, 128);
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, 128);
256 
257 /*
258  * I2C2 init
259  */
260 void i2c2_hw_init(void)
261 {
262  i2cStart(&I2CD2, &i2cfg2);
263  i2c2.reg_addr = &I2CD2;
264  i2c2.errors = &i2c2_errors;
265  i2c2.init_struct = &i2c2_init_s;
266  // Create thread
267  chThdCreateStatic(wa_thd_i2c2, sizeof(wa_thd_i2c2),
268  NORMALPRIO + 1, thd_i2c2, NULL);
269 }
270 
271 /*
272  * I2C2 thread
273  *
274  */
275 static void thd_i2c2(void *arg)
276 {
277  (void) arg;
278  chRegSetThreadName("i2c2");
279 
280  while (TRUE) {
281  handle_i2c_thd(&i2c2);
282  }
283 }
284 #endif /* USE_I2C2 */
285 
286 #if USE_I2C3
287 // I2C3 config
288 PRINT_CONFIG_VAR(I2C3_CLOCK_SPEED)
289 static SEMAPHORE_DECL(i2c3_sem, 0);
290 static I2CConfig i2cfg3 = I2C3_CFG_DEF;
291 #if defined STM32F7
292 // We need a special buffer for DMA operations
293 static IN_DMA_SECTION(uint8_t i2c3_dma_buf[I2C_BUF_LEN]);
294 static struct i2c_init i2c3_init_s = {
295  .sem = &i2c3_sem,
296  .cfg = &i2cfg3,
297  .dma_buf = i2c3_dma_buf
298 };
299 #else
300 static struct i2c_init i2c3_init_s = {
301  .sem = &i2c3_sem,
302  .cfg = &i2cfg3
303 };
304 #endif
305 // Errors
306 struct i2c_errors i2c3_errors;
307 // Thread
308 static __attribute__((noreturn)) void thd_i2c3(void *arg);
309 static THD_WORKING_AREA(wa_thd_i2c3, 128);
310 
311 /*
312  * I2C3 init
313  */
314 void i2c3_hw_init(void)
315 {
316  i2cStart(&I2CD3, &i2cfg3);
317  i2c3.reg_addr = &I2CD3;
318  i2c3.init_struct = NULL;
319  i2c3.errors = &i2c3_errors;
320  i2c3.init_struct = &i2c3_init_s;
321  // Create thread
322  chThdCreateStatic(wa_thd_i2c3, sizeof(wa_thd_i2c3),
323  NORMALPRIO + 1, thd_i2c3, NULL);
324 }
325 
326 /*
327  * I2C3 thread
328  *
329  */
330 static void thd_i2c3(void *arg)
331 {
332  (void) arg;
333  chRegSetThreadName("i2c3");
334 
335  while (TRUE) {
336  handle_i2c_thd(&i2c3);
337  }
338 }
339 #endif /* USE_I2C3 */
340 
341 
347 void i2c_event(void) {}
348 
355 void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
356 
374 bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
375 {
376 #if USE_I2C1 || USE_I2C2 || USE_I2C3
377  // sys lock
378  chSysLock();
379  uint8_t temp;
380  temp = p->trans_insert_idx + 1;
381  if (temp >= I2C_TRANSACTION_QUEUE_LEN) { temp = 0; }
382  if (temp == p->trans_extract_idx) {
383  // queue full
384  p->errors->queue_full_cnt++;
385  t->status = I2CTransFailed;
386  chSysUnlock();
387  return FALSE;
388  }
389 
390  t->status = I2CTransPending;
391 
392  /* put transacation in queue */
393  p->trans[p->trans_insert_idx] = t;
394  p->trans_insert_idx = temp;
395 
396  chSysUnlock();
397  chSemSignal(((struct i2c_init *)p->init_struct)->sem);
398  // transaction submitted
399  return TRUE;
400 #else
401  // if no I2C peripheral is used fill in with dummy function
402  (void)p;
403  (void)t;
404  return FALSE;
405 #endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 */
406 }
407 
413 bool i2c_idle(struct i2c_periph *p __attribute__((unused)))
414 {
415  return FALSE;
416 }
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:410
uint8_t trans_extract_idx
Definition: i2c.h:142
void i2c_init(struct i2c_periph *p)
Initialize I2C peripheral.
Definition: i2c.c:246
bool i2c_idle(struct i2c_periph *p)
i2c_idle() function
Definition: i2c_arch.c:413
Definition: i2c.h:66
volatile uint16_t queue_full_cnt
Definition: i2c.h:156
static THD_WORKING_AREA(wa_thd_spi1, 256)
void i2c_setbitrate(struct i2c_periph *p, int bitrate)
i2c_setbitrate() function
Definition: i2c_arch.c:355
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
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
bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
i2c_submit() function
Definition: i2c_arch.c:374
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:426
#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]
volatile uint16_t smbus_alert_cnt
Definition: i2c.h:163
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:347
#define I2C1_CLOCK_SPEED
I2C defines.
Definition: board.h:401
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:417
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.