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  *
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 static void *i2c_thread(void *thread_data);
46 
47 // private I2C init structure
48 struct i2c_thread_t {
49  pthread_mutex_t mutex;
50  pthread_cond_t condition;
51 };
52 
53 static void UNUSED i2c_arch_init(struct i2c_periph *p)
54 {
55  pthread_t tid;
56  if (pthread_create(&tid, NULL, i2c_thread, (void *)p) != 0) {
57  fprintf(stderr, "i2c_arch_init: Could not create I2C thread.\n");
58  return;
59  }
60 #ifndef __APPLE__
61  pthread_setname_np(tid, "i2c");
62 #endif
63 }
64 
65 void i2c_event(void)
66 {
67 }
68 
69 void i2c_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused)))
70 {
71 }
72 
73 bool i2c_idle(struct i2c_periph *p __attribute__((unused)))
74 {
75  return true;
76 }
77 
78 bool i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
79 {
80  // get mutex lock and condition
81  pthread_mutex_t *mutex = &(((struct i2c_thread_t *)(p->init_struct))->mutex);
82  pthread_cond_t *condition = &(((struct i2c_thread_t *)(p->init_struct))->condition);
83 
84  uint8_t next_idx;
85  pthread_mutex_lock(mutex);
86  next_idx = (p->trans_insert_idx + 1) % I2C_TRANSACTION_QUEUE_LEN;
87  if (next_idx == p->trans_extract_idx) {
88  // queue full
89  p->errors->queue_full_cnt++;
91  pthread_mutex_unlock(mutex);
92  return false;
93  }
94 
96 
97  /* put transaction in queue */
98  p->trans[p->trans_insert_idx] = t;
99  p->trans_insert_idx = next_idx;
100 
101  /* wake handler thread */
102  pthread_cond_signal(condition);
103  pthread_mutex_unlock(mutex);
104 
105  return true;
106 }
107 
108 /*
109  * Transactions handler thread
110  */
111 #pragma GCC diagnostic push
112 #pragma GCC diagnostic ignored "-Wcast-qual"
113 static void *i2c_thread(void *data)
114 {
115  struct i2c_msg trx_msgs[2];
116  struct i2c_rdwr_ioctl_data trx_data = {
117  .msgs = trx_msgs,
118  .nmsgs = 2
119  };
120 
122 
123  struct i2c_periph *p = (struct i2c_periph *)data;
124  pthread_mutex_t *mutex = &(((struct i2c_thread_t *)(p->init_struct))->mutex);
125  pthread_cond_t *condition = &(((struct i2c_thread_t *)(p->init_struct))->condition);
126 
127  while (1) {
128  /* wait for data to transfer */
129  pthread_mutex_lock(mutex);
130  if (p->trans_insert_idx == p->trans_extract_idx) {
131  pthread_cond_wait(condition, mutex);
132  }
133 
134  int fd = (int)p->reg_addr;
135  struct i2c_transaction *t = p->trans[p->trans_extract_idx];
136  pthread_mutex_unlock(mutex);
137 
138  // Switch the different transaction types
139  switch (t->type) {
140  // Just transmitting
141  case I2CTransTx:
142  // Set the slave address, converted to 7 bit
143  ioctl(fd, I2C_SLAVE, t->slave_addr >> 1);
144  if (write(fd, (uint8_t *)t->buf, t->len_w) < 0) {
145  /* if write failed, increment error counter ack_fail_cnt */
146  pthread_mutex_lock(mutex);
147  p->errors->ack_fail_cnt++;
148  pthread_mutex_unlock(mutex);
149  t->status = I2CTransFailed;
150  } else {
151  t->status = I2CTransSuccess;
152  }
153  break;
154  // Just reading
155  case I2CTransRx:
156  // Set the slave address, converted to 7 bit
157  ioctl(fd, I2C_SLAVE, t->slave_addr >> 1);
158  if (read(fd, (uint8_t *)t->buf, t->len_r) < 0) {
159  /* if read failed, increment error counter arb_lost_cnt */
160  pthread_mutex_lock(mutex);
161  p->errors->arb_lost_cnt++;
162  pthread_mutex_unlock(mutex);
163  t->status = I2CTransFailed;
164  } else {
165  t->status = I2CTransSuccess;
166  }
167  break;
168  // First Transmit and then read with repeated start
169  case I2CTransTxRx:
170  trx_msgs[0].addr = t->slave_addr >> 1;
171  trx_msgs[0].flags = 0; /* tx */
172  trx_msgs[0].len = t->len_w;
173  trx_msgs[0].buf = (void *) t->buf;
174  trx_msgs[1].addr = t->slave_addr >> 1;
175  trx_msgs[1].flags = I2C_M_RD;
176  trx_msgs[1].len = t->len_r;
177  trx_msgs[1].buf = (void *) t->buf;
178  if (ioctl(fd, I2C_RDWR, &trx_data) < 0) {
179  /* if write/read failed, increment error counter miss_start_stop_cnt */
180  pthread_mutex_lock(mutex);
182  pthread_mutex_unlock(mutex);
183  t->status = I2CTransFailed;
184  } else {
185  t->status = I2CTransSuccess;
186  }
187  break;
188  default:
189  t->status = I2CTransFailed;
190  break;
191  }
192 
193  pthread_mutex_lock(mutex);
195  pthread_mutex_unlock(mutex);
196  }
197  return NULL;
198 }
199 #pragma GCC diagnostic pop
200 
201 #if USE_I2C0
202 struct i2c_errors i2c0_errors;
203 struct i2c_thread_t i2c0_thread;
204 
205 void i2c0_hw_init(void)
206 {
207  i2c0.reg_addr = (void *)open("/dev/i2c-0", O_RDWR);
208  i2c0.errors = &i2c0_errors;
209 
210  /* zeros error counter */
211  ZEROS_ERR_COUNTER(i2c0_errors);
212 
213  pthread_mutex_init(&i2c0_thread.mutex, NULL);
214  pthread_cond_init(&i2c0_thread.condition, NULL);
215  i2c0.init_struct = (void *)(&i2c0_thread);
216 
217  i2c_arch_init(&i2c0);
218 }
219 #endif
220 
221 #if USE_I2C1
222 struct i2c_errors i2c1_errors;
223 struct i2c_thread_t i2c1_thread;
224 
225 void i2c1_hw_init(void)
226 {
227  i2c1.reg_addr = (void *)open("/dev/i2c-1", O_RDWR);
228  i2c1.errors = &i2c1_errors;
229 
230  /* zeros error counter */
231  ZEROS_ERR_COUNTER(i2c1_errors);
232 
233  pthread_mutex_init(&i2c1_thread.mutex, NULL);
234  pthread_cond_init(&i2c1_thread.condition, NULL);
235  i2c1.init_struct = (void *)(&i2c1_thread);
236 
237  i2c_arch_init(&i2c1);
238 }
239 #endif
240 
241 #if USE_I2C2
242 struct i2c_errors i2c2_errors;
243 struct i2c_thread_t i2c2_thread;
244 
245 void i2c2_hw_init(void)
246 {
247  i2c2.reg_addr = (void *)open("/dev/i2c-2", O_RDWR);
248  i2c2.errors = &i2c2_errors;
249 
250  /* zeros error counter */
251  ZEROS_ERR_COUNTER(i2c2_errors);
252 
253  pthread_mutex_init(&i2c2_thread.mutex, NULL);
254  pthread_cond_init(&i2c2_thread.condition, NULL);
255  i2c2.init_struct = (void *)(&i2c2_thread);
256 
257  i2c_arch_init(&i2c2);
258 }
259 #endif
260 
261 #if USE_I2C3
262 struct i2c_errors i2c3_errors;
263 struct i2c_thread_t i2c3_thread;
264 
265 void i2c3_hw_init(void)
266 {
267  i2c3.reg_addr = (void *)open("/dev/i2c-3", O_RDWR);
268  i2c3.errors = &i2c3_errors;
269 
270  /* zeros error counter */
271  ZEROS_ERR_COUNTER(i2c3_errors);
272 
273  pthread_mutex_init(&i2c3_thread.mutex, NULL);
274  pthread_cond_init(&i2c3_thread.condition, NULL);
275  i2c3.init_struct = (void *)(&i2c3_thread);
276 
277  i2c_arch_init(&i2c3);
278 }
279 #endif
volatile uint16_t arb_lost_cnt
Definition: i2c.h:159
pthread_cond_t condition
Definition: i2c_arch.c:50
#define I2C_TRANSACTION_QUEUE_LEN
I2C transaction queue length.
Definition: i2c.h:133
I2C errors counter.
Definition: i2c.h:154
volatile uint16_t miss_start_stop_cnt
Definition: i2c.h:158
transaction successfully finished by I2C driver
Definition: i2c.h:57
pthread_mutex_t mutex
Definition: i2c_arch.c:49
transmit and receive transaction
Definition: i2c.h:49
uint8_t last_wp UNUSED
Definition: navigation.c:92
uint8_t trans_extract_idx
Definition: i2c.h:142
__u16 addr
Definition: i2c_smbus.h:41
bool i2c_idle(struct i2c_periph *p)
i2c_idle() function
Definition: i2c_arch.c:413
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:355
struct i2c_errors * errors
Definition: i2c.h:148
#define I2C_SLAVE
Definition: i2c_smbus.h:129
#define I2C_THREAD_PRIO
Definition: i2c_arch.c:42
#define I2C_RDWR
Definition: i2c_smbus.h:138
Functions to obtain rt priority or set the nice level.
void * reg_addr
Definition: i2c.h:146
unsigned short flags
Definition: i2c_smbus.h:42
char * buf
Definition: i2c_smbus.h:50
#define I2C_M_RD
Definition: i2c_smbus.h:44
#define ZEROS_ERR_COUNTER(_i2c_err)
Definition: i2c.h:170
static void UNUSED i2c_arch_init(struct i2c_periph *p)
Definition: i2c_arch.c:53
struct i2c_transaction * trans[I2C_TRANSACTION_QUEUE_LEN]
Definition: i2c.h:140
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
short len
Definition: i2c_smbus.h:49
I2C peripheral structure.
Definition: i2c.h:138
unsigned char uint8_t
Definition: types.h:14
int fd
Definition: serial.c:26
transmit only transaction
Definition: i2c.h:47
static float p[2][2]
static void * i2c_thread(void *thread_data)
Definition: i2c_arch.c:113
void i2c_event(void)
i2c_event() function
Definition: i2c_arch.c:347
uint8_t trans_insert_idx
Definition: i2c.h:141
static int get_rt_prio(int prio)
Definition: rt_priority.h:32
receive only transaction
Definition: i2c.h:48
transaction is pending in queue
Definition: i2c.h:55
volatile uint16_t ack_fail_cnt
Definition: i2c.h:157
Architecture independent I2C (Inter-Integrated Circuit Bus) API.