MatrixMiniR4 1.1.4
Matrix Mini R4 Arduino Library API Documentation
Loading...
Searching...
No Matches
MiniR4I2CDevice.cpp
Go to the documentation of this file.
1
6#include "MiniR4I2CDevice.h"
7
8// #define DEBUG_SERIAL Serial
9
15MiniR4_I2CDevice::MiniR4_I2CDevice(uint8_t addr, TwoWire* theWire, uint8_t mux_ch)
16{
17 _addr = addr;
18 _wire = theWire;
19 _ch = mux_ch;
20 _begun = false;
21#ifdef ARDUINO_ARCH_SAMD
22 _maxBufferSize = 250; // as defined in Wire.h's RingBuffer
23#elif defined(ESP32)
24 _maxBufferSize = I2C_BUFFER_LENGTH;
25#else
26 _maxBufferSize = 32;
27#endif
28}
29
37bool MiniR4_I2CDevice::begin(bool addr_detect)
38{
39 _wire->begin();
40 _begun = true;
41
42 if (addr_detect) {
43 return detected();
44 }
45 return true;
46}
47
52{
53 // Not all port implement Wire::end(), such as
54 // - ESP8266
55 // - AVR core without WIRE_HAS_END
56 // - ESP32: end() is implemented since 2.0.1 which is latest at the moment.
57 // Temporarily disable for now to give time for user to update.
58#if !( \
59 defined(ESP8266) || (defined(ARDUINO_ARCH_AVR) && !defined(WIRE_HAS_END)) || \
60 defined(ARDUINO_ARCH_ESP32))
61 _wire->end();
62 _begun = false;
63#endif
64}
65
72{
73 // Init I2C if not done yet
74 if (!_begun && !begin()) {
75 return false;
76 }
77 i2cMUXSelect();
78 // A basic scanner, see if it ACK's
79 _wire->beginTransmission(_addr);
80 if (_wire->endTransmission() == 0) {
81#ifdef DEBUG_SERIAL
82 DEBUG_SERIAL.println(F("Detected"));
83#endif
84 return true;
85 }
86#ifdef DEBUG_SERIAL
87 DEBUG_SERIAL.println(F("Not detected"));
88#endif
89 return false;
90}
91
106 const uint8_t* buffer, size_t len, bool stop, const uint8_t* prefix_buffer, size_t prefix_len)
107{
108 if ((len + prefix_len) > maxBufferSize()) {
109 // currently not guaranteed to work if more than 32 bytes!
110 // we will need to find out if some platforms have larger
111 // I2C buffer sizes :/
112#ifdef DEBUG_SERIAL
113 DEBUG_SERIAL.println(F("\tI2CDevice could not write such a large buffer"));
114#endif
115 return false;
116 }
117 i2cMUXSelect();
118 _wire->beginTransmission(_addr);
119
120 // Write the prefix data (usually an address)
121 if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
122 if (_wire->write(prefix_buffer, prefix_len) != prefix_len) {
123#ifdef DEBUG_SERIAL
124 DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
125#endif
126 return false;
127 }
128 }
129
130 // Write the data itself
131 if (_wire->write(buffer, len) != len) {
132#ifdef DEBUG_SERIAL
133 DEBUG_SERIAL.println(F("\tI2CDevice failed to write"));
134#endif
135 return false;
136 }
137
138#ifdef DEBUG_SERIAL
139
140 DEBUG_SERIAL.print(F("\tI2CWRITE @ 0x"));
141 DEBUG_SERIAL.print(_addr, HEX);
142 DEBUG_SERIAL.print(F(" :: "));
143 if ((prefix_len != 0) && (prefix_buffer != nullptr)) {
144 for (uint16_t i = 0; i < prefix_len; i++) {
145 DEBUG_SERIAL.print(F("0x"));
146 DEBUG_SERIAL.print(prefix_buffer[i], HEX);
147 DEBUG_SERIAL.print(F(", "));
148 }
149 }
150 for (uint16_t i = 0; i < len; i++) {
151 DEBUG_SERIAL.print(F("0x"));
152 DEBUG_SERIAL.print(buffer[i], HEX);
153 DEBUG_SERIAL.print(F(", "));
154 if (i % 32 == 31) {
155 DEBUG_SERIAL.println();
156 }
157 }
158
159 if (stop) {
160 DEBUG_SERIAL.print("\tSTOP");
161 }
162#endif
163
164 if (_wire->endTransmission(stop) == 0) {
165#ifdef DEBUG_SERIAL
166 DEBUG_SERIAL.println();
167 // DEBUG_SERIAL.println("Sent!");
168#endif
169 return true;
170 } else {
171#ifdef DEBUG_SERIAL
172 DEBUG_SERIAL.println("\tFailed to send!");
173#endif
174 return false;
175 }
176}
177
186bool MiniR4_I2CDevice::read(uint8_t* buffer, size_t len, bool stop)
187{
188 size_t pos = 0;
189 while (pos < len) {
190 size_t read_len = ((len - pos) > maxBufferSize()) ? maxBufferSize() : (len - pos);
191 bool read_stop = (pos < (len - read_len)) ? false : stop;
192 if (!_read(buffer + pos, read_len, read_stop)) return false;
193 pos += read_len;
194 }
195 return true;
196}
197
198bool MiniR4_I2CDevice::_read(uint8_t* buffer, size_t len, bool stop)
199{
200 i2cMUXSelect();
201#if defined(TinyWireM_h)
202 size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len);
203#elif defined(ARDUINO_ARCH_MEGAAVR)
204 size_t recv = _wire->requestFrom(_addr, len, stop);
205#else
206 size_t recv = _wire->requestFrom((uint8_t)_addr, (uint8_t)len, (uint8_t)stop);
207#endif
208
209 if (recv != len) {
210 // Not enough data available to fulfill our obligation!
211#ifdef DEBUG_SERIAL
212 DEBUG_SERIAL.print(F("\tI2CDevice did not receive enough data: "));
213 DEBUG_SERIAL.println(recv);
214#endif
215 return false;
216 }
217
218 for (uint16_t i = 0; i < len; i++) {
219 buffer[i] = _wire->read();
220 }
221
222#ifdef DEBUG_SERIAL
223 DEBUG_SERIAL.print(F("\tI2CREAD @ 0x"));
224 DEBUG_SERIAL.print(_addr, HEX);
225 DEBUG_SERIAL.print(F(" :: "));
226 for (uint16_t i = 0; i < len; i++) {
227 DEBUG_SERIAL.print(F("0x"));
228 DEBUG_SERIAL.print(buffer[i], HEX);
229 DEBUG_SERIAL.print(F(", "));
230 if (len % 32 == 31) {
231 DEBUG_SERIAL.println();
232 }
233 }
234 DEBUG_SERIAL.println();
235#endif
236
237 return true;
238}
239
252 const uint8_t* write_buffer, size_t write_len, uint8_t* read_buffer, size_t read_len, bool stop)
253{
254 if (!write(write_buffer, write_len, stop)) {
255 return false;
256 }
257
258 return read(read_buffer, read_len);
259}
260
266{
267 return _addr;
268}
269
277bool MiniR4_I2CDevice::setSpeed(uint32_t desiredclk)
278{
279#if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) // fix arduino core set clock
280 // calculate TWBR correctly
281
282 if ((F_CPU / 18) < desiredclk) {
283# ifdef DEBUG_SERIAL
284 Serial.println(F("I2C.setSpeed too high."));
285# endif
286 return false;
287 }
288 uint32_t atwbr = ((F_CPU / desiredclk) - 16) / 2;
289 if (atwbr > 16320) {
290# ifdef DEBUG_SERIAL
291 Serial.println(F("I2C.setSpeed too low."));
292# endif
293 return false;
294 }
295
296 if (atwbr <= 255) {
297 atwbr /= 1;
298 TWSR = 0x0;
299 } else if (atwbr <= 1020) {
300 atwbr /= 4;
301 TWSR = 0x1;
302 } else if (atwbr <= 4080) {
303 atwbr /= 16;
304 TWSR = 0x2;
305 } else { // if (atwbr <= 16320)
306 atwbr /= 64;
307 TWSR = 0x3;
308 }
309 TWBR = atwbr;
310
311# ifdef DEBUG_SERIAL
312 Serial.print(F("TWSR prescaler = "));
313 Serial.println(pow(4, TWSR));
314 Serial.print(F("TWBR = "));
315 Serial.println(atwbr);
316# endif
317 return true;
318#elif (ARDUINO >= 157) && !defined(ARDUINO_STM32_FEATHER) && !defined(TinyWireM_h)
319 _wire->setClock(desiredclk);
320 return true;
321
322#else
323 (void)desiredclk;
324 return false;
325#endif
326}
327
328void MiniR4_I2CDevice::i2cMUXSelect()
329{
330 if (_ch < 0) return; // no MUX
331 _wire->beginTransmission(ADDR_PCA954X);
332 _wire->write((1 << _ch));
333 _wire->endTransmission(1);
334 delayMicroseconds(300);
335}
MiniR4 I2C low level functions.
#define ADDR_PCA954X
MiniR4_I2CDevice(uint8_t addr, TwoWire *theWire=&Wire, uint8_t mux_ch=-1)
Create an I2C device at a given address.
bool write(const uint8_t *buffer, size_t len, bool stop=true, const uint8_t *prefix_buffer=nullptr, size_t prefix_len=0)
Write a buffer or two to the I2C device. Cannot be more than maxBufferSize() bytes.
uint8_t address(void)
Returns the 7-bit address of this device.
bool setSpeed(uint32_t desiredclk)
Change the I2C clock speed to desired (relies on underlying Wire support!
void end(void)
De-initialize device, turn off the Wire interface.
bool write_then_read(const uint8_t *write_buffer, size_t write_len, uint8_t *read_buffer, size_t read_len, bool stop=false)
Write some data, then read some data from I2C into another buffer. Cannot be more than maxBufferSize(...
size_t maxBufferSize()
How many bytes we can read in a transaction.
bool detected(void)
Scans I2C for the address - note will give a false-positive if there's no pullups on I2C.
bool read(uint8_t *buffer, size_t len, bool stop=true)
Read from I2C into a buffer from the I2C device. Cannot be more than maxBufferSize() bytes.
bool begin(bool addr_detect=true)
Initializes and does basic address detection.