typo
[protos/imu.git] / i2cm_sw.c
1 /*
2  *  Copyright Droids Corporation, Microb Technology, Eirbot (2005)
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  *  Revision : $Id$
19  *
20  */
21
22
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <stdint.h>
27 #include <aversive.h>
28
29 #include <aversive/wait.h>
30
31
32 #include <util/delay.h>
33
34
35 #include "i2cm_sw.h"
36
37
38
39
40 volatile i2cm_state g_i2cm_state = NOT_INIT;
41 volatile uint8_t g_i2cm_byte;
42
43 void (*g_i2cm_event)(i2cm_state state);
44
45 /*
46   Mini Arduino
47   I2C:
48   A4 = PC4/SDA
49   A5 = PC5/SCL
50 */
51
52 #define I2CM_SCL_PORT  PORTD
53 #define I2CM_SCL_BIT   6
54
55 #define  I2CM_SDA_PORT PORTD
56 #define  I2CM_SDA_BIT  5
57
58 #define I2CM_SCL   I2CM_SCL_PORT, I2CM_SCL_BIT
59 #define I2CM_SDA   I2CM_SDA_PORT, I2CM_SDA_BIT
60
61
62
63
64 void i2cm_init(void)
65 {
66         /*
67           - port SCL/SDA is set to 0
68           - i2c is then driven using DDR 0 (Hi-Z) or 1 (For Low)
69          */
70
71         // SCL high
72         cbi(DDR(I2CM_SCL_PORT),I2CM_SCL_BIT);
73         I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
74
75         // SDA high
76         cbi(DDR(I2CM_SDA_PORT),I2CM_SDA_BIT);
77         I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
78         I2CM_DELAY();
79
80         g_i2cm_state = I2CM_READY;
81 }
82
83
84 void i2cm_manage(void)
85 {
86         if ( (g_i2cm_event  != NULL) && (g_i2cm_state  != I2CM_READY) ) {
87                 g_i2cm_event( g_i2cm_state );
88                 // reset notification
89                 if (g_i2cm_state != I2CM_BUSY)
90                         g_i2cm_state = I2CM_READY;
91         }
92 }
93
94 uint8_t i2cm_get_state(void)
95 {
96         return g_i2cm_state;
97 }
98
99
100 uint8_t i2cm_get_received_byte(void)
101 {
102         g_i2cm_state = I2CM_READY;
103         return g_i2cm_byte;
104 }
105
106 void i2cm_register_event(void (*func)(i2cm_state state))
107 {
108         uint8_t flags;
109         IRQ_LOCK(flags);
110         g_i2cm_event = func;
111         IRQ_UNLOCK(flags);
112 }
113
114
115 static uint8_t i2cm_send_byte(uint8_t byte)
116 {
117         uint8_t mask;
118         uint8_t err = 0;
119
120
121         g_i2cm_state = I2CM_BUSY;
122
123         // SCL should already be low
124         //  I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
125         //  I2CM_DELAY();
126
127         mask = 0x80;
128         while (mask) {
129
130
131                 // data out
132                 if (mask & byte)
133                         I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
134                 else
135                         I2C_LOW(I2CM_SDA_PORT, I2CM_SDA_BIT);
136                 I2CM_DELAY();
137                 mask >>=1;
138
139                 // clock High
140                 I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
141                 I2CM_DELAY();
142                 while ( bit_is_clear(PIN(I2CM_SCL_PORT), I2CM_SCL_BIT) );// slave handshake
143
144                 // clock low
145                 I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
146
147         }
148
149         /* receive ack */
150
151         // release SDA
152         I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
153         I2CM_BIT_DELAY();
154
155         // clock HIGH
156         I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
157         I2CM_DELAY();
158         while ( bit_is_clear(PIN(I2CM_SCL_PORT), I2CM_SCL_BIT) );// slave handshake
159
160         // we should receive ACK
161         if (bit_is_set(PIN(I2CM_SDA_PORT), I2CM_SDA_BIT))
162                 err = I2CM_SENT_NO_ACK;
163
164         // clock low
165         I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
166         I2CM_DELAY();
167
168         return err;
169 }
170
171
172 uint8_t i2cm_send_start(uint8_t sla_w)
173 {
174         uint8_t err;
175         uint16_t i;
176         g_i2cm_state = I2CM_BUSY;
177
178         I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
179         I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
180
181         I2CM_DELAY();
182
183         /* wait for bus realese */
184         for (i=0;i<0x8000; i++){
185                 if( bit_is_set(PIN(I2CM_SCL_PORT), I2CM_SCL_BIT) && \
186                     bit_is_set(PIN(I2CM_SDA_PORT), I2CM_SDA_BIT) )
187                         break;
188         }
189
190         //      while ( bit_is_clear(PIN(I2CM_SCL_PORT), I2CM_SCL_BIT) );// slave handshake
191
192         // start condition
193         I2C_LOW(I2CM_SDA_PORT, I2CM_SDA_BIT);
194         I2CM_DELAY();
195         I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
196         I2CM_DELAY();
197
198         err = i2cm_send_byte(sla_w);
199         return err;
200 }
201
202
203
204 uint8_t i2cm_send_stop(void)
205 {
206         g_i2cm_state = I2CM_BUSY;
207
208         // data down
209         I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
210         I2C_LOW(I2CM_SDA_PORT, I2CM_SDA_BIT);
211         I2CM_DELAY();
212
213         // stop condition
214         I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
215         I2CM_DELAY();
216         I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
217         I2CM_DELAY();
218
219         g_i2cm_state = I2CM_SENT_STOP;
220         return 0;
221 }
222
223
224 uint8_t i2cm_receive_byte(uint8_t last)
225 {
226         uint8_t mask,data;
227
228         g_i2cm_state = I2CM_BUSY;
229
230         I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
231
232
233         data = 0;
234         mask = 0x80;
235         while (mask) {
236
237                 // clock High
238                 I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
239                 I2CM_DELAY();
240                 while ( bit_is_clear(PIN(I2CM_SCL_PORT), I2CM_SCL_BIT) );// slave handshake
241
242                 if (bit_is_set(PIN(I2CM_SDA_PORT),I2CM_SDA_BIT))
243                         data |= mask;
244
245                 // clock low
246                 I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
247                 I2CM_DELAY();
248
249                 mask >>=1;
250         }
251
252         if (!last){
253                 /* send ack */
254                 I2C_LOW(I2CM_SDA_PORT, I2CM_SDA_BIT);
255                 I2CM_BIT_DELAY();
256         }
257
258         // clock HIGH
259         I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
260         I2CM_DELAY();
261         while ( bit_is_clear(PIN(I2CM_SCL_PORT), I2CM_SCL_BIT) );// slave handshake
262
263         // clock low
264         I2C_LOW(I2CM_SCL_PORT, I2CM_SCL_BIT);
265         I2CM_DELAY();
266
267         if (!last) {
268                 // release DATA
269                 I2C_HIGH(I2CM_SDA_PORT, I2CM_SDA_BIT);
270                 I2CM_BIT_DELAY();
271         }
272
273         g_i2cm_byte  = data;
274         g_i2cm_state = I2CM_RECEIVED_BYTE;
275
276         I2C_HIGH(I2CM_SCL_PORT, I2CM_SCL_BIT);
277
278         return 0;
279 }
280
281
282 uint8_t i2cm_send(uint8_t addr, uint8_t* data, uint8_t len)
283 {
284         uint8_t i;
285         uint8_t err = 0;
286
287         err = i2cm_send_start((addr<<1) | 0);
288         if (err)
289                 return err;
290
291         for (i=0; i<len; i++) {
292                 err = i2cm_send_byte(data[i]);
293                 if (err)
294                         break;
295         }
296
297         i2cm_send_stop();
298         return err;
299 }
300
301
302 uint8_t i2c_buf[0x20]; /* XXX */
303
304 uint8_t i2cm_recv(uint8_t addr, uint8_t len)
305 {
306         uint8_t i;
307         uint8_t err = 0;
308
309         err = i2cm_send_start((addr<<1) | 1);
310         if (err)
311                 return err;
312
313         I2CM_DELAY();
314
315         for (i=0; i<len; i++){
316                 err =i2cm_receive_byte(i == len-1);
317                 i2c_buf[i] = g_i2cm_byte;
318                 if (err)
319                         break;
320         }
321         i2cm_send_stop();
322         return err;
323 }
324
325
326 uint8_t i2cm_get_recv_buffer(uint8_t* buf, uint8_t len)
327 {
328         uint8_t i;
329         for (i=0; i<len; i++)
330                 buf[i] = i2c_buf[i];
331         return len;
332 }