Contiki-NG
i2c.c
1 /*
2  * Copyright (c) 2006, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 /*
32  * Small and portable implementation of a bit-banging I2C bus master.
33  *
34  * The code should port really easily to platforms other than the
35  * msp430 but has some hardcoded constants in it.
36  *
37  * More info at:
38  * http://i2c-bus.org/
39  * http://www.esacademy.com/faq/i2c/
40  */
41 
42 #include <stdio.h>
43 #include <contiki.h>
44 #include "dev/spi-legacy.h"
45 #include <dev/leds.h>
46 
47 #include "dev/i2c.h"
48 
49 /*
50  * On the Tmote sky access to I2C/SPI/UART0 must always be exclusive.
51  */
52 
53 void i2c_enable(void);
54 void i2c_disable(void);
55 int i2c_start(void);
56 unsigned i2c_read(int send_ack);
57 int i2c_write(unsigned);
58 void i2c_stop(void);
59 
60 #define I2C_PxDIR P3DIR
61 #define I2C_PxIN P3IN
62 #define I2C_PxOUT P3OUT
63 #define I2C_PxSEL P3SEL
64 /*
65  * SDA == P3.1
66  * SCL == P3.3
67  */
68 #define SDA 1
69 #define SCL 3
70 
71 #define SDA_0() (I2C_PxDIR |= BV(SDA)) /* SDA Output */
72 #define SDA_1() (I2C_PxDIR &= ~BV(SDA)) /* SDA Input */
73 #define SDA_IS_1 (I2C_PxIN & BV(SDA))
74 
75 #define SCL_0() (I2C_PxDIR |= BV(SCL)) /* SCL Output */
76 #define SCL_1() (I2C_PxDIR &= ~BV(SCL)) /* SCL Input */
77 #define SCL_IS_1 (I2C_PxIN & BV(SCL))
78 
79 /*
80  * Should avoid infinite looping while waiting for SCL_IS_1. xxx/bg
81  */
82 #define SCL_WAIT_FOR_1() do{}while (!SCL_IS_1)
83 
84 #define delay_4_7us() do{ _NOP(); _NOP(); _NOP(); _NOP(); \
85  _NOP(); _NOP(); _NOP(); _NOP(); \
86  _NOP(); _NOP(); _NOP(); _NOP(); }while(0)
87 
88 #define delay_4us() do{ _NOP(); _NOP(); _NOP(); _NOP(); \
89  _NOP(); _NOP(); _NOP(); _NOP(); \
90  _NOP(); _NOP(); }while(0)
91 
92 static unsigned char old_pxsel, old_pxout, old_pxdir;
93 
94 /*
95  * Grab SDA and SCL pins for exclusive use but remember old
96  * configuration so that it may be restored when we are done.
97  */
98 void
99 i2c_enable(void)
100 {
101  unsigned char sda_scl = BV(SDA)|BV(SCL);
102 
103  old_pxsel = I2C_PxSEL & sda_scl;
104  old_pxout = I2C_PxOUT & sda_scl;
105  old_pxdir = I2C_PxDIR & sda_scl;
106 
107  spi_busy = 1;
108 
109  I2C_PxSEL &= ~sda_scl;
110 
111  I2C_PxOUT &= ~sda_scl;
112 
113  I2C_PxDIR |= BV(SCL); /* SCL Output */
114  I2C_PxDIR &= ~BV(SDA); /* SDA Input */
115 }
116 
117 /*
118  * Restore bus to what it was before i2c_enable.
119  *
120  */
121 void
122 i2c_disable(void)
123 {
124  unsigned char not_sda_scl = ~(BV(SDA)|BV(SCL));
125 
126  I2C_PxDIR = (I2C_PxDIR & not_sda_scl) | old_pxdir;
127  I2C_PxOUT = (I2C_PxOUT & not_sda_scl) | old_pxout;
128  I2C_PxSEL = (I2C_PxSEL & not_sda_scl) | old_pxsel;
129 
130  spi_busy = 0;
131 }
132 
133 int
134 i2c_start(void)
135 {
136  SDA_1();
137  SCL_1();
138 #if 1
139  SCL_WAIT_FOR_1();
140 #else
141  {
142  unsigned long n;
143  for (n = 0; n < 100000 && !SCL_IS_1; n++)
144  ;
145  if (!SCL_IS_1)
146  return -1;
147  }
148 #endif
149  delay_4_7us();
150  SDA_0();
151  delay_4us();
152  SCL_0();
153  return 0;
154 }
155 
156 void
157 i2c_stop(void)
158 {
159  SDA_0();
160  delay_4us();
161  SCL_1();
162  SCL_WAIT_FOR_1();
163  SDA_1();
164 }
165 
166 /*
167  * Return true if we received an ACK.
168  */
169 int
170 i2c_write(unsigned _c)
171 {
172  unsigned char c = _c;
173  unsigned long n;
174  int i;
175  int ret;
176 
177  for (i = 0; i < 8; i++, c <<= 1) {
178  if (c & 0x80)
179  SDA_1();
180  else
181  SDA_0();
182  SCL_1();
183  SCL_WAIT_FOR_1();
184  SCL_0();
185  }
186 
187  SDA_1();
188  SCL_1();
189  ret = 0; /* Loop waiting for an ACK to arrive. */
190  for (n = 0; n < 250000; n++) {
191  if (!SDA_IS_1) {
192  ret = 1;
193  break;
194  }
195  }
196  SCL_WAIT_FOR_1(); /* clock stretching? */
197  SCL_0();
198 
199  return ret;
200 }
201 
202 unsigned
203 i2c_read(int send_ack)
204 {
205  int i;
206  unsigned char c = 0x00;
207 
208  SDA_1();
209  for (i = 0; i < 8; i++) {
210  c <<= 1;
211  SCL_1();
212  SCL_WAIT_FOR_1();
213  if (SDA_IS_1)
214  c |= 0x1;
215  SCL_0();
216  }
217 
218  if (send_ack)
219  SDA_0();
220  SCL_1();
221  SCL_WAIT_FOR_1();
222  SCL_0();
223 
224  return c;
225 }
Basic SPI macros
Header file for the LED HAL.