Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
i2c_arch.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
4  * 2018 Kirk Scheper <kirkscheper@gmail.com>
5  *
6  * This file is part of paparazzi.
7  *
8  * paparazzi is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2, or (at your option)
11  * any later version.
12  *
13  * paparazzi is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with paparazzi; see the file COPYING. If not, write to
20  * the Free Software Foundation, 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  *
23  */
24 
29 #include "mcu_periph/i2c.h"
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <sys/ioctl.h>
34 #include <linux/i2c.h>
35 #include <linux/i2c-dev.h>
36 #include <errno.h>
37 
38 #include <pthread.h>
39 #include "rt_priority.h"
40 
41 #ifndef I2C_THREAD_PRIO
42 #define I2C_THREAD_PRIO 10
43 #endif
44 
45 
46 static bool i2c_linux_idle(struct i2c_periph *p __attribute__((unused))) __attribute__((unused));
47 static bool i2c_linux_submit(struct i2c_periph *p, struct i2c_transaction *t) __attribute__((unused));
48 static void i2c_linux_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) __attribute__((unused));
49 
50 
51 static void *i2c_thread(void *thread_data);
52 
53 // private I2C init structure
54 struct i2c_thread_t {
55  pthread_mutex_t mutex;
56  pthread_cond_t condition;
57 };
58 
59 static void UNUSED i2c_arch_init(struct i2c_periph *p)
60 {
61  pthread_t tid;
62  if (pthread_create(&tid, NULL, i2c_thread, (void *)p) != 0) {
63  fprintf(stderr, "i2c_arch_init: Could not create I2C thread.\n");
64  return;
65  }
66 #ifndef __APPLE__
67  pthread_setname_np(tid, "i2c");
68 #endif
69 }
70 
71 void i2c_event(void)
72 {
73 }
74 
75 static void i2c_linux_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused)))
76 {
77 }
78 
79 static bool i2c_linux_idle(struct i2c_periph *p __attribute__((unused)))
80 {
81  return true;
82 }
83 
84 static bool i2c_linux_submit(struct i2c_periph *p, struct i2c_transaction *t)
85 {
86  // get mutex lock and condition
87  pthread_mutex_t *mutex = &(((struct i2c_thread_t *)(p->init_struct))->mutex);
88  pthread_cond_t *condition = &(((struct i2c_thread_t *)(p->init_struct))->condition);
89 
90  uint8_t next_idx;
91  pthread_mutex_lock(mutex);
92  next_idx = (p->trans_insert_idx + 1) % I2C_TRANSACTION_QUEUE_LEN;
93  if (next_idx == p->trans_extract_idx) {
94  // queue full
95  p->errors->queue_full_cnt++;
97  pthread_mutex_unlock(mutex);
98  return false;
99  }
100 
101  t->status = I2CTransPending;
102 
103  /* put transaction in queue */
104  p->trans[p->trans_insert_idx] = t;
105  p->trans_insert_idx = next_idx;
106 
107  /* wake handler thread */
108  pthread_cond_signal(condition);
109  pthread_mutex_unlock(mutex);
110 
111  return true;
112 }
113 
114 /*
115  * Transactions handler thread
116  */
117 #pragma GCC diagnostic push
118 #pragma GCC diagnostic ignored "-Wcast-qual"
119 static void *i2c_thread(void *data)
120 {
121  struct i2c_msg trx_msgs[2];
122  struct i2c_rdwr_ioctl_data trx_data = {
123  .msgs = trx_msgs,
124  .nmsgs = 2
125  };
126 
128 
129  struct i2c_periph *p = (struct i2c_periph *)data;
130  pthread_mutex_t *mutex = &(((struct i2c_thread_t *)(p->init_struct))->mutex);
131  pthread_cond_t *condition = &(((struct i2c_thread_t *)(p->init_struct))->condition);
132 
133  while (1) {
134  /* wait for data to transfer */
135  pthread_mutex_lock(mutex);
136  if (p->trans_insert_idx == p->trans_extract_idx) {
137  pthread_cond_wait(condition, mutex);
138  }
139 
140  int fd = (int)p->reg_addr;
141  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
142  pthread_mutex_unlock(mutex);
143 
144  // Switch the different transaction types
145  switch (t->type) {
146  // Just transmitting
147  case I2CTransTx:
148  // Set the slave address, converted to 7 bit
149  ioctl(fd, I2C_SLAVE, t->slave_addr >> 1);
150  if (write(fd, (uint8_t *)t->buf, t->len_w) < 0) {
151  /* if write failed, increment error counter ack_fail_cnt */
152  pthread_mutex_lock(mutex);
153  p->errors->ack_fail_cnt++;
154  pthread_mutex_unlock(mutex);
155  t->status = I2CTransFailed;
156  } else {
157  t->status = I2CTransSuccess;
158  }
159  break;
160  // Just reading
161  case I2CTransRx:
162  // Set the slave address, converted to 7 bit
163  ioctl(fd, I2C_SLAVE, t->slave_addr >> 1);
164  if (read(fd, (uint8_t *)t->buf, t->len_r) < 0) {
165  /* if read failed, increment error counter arb_lost_cnt */
166  pthread_mutex_lock(mutex);
167  p->errors->arb_lost_cnt++;
168  pthread_mutex_unlock(mutex);
169  t->status = I2CTransFailed;
170  } else {
171  t->status = I2CTransSuccess;
172  }
173  break;
174  // First Transmit and then read with repeated start
175  case I2CTransTxRx:
176  trx_msgs[0].addr = t->slave_addr >> 1;
177  trx_msgs[0].flags = 0; /* tx */
178  trx_msgs[0].len = t->len_w;
179  trx_msgs[0].buf = (void *) t->buf;
180  trx_msgs[1].addr = t->slave_addr >> 1;
181  trx_msgs[1].flags = I2C_M_RD;
182  trx_msgs[1].len = t->len_r;
183  trx_msgs[1].buf = (void *) t->buf;
184  if (ioctl(fd, I2C_RDWR, &trx_data) < 0) {
185  /* if write/read failed, increment error counter miss_start_stop_cnt */
186  pthread_mutex_lock(mutex);
187  p->errors->miss_start_stop_cnt++;
188  pthread_mutex_unlock(mutex);
189  t->status = I2CTransFailed;
190  } else {
191  t->status = I2CTransSuccess;
192  }
193  break;
194  default:
195  t->status = I2CTransFailed;
196  break;
197  }
198 
199  pthread_mutex_lock(mutex);
200  p->trans_extract_idx = (p->trans_extract_idx + 1) % I2C_TRANSACTION_QUEUE_LEN;
201  pthread_mutex_unlock(mutex);
202  }
203  return NULL;
204 }
205 #pragma GCC diagnostic pop
206 
207 #if USE_I2C0
208 struct i2c_errors i2c0_errors;
209 struct i2c_thread_t i2c0_thread;
210 
211 void i2c0_hw_init(void)
212 {
213  i2c0.idle = i2c_linux_idle;
214  i2c0.submit = i2c_linux_submit;
215  i2c0.setbitrate = i2c_linux_setbitrate;
216 
217  i2c0.reg_addr = (void *)open("/dev/i2c-0", O_RDWR);
218  i2c0.errors = &i2c0_errors;
219 
220  /* zeros error counter */
221  ZEROS_ERR_COUNTER(i2c0_errors);
222 
223  pthread_mutex_init(&i2c0_thread.mutex, NULL);
224  pthread_cond_init(&i2c0_thread.condition, NULL);
225  i2c0.init_struct = (void *)(&i2c0_thread);
226 
227  i2c_arch_init(&i2c0);
228 }
229 #endif
230 
231 #if USE_I2C1
232 struct i2c_errors i2c1_errors;
233 struct i2c_thread_t i2c1_thread;
234 
235 void i2c1_hw_init(void)
236 {
237  i2c1.idle = i2c_linux_idle;
238  i2c1.submit = i2c_linux_submit;
239  i2c1.setbitrate = i2c_linux_setbitrate;
240 
241  i2c1.reg_addr = (void *)open("/dev/i2c-1", O_RDWR);
242  i2c1.errors = &i2c1_errors;
243 
244  /* zeros error counter */
245  ZEROS_ERR_COUNTER(i2c1_errors);
246 
247  pthread_mutex_init(&i2c1_thread.mutex, NULL);
248  pthread_cond_init(&i2c1_thread.condition, NULL);
249  i2c1.init_struct = (void *)(&i2c1_thread);
250 
251  i2c_arch_init(&i2c1);
252 }
253 #endif
254 
255 #if USE_I2C2
256 struct i2c_errors i2c2_errors;
257 struct i2c_thread_t i2c2_thread;
258 
259 void i2c2_hw_init(void)
260 {
261  i2c2.idle = i2c_linux_idle;
262  i2c2.submit = i2c_linux_submit;
263  i2c2.setbitrate = i2c_linux_setbitrate;
264 
265  i2c2.reg_addr = (void *)open("/dev/i2c-2", O_RDWR);
266  i2c2.errors = &i2c2_errors;
267 
268  /* zeros error counter */
269  ZEROS_ERR_COUNTER(i2c2_errors);
270 
271  pthread_mutex_init(&i2c2_thread.mutex, NULL);
272  pthread_cond_init(&i2c2_thread.condition, NULL);
273  i2c2.init_struct = (void *)(&i2c2_thread);
274 
275  i2c_arch_init(&i2c2);
276 }
277 #endif
278 
279 #if USE_I2C3
280 struct i2c_errors i2c3_errors;
281 struct i2c_thread_t i2c3_thread;
282 
283 void i2c3_hw_init(void)
284 {
285  i2c3.idle = i2c_linux_idle;
286  i2c3.submit = i2c_linux_submit;
287  i2c3.setbitrate = i2c_linux_setbitrate;
288 
289  i2c3.reg_addr = (void *)open("/dev/i2c-3", O_RDWR);
290  i2c3.errors = &i2c3_errors;
291 
292  /* zeros error counter */
293  ZEROS_ERR_COUNTER(i2c3_errors);
294 
295  pthread_mutex_init(&i2c3_thread.mutex, NULL);
296  pthread_cond_init(&i2c3_thread.condition, NULL);
297  i2c3.init_struct = (void *)(&i2c3_thread);
298 
299  i2c_arch_init(&i2c3);
300 }
301 #endif
rt_priority.h
I2C_M_RD
#define I2C_M_RD
Definition: i2c_smbus.h:44
i2c_linux_idle
static bool i2c_linux_idle(struct i2c_periph *p)
Definition: i2c_arch.c:79
I2CTransTx
@ I2CTransTx
transmit only transaction
Definition: i2c.h:47
i2c_event
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:428
mutex
static pthread_mutex_t mutex
Definition: cv_detect_color_object.c:46
I2CTransFailed
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
UNUSED
uint8_t last_wp UNUSED
Definition: navigation.c:96
i2c_arch_init
static void UNUSED i2c_arch_init(struct i2c_periph *p)
Definition: i2c_arch.c:59
i2c_thread_t::condition
pthread_cond_t condition
Definition: i2c_arch.c:56
i2c_errors
I2C errors counter.
Definition: i2c.h:165
i2c_thread_t::mutex
pthread_mutex_t mutex
Definition: i2c_arch.c:55
I2C_THREAD_PRIO
#define I2C_THREAD_PRIO
Definition: i2c_arch.c:42
I2CTransSuccess
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
i2c_msg::len
short len
Definition: i2c_smbus.h:49
i2c_linux_submit
static bool i2c_linux_submit(struct i2c_periph *p, struct i2c_transaction *t)
Definition: i2c_arch.c:84
I2CTransRx
@ I2CTransRx
receive only transaction
Definition: i2c.h:48
i2c_linux_setbitrate
static void i2c_linux_setbitrate(struct i2c_periph *p, int bitrate)
Definition: i2c_arch.c:75
i2c_thread
static void * i2c_thread(void *thread_data)
Definition: i2c_arch.c:119
uint8_t
unsigned char uint8_t
Definition: types.h:14
i2c_transaction::status
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
I2CTransTxRx
@ I2CTransTxRx
transmit and receive transaction
Definition: i2c.h:49
i2c_transaction
I2C transaction structure.
Definition: i2c.h:93
i2c_msg::buf
char * buf
Definition: i2c_smbus.h:50
I2C_RDWR
#define I2C_RDWR
Definition: i2c_smbus.h:138
i2c_thread_t
Definition: i2c_arch.c:54
fd
int fd
Definition: serial.c:26
get_rt_prio
static int get_rt_prio(int prio)
Definition: rt_priority.h:32
I2C_TRANSACTION_QUEUE_LEN
#define I2C_TRANSACTION_QUEUE_LEN
I2C transaction queue length.
Definition: i2c.h:133
i2c_msg::flags
unsigned short flags
Definition: i2c_smbus.h:42
ZEROS_ERR_COUNTER
#define ZEROS_ERR_COUNTER(_i2c_err)
Definition: i2c.h:181
I2CTransPending
@ I2CTransPending
transaction is pending in queue
Definition: i2c.h:55
i2c_periph
Definition: i2c.h:144
i2c_msg::addr
__u16 addr
Definition: i2c_smbus.h:41
i2c.h
I2C_SLAVE
#define I2C_SLAVE
Definition: i2c_smbus.h:129
p
static float p[2][2]
Definition: ins_alt_float.c:268
i2c_msg
Definition: i2c_smbus.h:40