1 | /*
|
2 | Copyright (C) 2000 Jesper Hansen <jesperh@telia.com>.
|
3 |
|
4 | This file is part of the yampp system.
|
5 |
|
6 | This program is free software; you can redistribute it and/or
|
7 | modify it under the terms of the GNU General Public License
|
8 | as published by the Free Software Foundation; either version 2
|
9 | of the License, or (at your option) any later version.
|
10 |
|
11 | This program is distributed in the hope that it will be useful,
|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14 | GNU General Public License for more details.
|
15 |
|
16 | You should have received a copy of the GNU General Public License
|
17 | along with this program; if not, write to the Free Software Foundation,
|
18 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19 | */
|
20 |
|
21 | #include <io.h>
|
22 | #include <signal.h>
|
23 |
|
24 |
|
25 | #include <progmem.h>
|
26 |
|
27 |
|
28 | #define READ 0x01 // I2C READ bit
|
29 |
|
30 | #define SCLPORT PORTD
|
31 | #define SDAPORT PORTD
|
32 |
|
33 | #define SCL PB7
|
34 | #define SDA PB5
|
35 |
|
36 | #define QDEL delay(5)
|
37 | #define HDEL delay(10)
|
38 |
|
39 | #define I2C_SDL_LO cbi( SDAPORT, SDA)
|
40 | #define I2C_SDL_HI sbi( SDAPORT, SDA)
|
41 |
|
42 | #define I2C_SCL_LO cbi( SCLPORT, SCL);
|
43 | #define I2C_SCL_HI sbi( SCLPORT, SCL);
|
44 |
|
45 |
|
46 | //#define I2C_SCL_TOGGLE HDEL; I2C_SCL_HI; HDEL; I2C_SCL_LO;
|
47 | //#define I2C_START I2C_SDL_LO; QDEL; I2C_SCL_LO;
|
48 | //#define I2C_STOP HDEL; I2C_SCL_HI; QDEL; I2C_SDL_HI; HDEL;
|
49 |
|
50 |
|
51 | //#define DEBUG_I2C 1
|
52 |
|
53 |
|
54 | #define I2CTRACE(x) PRINT(x) \
|
55 |
|
56 | #define I2CTRACE2(a,b,c) PRINT(a); UART_Printfu08(b); PRINT(c); \
|
57 |
|
58 | void delay(unsigned short us)
|
59 | {
|
60 | unsigned short delay_loops;
|
61 | register unsigned short i;
|
62 |
|
63 | delay_loops = (us+3)/5*CYCLES_PER_US; // +3 for rounding up (dirty)
|
64 |
|
65 | // one loop takes 5 cpu cycles
|
66 | for (i=0; i < delay_loops; i++) {};
|
67 | }
|
68 |
|
69 | void i2ct(void)
|
70 | {
|
71 | HDEL; I2C_SCL_HI; HDEL; I2C_SCL_LO;
|
72 | }
|
73 |
|
74 | void i2cstart(void)
|
75 | {
|
76 | I2C_SDL_LO; QDEL; I2C_SCL_LO;
|
77 | }
|
78 |
|
79 | void i2cstop(void)
|
80 | {
|
81 | HDEL; I2C_SCL_HI; QDEL; I2C_SDL_HI; HDEL;
|
82 | }
|
83 |
|
84 |
|
85 | #define I2C_SCL_TOGGLE i2ct();
|
86 | #define I2C_START i2cstart();
|
87 | #define I2C_STOP i2cstop();
|
88 |
|
89 |
|
90 |
|
91 | //int q; // for debug
|
92 |
|
93 | unsigned int i2c_putbyte(unsigned char b)
|
94 | {
|
95 | int i;
|
96 |
|
97 | #ifdef DEBUG_I2C
|
98 | I2CTRACE2("<",b,">");
|
99 | #endif
|
100 |
|
101 | for (i=7;i>=0;i--)
|
102 | {
|
103 | if ( b & (1<<i) )
|
104 | I2C_SDL_HI;
|
105 | else
|
106 | I2C_SDL_LO; // address bit
|
107 | I2C_SCL_TOGGLE; // clock HI, delay, then LO
|
108 | }
|
109 |
|
110 | I2C_SDL_HI; // leave SDL HI
|
111 |
|
112 | // added
|
113 | cbi(SDAPORT-1, SDA); // change direction to input on SDA line (may not be needed)
|
114 |
|
115 | HDEL;
|
116 | I2C_SCL_HI; // clock back up
|
117 |
|
118 | b = inp(SDAPORT-2) & (1<<SDA); // get the ACK bit
|
119 |
|
120 | HDEL;
|
121 | I2C_SCL_LO; // not really ??
|
122 |
|
123 | sbi(SDAPORT-1, SDA); // change direction back to output
|
124 |
|
125 | HDEL;
|
126 |
|
127 | return (b == 0); // return ACK value
|
128 | }
|
129 |
|
130 |
|
131 | unsigned char i2c_getbyte(unsigned int last)
|
132 | {
|
133 | int i;
|
134 | unsigned char c,b = 0;
|
135 |
|
136 |
|
137 | I2C_SDL_HI; // make sure pullups are ativated
|
138 |
|
139 | cbi(SDAPORT-1, SDA); // change direction to input on SDA line (may not be needed)
|
140 |
|
141 | for (i=7;i>=0;i--)
|
142 | {
|
143 | HDEL;
|
144 | I2C_SCL_HI; // clock HI
|
145 |
|
146 | c = inp(SDAPORT-2) & (1<<SDA);
|
147 |
|
148 | b <<= 1;
|
149 | if (c)
|
150 | b |= 1;
|
151 |
|
152 | HDEL;
|
153 | I2C_SCL_LO; // clock LO
|
154 | }
|
155 |
|
156 | sbi(SDAPORT-1, SDA); // change direction to output on SDA line
|
157 |
|
158 | if (last)
|
159 | I2C_SDL_HI; // set NAK
|
160 | else
|
161 | I2C_SDL_LO; // set ACK
|
162 |
|
163 | I2C_SCL_TOGGLE; // clock pulse
|
164 |
|
165 | I2C_SDL_HI; // leave with SDL HI
|
166 |
|
167 | #ifdef DEBUG_I2C
|
168 | I2CTRACE2("<",b,">");
|
169 | #endif
|
170 |
|
171 | return b; // return received byte
|
172 | }
|
173 |
|
174 |
|
175 |
|
176 |
|
177 |
|
178 | /**************************************************************************/
|
179 | /* I2C public functions */
|
180 | /**************************************************************************/
|
181 |
|
182 | /*
|
183 | Initialize I2C communication
|
184 | */
|
185 | void i2c_init(void)
|
186 | {
|
187 |
|
188 | sbi( SDAPORT-1, SDA); // set SDA as output
|
189 | sbi( SCLPORT-1, SCL); // set SCL as output
|
190 |
|
191 | I2C_SDL_HI;
|
192 | I2C_SCL_HI;
|
193 | }
|
194 |
|
195 |
|
196 | /*
|
197 | Send a byte sequence on the I2C line
|
198 | */
|
199 | void i2c_send(unsigned char dev, unsigned char sub, unsigned char length, unsigned char *data)
|
200 | {
|
201 | #ifdef DEBUG_I2C
|
202 | I2CTRACE("i2c_send ");
|
203 | #endif
|
204 |
|
205 | I2C_START; // do start transition
|
206 | i2c_putbyte(dev); // send DEVICE address
|
207 | i2c_putbyte(sub); // and the subaddress
|
208 |
|
209 | // send the data
|
210 | while (length--)
|
211 | i2c_putbyte(*data++);
|
212 |
|
213 | I2C_SDL_LO; // clear data line and
|
214 | I2C_STOP; // send STOP transition
|
215 |
|
216 | #ifdef DEBUG_I2C
|
217 | I2CTRACE("\n");
|
218 | #endif
|
219 |
|
220 | }
|
221 |
|
222 |
|
223 | /*
|
224 | Retrieve a byte sequence on the I2C line
|
225 | */
|
226 | void i2c_receive(unsigned char dev, unsigned char sub, unsigned char length, unsigned char *data)
|
227 | {
|
228 | int j = length;
|
229 | unsigned char *p = data;
|
230 |
|
231 | #ifdef DEBUG_I2C
|
232 | I2CTRACE("i2c_receive ");
|
233 | #endif
|
234 |
|
235 | I2C_START; // do start transition
|
236 | i2c_putbyte(dev); // send DEVICE address
|
237 | i2c_putbyte(sub /*| READ*/); // and the subaddress
|
238 |
|
239 | HDEL;
|
240 | I2C_SCL_HI; // do a repeated START
|
241 | I2C_START; // transition
|
242 |
|
243 | i2c_putbyte(dev | READ);// resend DEVICE, with READ bit set
|
244 |
|
245 | // receive data bytes
|
246 | while (j--)
|
247 | *p++ = i2c_getbyte(j == 0);
|
248 |
|
249 | I2C_SDL_LO; // clear data line and
|
250 | I2C_STOP; // send STOP transition
|
251 |
|
252 | #ifdef DEBUG_I2C
|
253 | I2CTRACE("\n");
|
254 | #endif
|
255 | }
|