Paparazzi UAS  v4.0.4_stable-3-gf39211a
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
i2c_arch.c
Go to the documentation of this file.
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2010 The Paparazzi Team
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 
25 #include "mcu_periph/i2c.h"
26 
27 #include "std.h"
28 #include "interrupt_hw.h"
29 #include BOARD_CONFIG
30 
32 // I2C Automaton //
34 
35 __attribute__ ((always_inline)) static inline void I2cSendStart(struct i2c_periph* p) {
36  p->status = I2CStartRequested;
37  ((i2cRegs_t *)(p->reg_addr))->conset = _BV(STA);
38 }
39 
40 __attribute__ ((always_inline)) static inline void I2cSendAck(void* reg) {
41  ((i2cRegs_t *)reg)->conset = _BV(AA);
42 }
43 
44 __attribute__ ((always_inline)) static inline void I2cEndOfTransaction(struct i2c_periph* p) {
45  // handle fifo here
46  p->trans_extract_idx++;
47  if (p->trans_extract_idx >= I2C_TRANSACTION_QUEUE_LEN)
48  p->trans_extract_idx = 0;
49  // if no more transaction to process, stop here, else start next transaction
50  if (p->trans_extract_idx == p->trans_insert_idx) {
51  p->status = I2CIdle;
52  }
53  else {
54  I2cSendStart(p);
55  }
56 }
57 
58 __attribute__ ((always_inline)) static inline void I2cSendStop(struct i2c_periph* p, struct i2c_transaction* t) {
59  ((i2cRegs_t *)(p->reg_addr))->conset = _BV(STO);
60  // transaction finished with success
61  t->status = I2CTransSuccess;
62  I2cEndOfTransaction(p);
63 }
64 
65 __attribute__ ((always_inline)) static inline void I2cFail(struct i2c_periph* p, struct i2c_transaction* t) {
66  ((i2cRegs_t *)(p->reg_addr))->conset = _BV(STO);
67  // transaction failed
68  t->status = I2CTransFailed;
69  // FIXME I2C should be reseted here ?
70  I2cEndOfTransaction(p);
71 }
72 
73 __attribute__ ((always_inline)) static inline void I2cSendByte(void* reg, uint8_t b) {
74  ((i2cRegs_t *)reg)->dat = b;
75 }
76 
77 __attribute__ ((always_inline)) static inline void I2cReceive(void* reg, bool_t ack) {
78  if (ack) ((i2cRegs_t *)reg)->conset = _BV(AA);
79  else ((i2cRegs_t *)reg)->conclr = _BV(AAC);
80 }
81 
82 __attribute__ ((always_inline)) static inline void I2cClearStart(void* reg) {
83  ((i2cRegs_t *)reg)->conclr = _BV(STAC);
84 }
85 
86 __attribute__ ((always_inline)) static inline void I2cClearIT(void* reg) {
87  ((i2cRegs_t *)reg)->conclr = _BV(SIC);
88 }
89 
90 __attribute__ ((always_inline)) static inline void I2cAutomaton(int32_t state, struct i2c_periph* p) {
91  struct i2c_transaction* trans = p->trans[p->trans_extract_idx];
92  switch (state) {
93  case I2C_START:
94  case I2C_RESTART:
95  // Set R/W flag
96  switch (trans->type) {
97  case I2CTransRx :
98  SetBit(trans->slave_addr,0);
99  break;
100  case I2CTransTx:
101  case I2CTransTxRx:
102  ClearBit(trans->slave_addr,0);
103  break;
104  }
105  I2cSendByte(p->reg_addr,trans->slave_addr);
106  I2cClearStart(p->reg_addr);
107  p->idx_buf = 0;
108  break;
109  case I2C_MR_DATA_ACK:
110  if (p->idx_buf < trans->len_r) {
111  trans->buf[p->idx_buf] = ((i2cRegs_t *)(p->reg_addr))->dat;
112  p->idx_buf++;
113  I2cReceive(p->reg_addr,p->idx_buf < trans->len_r - 1);
114  }
115  else {
116  /* error , we should have got NACK */
117  I2cFail(p,trans);
118  }
119  break;
120  case I2C_MR_DATA_NACK:
121  if (p->idx_buf < trans->len_r) {
122  trans->buf[p->idx_buf] = ((i2cRegs_t *)(p->reg_addr))->dat;
123  }
124  I2cSendStop(p,trans);
125  break;
126  case I2C_MR_SLA_ACK: /* At least one char */
127  /* Wait and reply with ACK or NACK */
128  I2cReceive(p->reg_addr,p->idx_buf < trans->len_r - 1);
129  break;
130  case I2C_MR_SLA_NACK:
131  case I2C_MT_SLA_NACK:
132  /* Slave is not responding, transaction is failed */
133  I2cFail(p,trans);
134  break;
135  case I2C_MT_SLA_ACK:
136  case I2C_MT_DATA_ACK:
137  if (p->idx_buf < trans->len_w) {
138  I2cSendByte(p->reg_addr,trans->buf[p->idx_buf]);
139  p->idx_buf++;
140  } else {
141  if (trans->type == I2CTransTxRx) {
142  trans->type = I2CTransRx; /* FIXME should not change type */
143  p->idx_buf = 0;
144  trans->slave_addr |= 1;
145  I2cSendStart(p);
146  } else {
147  I2cSendStop(p,trans);
148  }
149  }
150  break;
151  default:
152  I2cFail(p,trans);
153  /* FIXME log error */
154  break;
155  }
156 }
157 
158 
159 #ifdef USE_I2C0
160 
161 /* default clock speed 37.5KHz with our 15MHz PCLK
162  I2C0_CLOCK = PCLK / (I2C0_SCLL + I2C0_SCLH) */
163 #ifndef I2C0_SCLL
164 #define I2C0_SCLL 200
165 #endif
166 
167 #ifndef I2C0_SCLH
168 #define I2C0_SCLH 200
169 #endif
170 
171 /* adjust for other PCLKs */
172 
173 #if (PCLK == 15000000)
174 #define I2C0_SCLL_D I2C0_SCLL
175 #define I2C0_SCLH_D I2C0_SCLH
176 #else
177 
178 #if (PCLK == 30000000)
179 #define I2C0_SCLL_D (2*I2C0_SCLL)
180 #define I2C0_SCLH_D (2*I2C0_SCLH)
181 #else
182 
183 #if (PCLK == 60000000)
184 #define I2C0_SCLL_D (4*I2C0_SCLL)
185 #define I2C0_SCLH_D (4*I2C0_SCLH)
186 #else
187 
188 #error unknown PCLK frequency
189 #endif
190 #endif
191 #endif
192 
193 #ifndef I2C0_VIC_SLOT
194 #define I2C0_VIC_SLOT 9
195 #endif
196 
197 
198 void i2c0_ISR(void) __attribute__((naked));
199 
200 void i2c0_ISR(void) {
201  ISR_ENTRY();
202 
203  uint32_t state = I2C0STAT;
204  I2cAutomaton(state,&i2c0);
205  I2cClearIT(i2c0.reg_addr);
206 
207  VICVectAddr = 0x00000000; // clear this interrupt from the VIC
208  ISR_EXIT(); // recover registers and return
209 }
210 
211 
212 /* SDA0 on P0.3 */
213 /* SCL0 on P0.2 */
214 void i2c0_hw_init ( void ) {
215 
216  i2c0.reg_addr = I2C0;
217 
218  /* set P0.2 and P0.3 to I2C0 */
219  PINSEL0 |= 1 << 4 | 1 << 6;
220  /* clear all flags */
221  I2C0CONCLR = _BV(AAC) | _BV(SIC) | _BV(STAC) | _BV(I2ENC);
222  /* enable I2C */
223  I2C0CONSET = _BV(I2EN);
224  /* set bitrate */
225  I2C0SCLL = I2C0_SCLL_D;
226  I2C0SCLH = I2C0_SCLH_D;
227 
228  // initialize the interrupt vector
229  VICIntSelect &= ~VIC_BIT(VIC_I2C0); // I2C0 selected as IRQ
230  VICIntEnable = VIC_BIT(VIC_I2C0); // I2C0 interrupt enabled
231  _VIC_CNTL(I2C0_VIC_SLOT) = VIC_ENABLE | VIC_I2C0;
232  _VIC_ADDR(I2C0_VIC_SLOT) = (uint32_t)i2c0_ISR; // address of the ISR
233 }
234 
235 #endif /* USE_I2C0 */
236 
237 
238 
239 #ifdef USE_I2C1
240 
241 /* default clock speed 37.5KHz with our 15MHz PCLK
242  I2C1_CLOCK = PCLK / (I2C1_SCLL + I2C1_SCLH) */
243 #ifndef I2C1_SCLL
244 #define I2C1_SCLL 200
245 #endif
246 
247 #ifndef I2C1_SCLH
248 #define I2C1_SCLH 200
249 #endif
250 
251 /* adjust for other PCLKs */
252 
253 #if (PCLK == 15000000)
254 #define I2C1_SCLL_D I2C1_SCLL
255 #define I2C1_SCLH_D I2C1_SCLH
256 #else
257 
258 #if (PCLK == 30000000)
259 #define I2C1_SCLL_D (2*I2C1_SCLL)
260 #define I2C1_SCLH_D (2*I2C1_SCLH)
261 #else
262 
263 #if (PCLK == 60000000)
264 #define I2C1_SCLL_D (4*I2C1_SCLL)
265 #define I2C1_SCLH_D (4*I2C1_SCLH)
266 #else
267 
268 #error unknown PCLK frequency
269 #endif
270 #endif
271 #endif
272 
273 #ifndef I2C1_VIC_SLOT
274 #define I2C1_VIC_SLOT 11
275 #endif
276 
277 
278 void i2c1_ISR(void) __attribute__((naked));
279 
280 void i2c1_ISR(void) {
281  ISR_ENTRY();
282 
283  uint32_t state = I2C1STAT;
284  I2cAutomaton(state,&i2c1);
285  I2cClearIT(i2c1.reg_addr);
286 
287  VICVectAddr = 0x00000000; // clear this interrupt from the VIC
288  ISR_EXIT(); // recover registers and return
289 }
290 
291 /* SDA1 on P0.14 */
292 /* SCL1 on P0.11 */
293 void i2c1_hw_init ( void ) {
294 
295  i2c1.reg_addr = I2C1;
296 
297  /* set P0.11 and P0.14 to I2C1 */
298  PINSEL0 |= 3 << 22 | 3 << 28;
299  /* clear all flags */
300  I2C1CONCLR = _BV(AAC) | _BV(SIC) | _BV(STAC) | _BV(I2ENC);
301  /* enable I2C */
302  I2C1CONSET = _BV(I2EN);
303  /* set bitrate */
304  I2C1SCLL = I2C1_SCLL_D;
305  I2C1SCLH = I2C1_SCLH_D;
306 
307  // initialize the interrupt vector
308  VICIntSelect &= ~VIC_BIT(VIC_I2C1); // I2C1 selected as IRQ
309  VICIntEnable = VIC_BIT(VIC_I2C1); // I2C1 interrupt enabled
310  _VIC_CNTL(I2C1_VIC_SLOT) = VIC_ENABLE | VIC_I2C1;
311  _VIC_ADDR(I2C1_VIC_SLOT) = (uint32_t)i2c1_ISR; // address of the ISR
312 }
313 
314 #endif /* USE_I2C1 */
315 
316 
317 bool_t i2c_idle(struct i2c_periph* p) {
318  return p->status == I2CIdle;
319 }
320 
321 bool_t i2c_submit(struct i2c_periph* p, struct i2c_transaction* t) {
322 
323  uint8_t idx;
324  idx = p->trans_insert_idx + 1;
325  if (idx >= I2C_TRANSACTION_QUEUE_LEN) idx = 0;
326  if (idx == p->trans_extract_idx) {
327  t->status = I2CTransFailed;
328  return FALSE; /* queue full */
329  }
330  t->status = I2CTransPending;
331  int_disable();
332  p->trans[p->trans_insert_idx] = t;
333  p->trans_insert_idx = idx;
334  /* if peripheral is idle, start the transaction */
335  if (p->status == I2CIdle)
336  I2cSendStart(p);
337  /* else it will be started by the interrupt handler */
338  /* when the previous transactions completes */
339  int_enable();
340 
341  return TRUE;
342 }
343 
344 void i2c_event(void) { }
345 
346 void i2c_setbitrate(struct i2c_periph* p, int bitrate)
347 {
348  int period = 15000000 / 2 / bitrate;
349  // Max 400kpbs
350  if (period < 19)
351  period = 19;
352  // Min 5kbps
353  if (period > 1500)
354  period = 1500;
355 
356 #if (PCLK == 30000000)
357  period *= 2;
358 #endif
359 
360 #if (PCLK == 60000000)
361  period *= 4;
362 #endif
363 
364  /* default clock speed 37.5KHz with our 15MHz PCLK
365  * I2C_CLOCK = PCLK / (I2C_SCLL + I2C_SCLH)
366  */
367 
368  /* set bitrate */
369  ((i2cRegs_t *)(p->reg_addr))->scll = period;
370  ((i2cRegs_t *)(p->reg_addr))->sclh = period;
371 }
372 
373 
#define VICIntSelect
Definition: LPC21xx.h:398
#define STAC
Definition: LPC21xx.h:189
#define int_disable()
Definition: interrupt_hw.h:32
#define I2C1
Definition: LPC21xx.h:166
void i2c_event(void)
Definition: i2c_arch.c:344
void * reg_addr
Definition: i2c.h:62
uint8_t trans_extract_idx
Definition: i2c.h:58
#define I2C_MT_SLA_ACK
Definition: i2c_arch.h:10
#define _VIC_CNTL(idx)
Definition: armVIC.h:19
#define I2C_MR_DATA_NACK
Definition: i2c_arch.h:16
bool_t i2c_idle(struct i2c_periph *p)
Definition: i2c_arch.c:317
#define I2C0SCLH
Definition: LPC21xx.h:161
#define I2C0SCLL
Definition: LPC21xx.h:162
enum I2CStatus status
Definition: i2c.h:60
#define _VIC_ADDR(idx)
Definition: armVIC.h:20
uint8_t slave_addr
Definition: i2c.h:43
#define I2C1STAT
Definition: LPC21xx.h:169
#define I2C_MR_DATA_ACK
Definition: i2c_arch.h:15
#define FALSE
Definition: imu_chimu.h:141
#define I2C_MR_SLA_ACK
Definition: i2c_arch.h:13
#define I2ENC
Definition: LPC21xx.h:190
#define I2C0CONSET
Definition: LPC21xx.h:157
#define AAC
Definition: LPC21xx.h:187
#define I2C1CONCLR
Definition: LPC21xx.h:174
#define I2EN
Definition: LPC21xx.h:183
Definition: i2c.h:23
bool_t i2c_submit(struct i2c_periph *p, struct i2c_transaction *t)
Definition: i2c_arch.c:321
#define int_enable()
Definition: interrupt_hw.h:31
#define I2C0CONCLR
Definition: LPC21xx.h:163
#define VICVectAddr
Definition: LPC21xx.h:404
unsigned long uint32_t
Definition: types.h:18
#define I2C1SCLH
Definition: LPC21xx.h:172
#define STA
Definition: LPC21xx.h:182
enum I2CTransactionStatus status
Definition: i2c.h:47
#define I2C_MR_SLA_NACK
Definition: i2c_arch.h:14
#define AA
Definition: LPC21xx.h:179
signed long int32_t
Definition: types.h:19
#define VIC_BIT(chan)
Definition: lpcVIC.h:105
#define TRUE
Definition: imu_chimu.h:144
#define PINSEL0
Definition: LPC21xx.h:315
volatile uint8_t buf[I2C_BUF_LEN]
Definition: i2c.h:46
#define VIC_I2C0
Definition: lpcVIC.h:78
#define I2cSendStart()
Definition: i2c_arch.h:6
uint8_t len_w
Definition: i2c.h:45
#define I2C_RESTART
Definition: i2c_arch.h:9
uint16_t len_r
Definition: i2c.h:44
#define I2C_START
Definition: i2c_arch.h:8
unsigned char uint8_t
Definition: types.h:14
#define ISR_EXIT()
Definition: armVIC.h:61
#define I2C1SCLL
Definition: LPC21xx.h:173
uint8_t trans_insert_idx
Definition: i2c.h:57
#define VICIntEnable
Definition: LPC21xx.h:399
Definition: i2c.h:54
enum I2CTransactionType type
Definition: i2c.h:42
Definition: i2c.h:10
#define I2C0STAT
Definition: LPC21xx.h:158
#define STO
Definition: LPC21xx.h:181
#define I2C_TRANSACTION_QUEUE_LEN
Definition: i2c.h:51
#define I2C_MT_SLA_NACK
Definition: i2c_arch.h:11
#define SIC
Definition: LPC21xx.h:188
Definition: i2c.h:9
__attribute__((always_inline))
Definition: i2c_arch.c:35
#define I2C1CONSET
Definition: LPC21xx.h:168
#define ISR_ENTRY()
Definition: armVIC.h:40
#define I2C0
Definition: LPC21xx.h:154
#define VIC_ENABLE
Definition: lpcVIC.h:102
void i2c_setbitrate(struct i2c_periph *p, int bitrate)
Definition: i2c_arch.c:346
#define VIC_I2C1
Definition: lpcVIC.h:89
struct i2c_transaction * trans[I2C_TRANSACTION_QUEUE_LEN]
Definition: i2c.h:56
#define I2C_MT_DATA_ACK
Definition: i2c_arch.h:12