Krolyxon
Commit 3120783

Branches

Tags

Refs →

orion-rf.piolibdepsesp32-s3-n16r8Adafruit BusIOAdafruit_I2CDevice.cpp

320 lines · 9.2 KB · C++

1#include "Adafruit_I2CDevice.h"
2
3// #define DEBUG_SERIAL Serial
4
5/*!
6 * @brief Create an I2C device at a given address
7 * @param addr The 7-bit I2C address for the device
8 * @param theWire The I2C bus to use, defaults to &Wire
9 */
10Adafruit_I2CDevice::Adafruit_I2CDevice(uint8_t addr, TwoWire *theWire) {
11 _addr = addr;
12 _wire = theWire;
13 _begun = false;
14#ifdef ARDUINO_ARCH_SAMD
15 _maxBufferSize = 250; // as defined in Wire.h's RingBuffer
16#elif defined(ESP32)
17 _maxBufferSize = I2C_BUFFER_LENGTH;
18#else
19 _maxBufferSize = 32;
20#endif
21}
22
23/*!
24 * @brief Initializes and does basic address detection
25 * @param addr_detect Whether we should attempt to detect the I2C address
26 * with a scan. 99% of sensors/devices don't mind, but once in a while they
27 * don't respond well to a scan!
28 * @return True if I2C initialized and a device with the addr found
29 */
30bool Adafruit_I2CDevice::begin(bool addr_detect) {
31 _wire->begin();
32 _begun = true;
33
34 if (addr_detect) {
35 return detected();
36 }
37 return true;
38}
39
40/*!
41 * @brief De-initialize device, turn off the Wire interface
42 */
43void Adafruit_I2CDevice::end(void) {
44 // Not all port implement Wire::end(), such as
45 // - ESP8266
46 // - AVR core without WIRE_HAS_END
47 // - ESP32: end() is implemented since 2.0.1 which is latest at the moment.
48 // Temporarily disable for now to give time for user to update.
49#if !(defined(ESP8266) || \
50 (defined(ARDUINO_ARCH_AVR) && !defined(WIRE_HAS_END)) || \
51 defined(ARDUINO_ARCH_ESP32))
52 _wire->end();
53 _begun = false;
54#endif
55}
56
57/*!
58 * @brief Scans I2C for the address - note will give a false-positive
59 * if there's no pullups on I2C
60 * @return True if I2C initialized and a device with the addr found
61 */
62bool Adafruit_I2CDevice::detected(void) {
63 // Init I2C if not done yet
64 if (!_begun && !begin()) {
65 return false;
66 }
67
68 // A basic scanner, see if it ACK's
69 _wire->beginTransmission(_addr);
70#ifdef DEBUG_SERIAL
71 DEBUG_SERIAL.print(F("Address 0x"));
72 DEBUG_SERIAL.print(_addr, HEX);
73#endif
74#ifdef ARDUINO_ARCH_MBED
75 _wire->write(0); // forces a write request instead of a read
76#endif
77 if (_wire->endTransmission() == 0) {
78#ifdef DEBUG_SERIAL
79 DEBUG_SERIAL.println(F(" Detected"));
80#endif
81 return true;
82 }
83#ifdef DEBUG_SERIAL
84 DEBUG_SERIAL.println(F(" Not detected"));
85#endif
86 return false;
87}
88
89/*!
90 * @brief Write a buffer or two to the I2C device. Cannot be more than
91 * maxBufferSize() bytes.
92 * @param buffer Pointer to buffer of data to write. This is const to
93 * ensure the content of this buffer doesn't change.
94 * @param len Number of bytes from buffer to write
95 * @param prefix_buffer Pointer to optional array of data to write before
96 * buffer. Cannot be more than maxBufferSize() bytes. This is const to
97 * ensure the content of this buffer doesn't change.
98 * @param prefix_len Number of bytes from prefix buffer to write
99 * @param stop Whether to send an I2C STOP signal on write
100 * @return True if write was successful, otherwise false.
101 */
102bool Adafruit_I2CDevice::write(const uint8_t *buffer, size_t len, bool stop,
103 const uint8_t *prefix_buffer,
104 size_t prefix_len) {
105 if ((len + prefix_len) > maxBufferSize()) {
106 // currently not guaranteed to work if more than 32 bytes!
107 // we will need to find out if some platforms have larger
108 // I2C buffer sizes :/
109#ifdef DEBUG_SERIAL
110 DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer"));
111#endif
112 return false;
113 }
114
115 _wire->beginTransmission(_addr);
116
117 // Write the prefix data (usually an address)
118 if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
119 if (_wire->write(prefix_buffer, prefix_len) != prefix_len) {
120#ifdef DEBUG_SERIAL
121 DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
122#endif
123 return false;
124 }
125 }
126
127 // Write the data itself
128 if (_wire->write(buffer, len) != len) {
129#ifdef DEBUG_SERIAL
130 DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
131#endif
132 return false;
133 }
134
135#ifdef DEBUG_SERIAL
136
137 DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x"));
138 DEBUG_SERIAL.print(_addr, HEX);
139 DEBUG_SERIAL.print(F(" :: "));
140 if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
141 for (uint16_t i = 0; i < prefix_len; i++) {
142 DEBUG_SERIAL.print(F("0x"));
143 DEBUG_SERIAL.print(prefix_buffer[i], HEX);
144 DEBUG_SERIAL.print(F(", "));
145 }
146 }
147 for (uint16_t i = 0; i < len; i++) {
148 DEBUG_SERIAL.print(F("0x"));
149 DEBUG_SERIAL.print(buffer[i], HEX);
150 DEBUG_SERIAL.print(F(", "));
151 if (i % 32 == 31) {
152 DEBUG_SERIAL.println();
153 }
154 }
155
156 if (stop) {
157 DEBUG_SERIAL.print("\tSTOP");
158 }
159#endif
160
161 if (_wire->endTransmission(stop) == 0) {
162#ifdef DEBUG_SERIAL
163 DEBUG_SERIAL.println();
164 // DEBUG_SERIAL.println("Sent!");
165#endif
166 return true;
167 } else {
168#ifdef DEBUG_SERIAL
169 DEBUG_SERIAL.println("\tFailed to send!");
170#endif
171 return false;
172 }
173}
174
175/*!
176 * @brief Read from I2C into a buffer from the I2C device.
177 * Cannot be more than maxBufferSize() bytes.
178 * @param buffer Pointer to buffer of data to read into
179 * @param len Number of bytes from buffer to read.
180 * @param stop Whether to send an I2C STOP signal on read
181 * @return True if read was successful, otherwise false.
182 */
183bool Adafruit_I2CDevice::read(uint8_t *buffer, size_t len, bool stop) {
184 size_t pos = 0;
185 while (pos < len) {
186 size_t read_len =
187 ((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos);
188 bool read_stop = (pos < (len - read_len)) ? false : stop;
189 if (!_read(buffer + pos, read_len, read_stop))
190 return false;
191 pos += read_len;
192 }
193 return true;
194}
195
196bool Adafruit_I2CDevice::_read(uint8_t *buffer, size_t len, bool stop) {
197#if defined(TinyWireM_h)
198 size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len);
199#elif defined(ARDUINO_ARCH_MEGAAVR)
200 size_t recv = _wire->requestFrom(_addr, len, stop);
201#else
202 size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
203#endif
204
205 if (recv != len) {
206 // Not enough data available to fulfill our obligation!
207#ifdef DEBUG_SERIAL
208 DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: "));
209 DEBUG_SERIAL.println(recv);
210#endif
211 return false;
212 }
213
214 for (uint16_t i = 0; i < len; i++) {
215 buffer[i] = _wire->read();
216 }
217
218#ifdef DEBUG_SERIAL
219 DEBUG_SERIAL.print(F("\tI2CREAD @ 0x"));
220 DEBUG_SERIAL.print(_addr, HEX);
221 DEBUG_SERIAL.print(F(" :: "));
222 for (uint16_t i = 0; i < len; i++) {
223 DEBUG_SERIAL.print(F("0x"));
224 DEBUG_SERIAL.print(buffer[i], HEX);
225 DEBUG_SERIAL.print(F(", "));
226 if (len % 32 == 31) {
227 DEBUG_SERIAL.println();
228 }
229 }
230 DEBUG_SERIAL.println();
231#endif
232
233 return true;
234}
235
236/*!
237 * @brief Write some data, then read some data from I2C into another buffer.
238 * Cannot be more than maxBufferSize() bytes. The buffers can point to
239 * same/overlapping locations.
240 * @param write_buffer Pointer to buffer of data to write from
241 * @param write_len Number of bytes from buffer to write.
242 * @param read_buffer Pointer to buffer of data to read into.
243 * @param read_len Number of bytes from buffer to read.
244 * @param stop Whether to send an I2C STOP signal between the write and read
245 * @return True if write & read was successful, otherwise false.
246 */
247bool Adafruit_I2CDevice::write_then_read(const uint8_t *write_buffer,
248 size_t write_len, uint8_t *read_buffer,
249 size_t read_len, bool stop) {
250 if (!write(write_buffer, write_len, stop)) {
251 return false;
252 }
253
254 return read(read_buffer, read_len);
255}
256
257/*!
258 * @brief Returns the 7-bit address of this device
259 * @return The 7-bit address of this device
260 */
261uint8_t Adafruit_I2CDevice::address(void) { return _addr; }
262
263/*!
264 * @brief Change the I2C clock speed to desired (relies on
265 * underlying Wire support!
266 * @param desiredclk The desired I2C SCL frequency
267 * @return True if this platform supports changing I2C speed.
268 * Not necessarily that the speed was achieved!
269 */
270bool Adafruit_I2CDevice::setSpeed(uint32_t desiredclk) {
271#if defined(__AVR_ATmega328__) || \
272 defined(__AVR_ATmega328P__) // fix arduino core set clock
273 // calculate TWBR correctly
274
275 if ((F_CPU / 18) < desiredclk) {
276#ifdef DEBUG_SERIAL
277 Serial.println(F("I2C.setSpeed too high."));
278#endif
279 return false;
280 }
281 uint32_t atwbr = ((F_CPU / desiredclk) - 16) / 2;
282 if (atwbr > 16320) {
283#ifdef DEBUG_SERIAL
284 Serial.println(F("I2C.setSpeed too low."));
285#endif
286 return false;
287 }
288
289 if (atwbr <= 255) {
290 atwbr /= 1;
291 TWSR = 0x0;
292 } else if (atwbr <= 1020) {
293 atwbr /= 4;
294 TWSR = 0x1;
295 } else if (atwbr <= 4080) {
296 atwbr /= 16;
297 TWSR = 0x2;
298 } else { // if (atwbr <= 16320)
299 atwbr /= 64;
300 TWSR = 0x3;
301 }
302 TWBR = atwbr;
303
304#ifdef DEBUG_SERIAL
305 Serial.print(F("TWSR prescaler = "));
306 Serial.println(pow(4, TWSR));
307 Serial.print(F("TWBR = "));
308 Serial.println(atwbr);
309#endif
310 return true;
311#elif (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) && \
312 !defined(TinyWireM_h)
313 _wire->setClock(desiredclk);
314 return true;
315
316#else
317 (void)desiredclk;
318 return false;
319#endif
320}