i2c.c


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
}