rusEFI
The most advanced open source ECU
Loading...
Searching...
No Matches
hw_layer
drivers
i2c
i2c_bb.cpp
Go to the documentation of this file.
1
/**
2
* @file i2c_bb.cpp
3
* @brief Bit-banged I2C driver
4
*
5
* @date February 6, 2020
6
* @author Matthew Kennedy, (c) 2020
7
*/
8
9
#include "
pch.h
"
10
11
#include "
i2c_bb.h
"
12
13
void
BitbangI2c::sda_high
() {
14
#if EFI_PROD_CODE
15
palSetPad(
m_sdaPort
,
m_sdaPin
);
16
#endif
17
}
18
19
void
BitbangI2c::sda_low
() {
20
#if EFI_PROD_CODE
21
palClearPad(
m_sdaPort
,
m_sdaPin
);
22
#endif
23
}
24
25
void
BitbangI2c::scl_high
() {
26
#if EFI_PROD_CODE
27
palSetPad(
m_sclPort
,
m_sclPin
);
28
#endif
29
}
30
31
void
BitbangI2c::scl_low
() {
32
#if EFI_PROD_CODE
33
palClearPad(
m_sclPort
,
m_sclPin
);
34
#endif
35
}
36
37
bool
BitbangI2c::init
(
brain_pin_e
scl,
brain_pin_e
sda) {
38
#if EFI_PROD_CODE
39
if
(
m_sdaPort
) {
40
return
false
;
41
}
42
43
if
(!
isBrainPinValid
(scl) || !
isBrainPinValid
(sda)) {
44
return
false
;
45
}
46
47
efiSetPadMode
(
"i2c"
, scl, PAL_MODE_OUTPUT_OPENDRAIN);
//PAL_STM32_OTYPE_OPENDRAIN
48
efiSetPadMode
(
"i2c"
, sda, PAL_MODE_OUTPUT_OPENDRAIN);
49
50
m_sclPort
=
getHwPort
(
"i2c"
, scl);
51
m_sclPin
=
getHwPin
(
"i2c"
, scl);
52
53
m_sdaPort
=
getHwPort
(
"i2c"
, sda);
54
m_sdaPin
=
getHwPin
(
"i2c"
, sda);
55
#endif
56
57
// Both lines idle high
58
scl_high
();
59
sda_high
();
60
61
return
true
;
62
}
63
64
void
BitbangI2c::deinit
() {
65
#if EFI_PROD_CODE
66
if
(
m_sclPort
) {
67
gpio_pin_markUnused
(
m_sclPort
,
m_sclPin
);
68
m_sclPort
= NULL;
69
}
70
if
(
m_sdaPort
) {
71
gpio_pin_markUnused
(
m_sdaPort
,
m_sdaPin
);
72
m_sdaPort
= NULL;
73
}
74
#endif
75
}
76
77
void
BitbangI2c::start
() {
78
// Start with both lines high (bus idle)
79
sda_high
();
80
waitQuarterBit
();
81
scl_high
();
82
waitQuarterBit
();
83
84
// SDA goes low while SCL is high
85
sda_low
();
86
waitQuarterBit
();
87
scl_low
();
88
waitQuarterBit
();
89
}
90
91
void
BitbangI2c::stop
() {
92
scl_low
();
93
waitQuarterBit
();
94
sda_low
();
95
waitQuarterBit
();
96
scl_high
();
97
waitQuarterBit
();
98
// SDA goes high while SCL is high
99
sda_high
();
100
}
101
102
void
BitbangI2c::sendBit
(
bool
val) {
103
waitQuarterBit
();
104
105
// Write the bit (write while SCL is low)
106
if
(val) {
107
sda_high
();
108
}
else
{
109
sda_low
();
110
}
111
112
// Data setup time (~100ns min)
113
waitQuarterBit
();
114
115
// Strobe the clock
116
scl_high
();
117
waitQuarterBit
();
118
scl_low
();
119
waitQuarterBit
();
120
}
121
122
bool
BitbangI2c::readBit
() {
123
waitQuarterBit
();
124
125
scl_high
();
126
127
waitQuarterBit
();
128
waitQuarterBit
();
129
130
#if EFI_PROD_CODE
131
// Read just before we set the clock low (ie, as late as possible)
132
bool
val = palReadPad(
m_sdaPort
,
m_sdaPin
);
133
#else
134
bool
val =
false
;
135
#endif
136
137
scl_low
();
138
waitQuarterBit
();
139
140
return
val;
141
}
142
143
bool
BitbangI2c::writeByte
(uint8_t data) {
144
// write out 8 data bits
145
for
(
size_t
i = 0; i < 8; i++) {
146
// Send the MSB
147
sendBit
((data & 0x80) != 0);
148
149
data = data << 1;
150
}
151
152
// Force a release of the data line so the slave can ACK
153
sda_high
();
154
155
// Read the ack bit
156
bool
ackBit =
readBit
();
157
158
// 0 -> ack
159
// 1 -> nack
160
return
!ackBit;
161
}
162
163
uint8_t
BitbangI2c::readByte
(
bool
ack) {
164
uint8_t result = 0;
165
166
// Read in 8 data bits
167
for
(
size_t
i = 0; i < 8; i++) {
168
result = result << 1;
169
170
result |=
readBit
() ? 1 : 0;
171
}
172
173
// 0 -> ack
174
// 1 -> nack
175
sendBit
(!ack);
176
177
// release SDA
178
sda_high
();
179
180
return
result;
181
}
182
183
void
BitbangI2c::waitQuarterBit
() {
184
// This yields a bitrate of about 320khz on a 168MHz F4
185
for
(
size_t
i = 0; i < 30; i++) {
186
__asm__
volatile
(
"nop"
);
187
}
188
}
189
190
void
BitbangI2c::write
(uint8_t
addr
,
const
uint8_t* writeData,
size_t
writeSize) {
191
start
();
192
193
// Address + write
194
writeByte
(
addr
<< 1 | 0);
195
196
// Write outbound bytes
197
for
(
size_t
i = 0; i < writeSize; i++) {
198
writeByte
(writeData[i]);
199
}
200
201
stop
();
202
}
203
204
void
BitbangI2c::writeRead
(uint8_t
addr
,
const
uint8_t* writeData,
size_t
writeSize, uint8_t* readData,
size_t
readSize) {
205
write
(
addr
, writeData, writeSize);
206
207
read
(
addr
, readData, readSize);
208
}
209
210
void
BitbangI2c::read
(uint8_t
addr
, uint8_t* readData,
size_t
readSize) {
211
start
();
212
213
// Address + read
214
writeByte
(
addr
<< 1 | 1);
215
216
for
(
size_t
i = 0; i < readSize - 1; i++) {
217
// All but the last byte send ACK to indicate we're still reading
218
readData[i] =
readByte
(
true
);
219
}
220
221
// last byte sends NAK to indicate we're done reading
222
readData[readSize - 1] =
readByte
(
false
);
223
224
stop
();
225
}
226
227
uint8_t
BitbangI2c::readRegister
(uint8_t
addr
, uint8_t reg) {
228
uint8_t retval;
229
230
writeRead
(
addr
, ®, 1, &retval, 1);
231
232
return
retval;
233
}
234
235
void
BitbangI2c::writeRegister
(uint8_t
addr
, uint8_t reg, uint8_t val) {
236
uint8_t buf[2];
237
buf[0] = reg;
238
buf[1] = val;
239
240
write
(
addr
, buf, 2);
241
}
addr
constexpr uint8_t addr
Definition
ads1015.cpp:14
efiSetPadMode
void efiSetPadMode(const char *msg, brain_pin_e brainPin, iomode_t mode)
Definition
bootloader_main.cpp:207
BitbangI2c::read
void read(uint8_t addr, uint8_t *data, size_t size)
Definition
i2c_bb.cpp:210
BitbangI2c::waitQuarterBit
void waitQuarterBit()
Definition
i2c_bb.cpp:183
BitbangI2c::m_sclPort
ioportid_t m_sclPort
Definition
i2c_bb.h:54
BitbangI2c::m_sdaPin
ioportmask_t m_sdaPin
Definition
i2c_bb.h:57
BitbangI2c::write
void write(uint8_t addr, const uint8_t *data, size_t size)
Definition
i2c_bb.cpp:190
BitbangI2c::m_sdaPort
ioportid_t m_sdaPort
Definition
i2c_bb.h:56
BitbangI2c::writeByte
bool writeByte(uint8_t data)
Definition
i2c_bb.cpp:143
BitbangI2c::writeRegister
void writeRegister(uint8_t addr, uint8_t reg, uint8_t val)
Definition
i2c_bb.cpp:235
BitbangI2c::start
void start()
Definition
i2c_bb.cpp:77
BitbangI2c::readBit
bool readBit()
Definition
i2c_bb.cpp:122
BitbangI2c::init
bool init(brain_pin_e scl, brain_pin_e sda)
Definition
i2c_bb.cpp:37
BitbangI2c::scl_low
void scl_low()
Definition
i2c_bb.cpp:31
BitbangI2c::sda_low
void sda_low()
Definition
i2c_bb.cpp:19
BitbangI2c::sda_high
void sda_high()
Definition
i2c_bb.cpp:13
BitbangI2c::stop
void stop()
Definition
i2c_bb.cpp:91
BitbangI2c::readByte
uint8_t readByte(bool ack)
Definition
i2c_bb.cpp:163
BitbangI2c::readRegister
uint8_t readRegister(uint8_t addr, uint8_t reg)
Definition
i2c_bb.cpp:227
BitbangI2c::scl_high
void scl_high()
Definition
i2c_bb.cpp:25
BitbangI2c::writeRead
void writeRead(uint8_t addr, const uint8_t *writeData, size_t writeSize, uint8_t *readData, size_t readSize)
Definition
i2c_bb.cpp:204
BitbangI2c::m_sclPin
ioportmask_t m_sclPin
Definition
i2c_bb.h:55
BitbangI2c::sendBit
void sendBit(bool val)
Definition
i2c_bb.cpp:102
BitbangI2c::deinit
void deinit()
Definition
i2c_bb.cpp:64
Gpio
Gpio
Definition
rusefi_hw_enums.h:14
getHwPort
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
Definition
cypress_pins.cpp:137
getHwPin
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
Definition
cypress_pins.cpp:153
i2c_bb.h
Bit-banged I2C driver.
pch.h
gpio_pin_markUnused
void gpio_pin_markUnused(ioportid_t port, ioportmask_t pin)
Definition
pin_repository.cpp:307
isBrainPinValid
bool isBrainPinValid(brain_pin_e brainPin)
Definition
pin_repository.cpp:25
Generated on Sat Sep 27 2025 00:10:06 for rusEFI by
1.9.8