-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathI2C_BitBang.h
137 lines (117 loc) · 3.03 KB
/
I2C_BitBang.h
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
/*
* I2C_BitBang.h
*
* Created: 1/4/2023 10:13:05 AM
* Author: aparady
*/
#ifndef I2C_BITBANG_H_
#define I2C_BITBANG_H_
#define I2C_delay asm("nop") // Adjust this based on clock speed to change SCL frequency
// Define what pin is SDA and what pin is SCL
#define SDA_HIGH (PORTE |= (1<<PORTE0))
#define SCL_HIGH (PORTE |= (1<<PORTE1))
#define SDA_LOW (PORTE &= ~(1<<PORTE0))
#define SCL_LOW (PORTE &= ~(1<<PORTE1))
#define SDA_READ_ON (DDRE &= ~(1<<DDE0))
#define SDA_READ_OFF (DDRE |= (1<<DDE0))
#define SCL_READ_ON (DDRE &= ~(1<<DDE1))
#define SCL_READ_OFF (DDRE |= (1<<DDE1))
uint8_t read_data = 0; // Returned data from slave device
uint8_t bit_convert[8] = {1, 2, 4, 8, 16, 32, 64, 128}; // Conversion factors for binary value without shifting to allow for a constant conversion speed
void I2C_start(){
// Start from known state
SDA_HIGH;
I2C_delay;
SCL_HIGH;
I2C_delay;
// Follow standard I2C start condition
SDA_LOW;
I2C_delay;
SCL_LOW;
I2C_delay;
}
void I2C_stop(){
// Follow standard I2C stop condition
SDA_LOW;
I2C_delay;
SCL_HIGH;
I2C_delay;
SDA_HIGH;
I2C_delay;
}
void I2C_sendACK(){
// Send ACK to tell slave to keep transmitting
SDA_READ_OFF;
I2C_delay;
SDA_LOW;
I2C_delay;
SCL_HIGH;
I2C_delay;
SCL_LOW;
I2C_delay;
SDA_LOW;
I2C_delay;
}
void I2C_sendNACK(){
// Send ACK to tell slave to stop transmitting
SDA_READ_OFF;
I2C_delay;
SDA_HIGH;
I2C_delay;
SCL_HIGH;
I2C_delay;
SCL_LOW;
I2C_delay;
SDA_LOW;
I2C_delay;
}
uint8_t I2C_write(uint8_t Data){
// Go through all eight bits and force SDA to be high or low depending on if bit is set
for(int bits = 7; bits >= 0; bits--){
(Data & 0x80) ? SDA_HIGH : SDA_LOW; // If data in last bit is set/1, then force SDA high. Otherwise leave SDA low and clock it out.
Data <<= 1; // Shift data left by one bit
I2C_delay;
// Clock data out
SCL_HIGH;
I2C_delay;
SCL_LOW;
I2C_delay;
}
// Check for ACK or NACK
SDA_LOW;
I2C_delay;
SDA_READ_ON;
I2C_delay;
SCL_HIGH;
I2C_delay;
uint8_t ACK = ((PINE & (1 << PORTE0)) >> PORTE0); // Check if ACK was received by converting pin read to binary, 0 = ACK, 1 = NACK
SDA_READ_OFF;
I2C_delay;
SCL_LOW;
I2C_delay;
return ACK;
}
uint8_t I2C_read(uint8_t ack){
// Prepare transmission lines for slave data
read_data = 0;
//SDA_HIGH;
//I2C_delay;
SDA_READ_ON;
I2C_delay;
for(int bits = 7; bits >= 0; bits--){
// Clock bits from slave device
SCL_HIGH;
I2C_delay;
read_data = read_data + ((((PINE & (1 << PORTE0)) >> PORTE0)) * bit_convert[bits]); // Convert pin read to binary and multiply it by number of bits to create a full hex byte
SCL_LOW;
I2C_delay;
}
if (ack == 1){
I2C_sendACK(); // Send ACK if more data needs to be transferred. Otherwise send NACK to end transmission
}else{
I2C_sendNACK();
}
read_data = (((read_data / 16) * 10) + (read_data % 16)); // Convert received data from hex to decimal
return read_data;
}
#endif /* I2C_BITBANG_H_ */