-
Notifications
You must be signed in to change notification settings - Fork 0
/
I2C.c
executable file
·204 lines (167 loc) · 5.11 KB
/
I2C.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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include <xc.h> /* XC8 General Include File */
#include "I2C.h"
/* Software I2C implementation for use with microcomputers without any
I2C hardware. */
#define SCL PORTAbits.RA4 /* Clock */
#define SCLDIR TRISAbits.TRISA4
#define SCLIN SCLDIR = 1; __delay_us(3)
#define SCLOUT SCLDIR = 0; Nop(); Nop()
#define SDA PORTAbits.RA5 /* Data */
#define SDADIR TRISAbits.TRISA5
#define SDAIN SDADIR = 1
#define SDAOUT SDADIR = 0
TCHAR I2C_device;
static BOOLEAN Ack(void)
{
BOOLEAN ack;
SCLIN; /* set SCL as an input so SCL goes high */
ack = (BOOLEAN)(SDA == 0); /* sample SDA acknowledge */
SCLOUT; /* set SCL to an output so SCL goes low */
return ack;
} /* end Ack() */
static void SendByte(TCHAR b)
{
TCHAR cnt = 8;
while (cnt--) {
if (b&0x80) { SDAIN; /* set SDA as input -> goes high */
} else { SDAOUT; } /* set SDA as output -> goes low */
SCLIN; /* set SCL as input -> goes high */
b <<= 1; /* shift left 1 bit (part of delay) */
SCLOUT; /* set SCL as output -> goes low */
} /* end while */
Nop(); /* delay for data hold */
SDAIN; /* leave SDA high for acknowledge */
} /* end SendByte() */
static BOOLEAN SendByteAck(TCHAR b)
{
SendByte(b);
return Ack();
} /* end SendByteAck() */
static TCHAR ReceiveByte(void) {
TCHAR cnt = 8;
TCHAR lb = 0;
while (cnt--) {
lb <<= 1; /* shift left 1 bit position */
SCLIN; /* set SCL as input -> goes high */
if (SDA) lb |= 1; /* set LSB of byte */
SCLOUT; /* set SCL as output -> goes low */
} /* end while */
return lb;
} /* end ReceiveByte() */
static TCHAR ReceiveByteAck(void) {
TCHAR lb = ReceiveByte();
SDAOUT; /* leave SDA low for acknowledge */
Ack();
SDAIN; /* set SDA high again */
return lb;
} /* end ReceiveByteAck() */
static void DoStart(void) {
// Verify the SDA/SCL bits are still 0
LATAbits.LATA4 = 0; /* set SDA/SCL low */
LATAbits.LATA5 = 0;
/* do start bit */
SDAIN;
SCLIN; /* set SCL, SDA as inputs -> go high */
SDAOUT; /* set SDA as output -> goes low */
__delay_us(3);
SCLOUT; /* set SCL as output -> goes low */
} /* end DoStart() */
void I2C_Power(BOOLEAN TurnOn, BOOLEAN Count)
{
/* turn on/off memory power switch */
// if (TurnOn) {
// sbit(MPOWER, P6OUT); /* Power on */
// Timers_Delay(1); /* Stabilize power */
// } else {
// cbit(MPOWER, P6OUT); /* Power off */
// }
}
static void Start(TCHAR b, TCHAR adr) {
DoStart();
/* start sending the data */
SendByteAck(b);
SendByteAck((TCHAR) (adr));
} /* end Start() */
static void Stop(void) {
/* do stop bit */
SDAOUT; /* set SDA as output -> goes low */
SCLIN; /* set SCL as input -> goes high */
__delay_us(3);
SDAIN; /* set SDA as input -> goes high */
// ei(); /* Enable interrupts */
} /* end Stop() */
void I2C_Init(void)
{
/* set up registers for I2C communication */
SDAIN; SCLIN; /* set SDA and SCL as inputs */
LATAbits.LATA4 = 0; /* set SDA/SCL low, Power off */
LATAbits.LATA5 = 0;
I2C_Power(FALSE, FALSE); /* initially turn off I2C power */
I2C_device = 0xDEu; /* default is the RTC chip */
}
void I2C_GetBuf(TCHAR adr, TCHAR buf[], CARDINAL size)
{
CARDINAL ind;
Start(I2C_device, adr); /* output start bit and device address */
/* do start bit again */
DoStart();
SendByteAck(I2C_device+1u);
for (ind=0; ind<size-1; ind++) {
buf[ind] = ReceiveByteAck(); /* receive data buffer */
} /* end for */
buf[size-1] = ReceiveByte();
Stop();
} /* end GetBuf() */
//TCHAR I2C_Get(TCHAR adr)
//{
// TCHAR ch;
//
// Start(I2C_device, adr); /* output start bit and device address */
//
// /* do start bit */
// DoStart();
// SendByteAck(I2C_device+1u); /* send device address -- read mode */
// ch = ReceiveByte(); /* receive byte */
// Stop(); /* output stop bit */
// return ch;
//} /* end Get() */
//
//
//BOOLEAN I2C_GetAck(void)
//{
// TCHAR ch;
// BOOLEAN ack;
//
// /* do start bit */
// DoStart();
// ack = SendByteAck(I2C_device+1u); /* send device address -- read mode */
// ch = ReceiveByte(); /* receive current address */
// Stop(); /* output stop bit */
// return ack;
//} /* end GetAck() */
void I2C_SendBuf(TCHAR adr, TCHAR buf[], CARDINAL size)
{
CARDINAL ind;
Start(I2C_device, adr); /* output start bit and device address */
for (ind=0; ind<size-1; ind++) {
SendByteAck(buf[ind]); /* output data buffer */
} /* end for */
SendByteAck(buf[size-1]);
Stop();
} /* end SendBuf() */
//BOOLEAN I2C_Device_Present(void)
//{
// // Check for device twice before giving up
// if (I2C_GetAck()) return TRUE;
// return (I2C_GetAck());
//}
void I2C_Send(TCHAR adr, TCHAR byte)
{
Start(I2C_device, adr); /* output start bit and device address */
SendByteAck(byte); /* output data */
Stop(); /* output stop bit */
} /* end Send() */
void I2C_BEGIN(void)
{
I2C_Init();
}