-
Notifications
You must be signed in to change notification settings - Fork 1
/
i2csw.c
176 lines (140 loc) · 4.17 KB
/
i2csw.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*! \file i2csw.c \brief Software I2C interface using port pins. */
//*****************************************************************************
//
// File Name : 'i2csw.c'
// Title : Software I2C interface using port pins
// Author : Pascal Stang
// Created : 11/22/2000
// Revised : 5/2/2002
// Version : 1.1
// Target MCU : Atmel AVR series
// Editor Tabs : 4
//
// This code is distributed under the GNU Public License
// which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************
#include <avr/io.h>
#include "i2csw.h"
// Standard I2C bit rates are:
// 100KHz for slow speed
// 400KHz for high speed
//#define QDEL delay(5) // i2c quarter-bit delay
//#define HDEL delay(10) // i2c half-bit delay
// i2c quarter-bit delay
#define QDEL asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop");
// i2c half-bit delay
#define HDEL asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop"); asm volatile("nop");
#define I2C_SDL_LO cbi( SDAPORT, SDA)
#define I2C_SDL_HI sbi( SDAPORT, SDA)
#define I2C_SCL_LO cbi( SCLPORT, SCL);
#define I2C_SCL_HI sbi( SCLPORT, SCL);
#define I2C_SCL_TOGGLE HDEL; I2C_SCL_HI; HDEL; I2C_SCL_LO;
#define I2C_START I2C_SDL_LO; QDEL; I2C_SCL_LO;
#define I2C_STOP HDEL; I2C_SCL_HI; QDEL; I2C_SDL_HI; HDEL;
/*
void i2ct(void)
{
HDEL; I2C_SCL_HI; HDEL; I2C_SCL_LO;
}
void i2cstart(void)
{
I2C_SDL_LO; QDEL; I2C_SCL_LO;
}
void i2cstop(void)
{
HDEL; I2C_SCL_HI; QDEL; I2C_SDL_HI; HDEL;
}
#define I2C_SCL_TOGGLE i2ct();
#define I2C_START i2cstart();
#define I2C_STOP i2cstop();
*/
UINT i2cPutbyte(u08 b)
{
int i;
for (i=7;i>=0;i--)
{
if ( b & (1<<i) )
I2C_SDL_HI;
else
I2C_SDL_LO; // address bit
I2C_SCL_TOGGLE; // clock HI, delay, then LO
}
I2C_SDL_HI; // leave SDL HI
// added
cbi(SDADDR, SDA); // change direction to input on SDA line (may not be needed)
HDEL;
I2C_SCL_HI; // clock back up
b = inb(SDAPIN) & (1<<SDA); // get the ACK bit
HDEL;
I2C_SCL_LO; // not really ??
sbi(SDADDR, SDA); // change direction back to output
HDEL;
return (b == 0); // return ACK value
}
u08 i2cGetbyte(UINT last)
{
int i;
u08 c,b = 0;
I2C_SDL_HI; // make sure pullups are ativated
cbi(SDADDR, SDA); // change direction to input on SDA line (may not be needed)
for(i=7;i>=0;i--)
{
HDEL;
I2C_SCL_HI; // clock HI
c = inb(SDAPIN) & (1<<SDA);
b <<= 1;
if(c) b |= 1;
HDEL;
I2C_SCL_LO; // clock LO
}
sbi(SDADDR, SDA); // change direction to output on SDA line
if (last)
I2C_SDL_HI; // set NAK
else
I2C_SDL_LO; // set ACK
I2C_SCL_TOGGLE; // clock pulse
I2C_SDL_HI; // leave with SDL HI
return b; // return received byte
}
//************************
//* I2C public functions *
//************************
//! Initialize I2C communication
void i2cInit(void)
{
sbi( SDADDR, SDA); // set SDA as output
sbi( SCLDDR, SCL); // set SCL as output
I2C_SDL_HI; // set I/O state and pull-ups
I2C_SCL_HI; // set I/O state and pull-ups
}
//! Send a byte sequence on the I2C bus
void i2cSend(u08 device, u08 subAddr, u08 length, u08 *data)
{
I2C_START; // do start transition
i2cPutbyte(device); // send DEVICE address
i2cPutbyte(subAddr); // and the subaddress
// send the data
while (length--)
i2cPutbyte(*data++);
I2C_SDL_LO; // clear data line and
I2C_STOP; // send STOP transition
}
//! Retrieve a byte sequence on the I2C bus
void i2cReceive(u08 device, u08 subAddr, u08 length, u08 *data)
{
int j = length;
u08 *p = data;
I2C_START; // do start transition
i2cPutbyte(device); // send DEVICE address
i2cPutbyte(subAddr); // and the subaddress
HDEL;
I2C_SCL_HI; // do a repeated START
I2C_START; // transition
i2cPutbyte(device | READ); // resend DEVICE, with READ bit set
// receive data bytes
while (j--)
*p++ = i2cGetbyte(j == 0);
I2C_SDL_LO; // clear data line and
I2C_STOP; // send STOP transition
}