Paparazzi UAS v7.0_unstable
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// Default stack size
45#ifndef I2C_THREAD_STACK_SIZE
46#define I2C_THREAD_STACK_SIZE 512
47#endif
48
49
50static bool i2c_chibios_idle(struct i2c_periph *p) __attribute__((unused));
51static bool i2c_chibios_submit(struct i2c_periph *p, struct i2c_transaction *t) __attribute__((unused));
52static 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
58struct 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;
68};
69
70
71static void handle_i2c_thd(struct i2c_periph *p);
72
73// Timeout for I2C transaction
74static const systime_t tmo = TIME_US2I(10000000 / PERIODIC_FREQUENCY);
75
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 */
94static void i2c_clear_bus(struct i2c_init *i)
95{
96 const iomode_t mode_saved = palReadLineMode(i->line_scl);
98 for(uint8_t j = 0; j < 20; j++) {
99 palToggleLine(i->line_scl);
101 }
102 palSetLineMode(i->line_scl, mode_saved);
103}
104
105static 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
119static 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
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);
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
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
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
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
245static 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;
250
251 while (TRUE) {
253 }
254}
255#endif /* USE_I2C1 || USE_I2C2 || USE_I2C3 || USE_I2C4 */
256
257#if USE_I2C1
259// Local variables (in DMA safe memory)
260static 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};
268
269/*
270 * I2C1 init
271 */
272void 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
284 NORMALPRIO + 1, thd_i2c, (void *)&i2c1);
285}
286#endif /* USE_I2C1 */
287
288#if USE_I2C2
290// Local variables (in DMA safe memory)
291static 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};
299
300/*
301 * I2C2 init
302 */
303void 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
315 NORMALPRIO + 1, thd_i2c, (void *)&i2c2);
316}
317#endif /* USE_I2C2 */
318
319#if USE_I2C3
321// Local variables (in DMA safe memory)
322static 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};
330
331/*
332 * I2C3 init
333 */
334void 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
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)
355static IN_BDMA_SECTION(struct i2c_init i2c4_init_s) = {
356#else
357// Local variables (in DMA safe memory)
358static 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};
367
368/*
369 * I2C4 init
370 */
371void 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
383 NORMALPRIO + 1, thd_i2c, (void *)&i2c4);
384}
385#endif /* USE_I2C4 */
386
387
393void i2c_event(void) {}
394
401static void i2c_chibios_setbitrate(struct i2c_periph *p __attribute__((unused)), int bitrate __attribute__((unused))) {}
402
420static 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
459static 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 I2C1_CFG_DEF
Definition board.h:447
#define LINE_I2C1_SCL
Definition board.h:774
#define I2C2_CFG_DEF
Definition board.h:463
static uint8_t status
#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
static THD_WORKING_AREA(wa_thd_spi1, SPI_THREAD_STACK_SIZE)
#define I2C1_CLOCK_SPEED
#define I2C3_CLOCK_SPEED
#define I2C2_CLOCK_SPEED
#define I2C4_CLOCK_SPEED
#define LINE_I2C3_SCL
Definition board.h:254
#define LINE_I2C3_SDA
Definition board.h:279
#define I2C3_CFG_DEF
Definition crazyflie.h:214
void * init_struct
Definition i2c.h:158
enum I2CTransactionStatus status
Transaction status.
Definition i2c.h:126
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:188
@ 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]
uint16_t foo
Definition main_demo5.c:58
#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.