diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino index 4124d7d6..214ffe99 100644 --- a/libraries/Wire/examples/master_reader/master_reader.ino +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -12,21 +12,19 @@ #include -void setup() -{ - Wire.begin(); // join i2c bus (address optional for master) +void setup() { + Wire.begin(); // join I2C bus (address optional for master) Serial.begin(9600); // start serial for output } -void loop() -{ - Wire.requestFrom(2, 6); // request 6 bytes from slave device #2 +void loop() { + Wire.requestFrom(8, 6); // request 6 bytes from slave device #8 - while(Wire.available()) // slave may send less than requested - { + while (Wire.available()) { // slave may send less than requested char c = Wire.read(); // receive a byte as character Serial.print(c); // print the character } + Serial.println(); delay(500); } diff --git a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino new file mode 100644 index 00000000..57bd82b5 --- /dev/null +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -0,0 +1,100 @@ +// Wire Master Reader Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Reads data from an I2C/TWI slave device +// Refer to the "Wire Slave Sender Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +// request 6 bytes from slave device #8 +constexpr size_t REQUESTED_BYTE_COUNT = 6; + +constexpr size_t RECEIVE_BUFFER_SIZE = REQUESTED_BYTE_COUNT; +constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire.begin(); // join I2C bus (address optional for master) + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWireBuffersCapacity(Serial); +} + +void loop() { + Wire.requestFrom(8, REQUESTED_BYTE_COUNT); + + while (Wire.available()) { // slave may send less than requested + const char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + Serial.println(); + + delay(500); +} + +void printWireBuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire_BUFFERS(); + + stream.print("Wire transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire1.begin(); // join I2C bus (address optional for master) + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWire1BuffersCapacity(Serial); +} + +void loop() { + Wire1.requestFrom(8, REQUESTED_BYTE_COUNT); + + while (Wire1.available()) { // slave may send less than requested + const char c = Wire1.read(); // receive a byte as character + Serial.print(c); // print the character + } + Serial.println(); + + delay(500); +} + +void printWire1BuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire1_BUFFERS(); + + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire1 service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +#endif diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino index ccaa0361..4028a5af 100644 --- a/libraries/Wire/examples/master_writer/master_writer.ino +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -17,7 +17,7 @@ void setup() Wire.begin(); // join i2c bus (address optional for master) } -byte x = 0; +static byte x = 0; void loop() { diff --git a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino new file mode 100644 index 00000000..0b5d97fd --- /dev/null +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -0,0 +1,100 @@ +// Wire Master Writer Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Writes data to an I2C/TWI slave device +// Refer to the "Wire Slave Receiver Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +// The following text will not fit into the default buffer of 32 bytes. +static const char text[] = "You really won't believe it, but x is "; + +constexpr size_t RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire.begin(); // join I2C bus (address optional for master) + + // This is just for curiosity and could be removed + Serial.begin(9600); // start serial for output + printWireBuffersCapacity(Serial); +} + +static byte x = 0; + +void loop() { + Wire.beginTransmission(8); // transmit to device #8 + Wire.write(text); // sends multiple bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +void printWireBuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire_BUFFERS(); + + stream.print("Wire transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +void setup() { + Wire1.begin(); // join I2C bus (address optional for master) + + // This is just for curiosity and could be removed + Serial.begin(9600); // start serial for output + printWire1BuffersCapacity(Serial); +} + +static byte x = 0; + +void loop() { + Wire1.beginTransmission(8); // transmit to device #8 + Wire1.write(text); // sends multiple bytes + Wire1.write(x); // sends one byte + Wire1.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +void printWire1BuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire1_BUFFERS(); + + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire1 service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +#endif diff --git a/libraries/Wire/examples/slave_receiver/slave_receiver.ino b/libraries/Wire/examples/slave_receiver/slave_receiver.ino index 60dd4bdd..1fb2037f 100644 --- a/libraries/Wire/examples/slave_receiver/slave_receiver.ino +++ b/libraries/Wire/examples/slave_receiver/slave_receiver.ino @@ -26,6 +26,11 @@ void loop() // function that executes whenever data is received from master // this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. void receiveEvent(int howMany) { while(1 < Wire.available()) // loop through all but the last diff --git a/libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino b/libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino new file mode 100644 index 00000000..8bdbcb7d --- /dev/null +++ b/libraries/Wire/examples/slave_receiver_Wire1Wire_connected/slave_receiver_Wire1Wire_connected.ino @@ -0,0 +1,100 @@ +// Wire1 connnected to Wire. (scl <-> scl1, sda <-> sda1) + +// Demonstrates use of the Wire library on a single Arduino board +// with 2 Wire interfaces (like Arduino Due). +// Uses the option of customizing the buffers. +// +// Wire data to an I2C/TWI slave device +// Wire1 receives data as an I2C/TWI slave device + +// Created 02 Jan 2025 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +static_assert(WIRE_INTERFACES_COUNT > 1, "You need two I2C interfaces on the Arduino board to run this sketch"); + +static const char text[] = "You really won't believe it, but x is "; + +// Wire is the master writer +constexpr size_t M_RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t M_TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. +SET_Wire_BUFFERS(M_RECEIVE_BUFFER_SIZE, M_TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +// Wire1 is the slave receiver +constexpr size_t S_RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. +constexpr size_t S_TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. +SET_Wire1_BUFFERS(S_RECEIVE_BUFFER_SIZE, S_TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Serial.begin(9600); // start serial for output + Wire.begin(); // master joins I2C bus (address optional for master) + Wire1.begin(8); // slave joins I2C bus with address #8 + Wire1.onReceive(receiveEvent); // register event + + // This is just for curiosity and could be removed + printWireBuffersCapacity(Serial); + printWire1BuffersCapacity(Serial); +} + +static byte x = 0; + +void loop() { + Wire.beginTransmission(8); // transmit to device #8 + Wire.write(text); // sends multiple bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. +void receiveEvent(int howMany) { + while (1 < Wire1.available()) { // loop through all but the last + const char c = Wire1.read(); // receive byte as a character + Serial.print(c); // print the character + } + const int x = Wire1.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +void printWireBuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire_BUFFERS(); + + stream.print("Wire transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); + delay(250); // Give time to finalize the print out +} + +void printWire1BuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire1_BUFFERS(); + + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire1 service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); + delay(250); // Give time to free up Serial output buffer. +} diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino new file mode 100644 index 00000000..fef329cd --- /dev/null +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -0,0 +1,117 @@ +// Wire Slave Receiver Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Receives data as an I2C/TWI slave device +// Refer to the "Wire Master Writer Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +constexpr size_t RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. +constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire.begin(8); // join I2C bus with address #8 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWireBuffersCapacity(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. +void receiveEvent(int howMany) { + while (1 < Wire.available()) { // loop through all but the last + const char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + const int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +void printWireBuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire_BUFFERS(); + + stream.print("Wire transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); + delay(250); // Give time to free up Serial output buffer. +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire1.begin(8); // join I2C bus with address #8 + Wire1.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output + + // This is just for curiosity and could be removed + printWire1BuffersCapacity(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +// +// Hint: This function is called within an interrupt context. +// That means, that there must be enough space in the Serial output +// buffer for the characters to be printed. Otherwise the +// Serial.print() call will lock up. +void receiveEvent(int howMany) { + while (1 < Wire1.available()) { // loop through all but the last + const char c = Wire1.read(); // receive byte as a character + Serial.print(c); // print the character + } + const int x = Wire1.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +void printWire1BuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire1_BUFFERS(); + + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire1 service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); + delay(250); // Give time to free up Serial output buffer. +} + +#endif diff --git a/libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino b/libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino new file mode 100644 index 00000000..9260aa23 --- /dev/null +++ b/libraries/Wire/examples/slave_sender_Wire1Wire_connected/slave_sender_Wire1Wire_connected.ino @@ -0,0 +1,91 @@ +// Wire1 connnected to Wire. (scl <-> scl1, sda <-> sda1) + +// Demonstrates use of the Wire library on a single Arduino board +// with 2 Wire interfaces (like Arduino Due). +// Uses the option of customizing the buffers. +// +// Wire reads data from an I2C/TWI slave device +// Wire1 sends data as an I2C/TWI slave device + +// Created 02 Jan 2025 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +static_assert(WIRE_INTERFACES_COUNT > 1, "You need two I2C interfaces on the Arduino board to run this sketch"); + +static const char text[] = "hello "; // respond with message of 6 bytes + +// Wire is the master reader +constexpr size_t M_RECEIVE_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 +constexpr size_t M_TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. +SET_Wire_BUFFERS(M_RECEIVE_BUFFER_SIZE, M_TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no slave buffers needed */ ); + +// Wire1 is the slave sender +constexpr size_t S_RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t S_TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 +SET_Wire1_BUFFERS(S_RECEIVE_BUFFER_SIZE, S_TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Serial.begin(9600); // start serial for output + Wire.begin(); // master joins I2C bus (address optional for master) + Wire1.begin(8); // slave joins I2C bus with address #8 + Wire1.onRequest(requestEvent); // register slave event + + // This is just for curiosity and could be removed + printWireBuffersCapacity(Serial); + printWire1BuffersCapacity(Serial); +} + +void loop() { + Wire.requestFrom(8, M_RECEIVE_BUFFER_SIZE); + + while (Wire.available()) { + const char c = Wire.read(); // receive a byte as character + Serial.print(c); // print the character + } + Serial.println(); + + delay(500); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire1.write(text); + // as expected by master +} + +// print Wire buffer sizes +void printWireBuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire_BUFFERS(); + + stream.print("Wire transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +// print Wire1 buffer sizes +void printWire1BuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire1_BUFFERS(); + + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire1 service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} diff --git a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino new file mode 100644 index 00000000..f09d692a --- /dev/null +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -0,0 +1,99 @@ +// Wire Slave Sender Custom Buffer + +// Demonstrates use of the Wire library with customized buffers +// Sends data as an I2C/TWI slave device +// Refer to the "Wire Master Reader Custom Buffer" example for use with this + +// Created 31 Dec 2024 + +// This example code is in the public domain. + + +#include +#include +#include "Arduino.h" + +#define USE_WIRE1 false // Set to true for using Wire1 + +static const char text[] = "hello "; // respond with message of 6 bytes + +constexpr size_t RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +constexpr size_t TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 + +#if not USE_WIRE1 + +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire.begin(8); // join I2C bus with address #8 + Wire.onRequest(requestEvent); // register event + + // This is just for curiosity and could be removed + Serial.begin(9600); + printWireBuffersCapacity(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire.write(text); + // as expected by master +} + +void printWireBuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire_BUFFERS(); + + stream.print("Wire transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +#else + +SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + false /* no master buffers needed */, true /* slave buffers needed */ ); + +void setup() { + Wire1.begin(8); // join I2C bus with address #8 + Wire1.onRequest(requestEvent); // register event + + // This is just for curiosity and could be removed + Serial.begin(9600); + printWire1BuffersCapacity(Serial); +} + +void loop() { + delay(100); +} + +// function that executes whenever data is requested by master +// this function is registered as an event, see setup() +void requestEvent() { + Wire1.write(text); + // as expected by master +} + +void printWire1BuffersCapacity(Stream& stream) { + const auto& buffers = GET_Wire1_BUFFERS(); + + stream.print("Wire1 transmit buffer size is "); + stream.println(buffers.txWireBufferCapacity()); + + stream.print("Wire1 receive buffer size is "); + stream.println(buffers.rxWireBufferCapacity()); + + stream.print("Wire1 service buffer size is "); + stream.println(buffers.srvWireBufferCapacity()); +} + +#endif diff --git a/libraries/Wire/src/TwoWireBuffers.cpp b/libraries/Wire/src/TwoWireBuffers.cpp new file mode 100644 index 00000000..b8160f85 --- /dev/null +++ b/libraries/Wire/src/TwoWireBuffers.cpp @@ -0,0 +1,40 @@ +/* + TwoWireBuffers.cpp - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "TwoWireBuffers.h" +#include "variant.h" + +constexpr size_t RX_BUFFER_DEFAULT_LENGTH = 32; +constexpr size_t TX_BUFFER_DEFAULT_LENGTH = 32; + +#if WIRE_INTERFACES_COUNT > 0 +// Default buffers for the Wire object +template<> __attribute__((weak)) TwoWireBuffers::Interface& WireBuffers<0>::instance() { \ + static TwoWireBuffers::Impl buffers; \ + return buffers; \ +} +#endif + +#if WIRE_INTERFACES_COUNT > 1 +// Default buffers for the Wire1 object +template<> __attribute__((weak)) TwoWireBuffers::Interface& WireBuffers<1>::instance() { \ + static TwoWireBuffers::Impl buffers; \ + return buffers; \ +} +#endif diff --git a/libraries/Wire/src/TwoWireBuffers.h b/libraries/Wire/src/TwoWireBuffers.h new file mode 100644 index 00000000..b5960863 --- /dev/null +++ b/libraries/Wire/src/TwoWireBuffers.h @@ -0,0 +1,121 @@ +/* + TwoWireBuffers.h - TWI/I2C library for Wiring & Arduino + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#pragma once + +#ifndef TwiBuffers_h +#define TwiBuffers_h + +#include +#include +#include + +namespace TwoWireBuffers { + +/* Template class that implements an compile time fixed size array. */ +template +class StaticBuffer { + uint8_t mByteArray[CAPACITY]; +public: + inline uint8_t capacity() const {return CAPACITY;} + inline uint8_t* storage() {return mByteArray;} +}; + +/* Specialization of StaticBuffer template class with zero size. */ +template<> +class StaticBuffer<0> { +public: + inline uint8_t capacity() const {return 0;} + inline uint8_t* storage() {return nullptr;} +}; + + +/* Interface that provides buffers for twi driver and TwoWire objects */ +class Interface { +public: + virtual uint8_t* rxWireBuffer() = 0; + virtual size_t rxWireBufferCapacity()const = 0; + + virtual uint8_t* txWireBuffer() = 0; + virtual size_t txWireBufferCapacity()const = 0; + + virtual uint8_t* srvWireBuffer() = 0; + virtual size_t srvWireBufferCapacity()const = 0; +}; + +/* Template class implementing Interface with template parameter + * determined buffer sizes. + */ +template< + size_t RX_CAPACITY, // Receive buffer size. May be zero, if only transmitting data is needed + size_t TX_CAPACITY // Transmit buffer size. May be zero, if only receiving data is needed + > +class Impl : public Interface { + // Service buffer is needed for transmit and receive. + static constexpr size_t SRV_CAPACITY = + RX_CAPACITY > TX_CAPACITY ? RX_CAPACITY : TX_CAPACITY; + + // Set the capacity for a TwoWire object. + TwoWireBuffers::StaticBuffer mRxWireBuffer; + TwoWireBuffers::StaticBuffer mTxWireBuffer; + TwoWireBuffers::StaticBuffer mSrvWireBuffer; + +public: + virtual uint8_t* rxWireBuffer() override {return mRxWireBuffer.storage();} + virtual size_t rxWireBufferCapacity()const override {return mRxWireBuffer.capacity();} + + virtual uint8_t* txWireBuffer() override {return mTxWireBuffer.storage();} + virtual size_t txWireBufferCapacity()const override {return mTxWireBuffer.capacity();} + + virtual uint8_t* srvWireBuffer() override {return mSrvWireBuffer.storage();} + virtual size_t srvWireBufferCapacity()const override {return mSrvWireBuffer.capacity();} +}; + +} // namespace TwoWireBuffers + +template struct WireBuffers { // The buffers for the Wire object + static TwoWireBuffers::Interface& instance(); +}; + +// Note: enableMaster and enableSlave don't have any impact on sam architecture, but they +// are present to keep the macro compatible with the one on the avr architecture, where +// it makes a difference in regard to memory consumption. +#define SET_WIRE_BUFFERS_(wireNum, rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) \ + template<> TwoWireBuffers::Interface& WireBuffers::instance() { \ + static TwoWireBuffers::Impl buffers; \ + return buffers; \ + } + +#define GET_WIRE_BUFFERS_(wireNum) WireBuffers::instance() + +#if WIRE_INTERFACES_COUNT > 0 + #define SET_Wire_BUFFERS(rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) \ + SET_WIRE_BUFFERS_(0, rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) + + #define GET_Wire_BUFFERS() GET_WIRE_BUFFERS_(0) +#endif + +#if WIRE_INTERFACES_COUNT > 1 + #define SET_Wire1_BUFFERS(rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) \ + SET_WIRE_BUFFERS_(1, rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) + + #define GET_Wire1_BUFFERS() GET_WIRE_BUFFERS_(1) +#endif + +#endif /* TwiBuffers_h */ diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 2cb7dfe2..8135fd88 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -1,5 +1,5 @@ /* - * TwoWire.h - TWI/I2C library for Arduino Due + * Wire.cpp - TWI/I2C library for Arduino Due * Copyright (c) 2011 Cristian Maglie * All rights reserved. * @@ -27,6 +27,7 @@ extern "C" { } #include "Wire.h" +#include "TwoWireBuffers.h" static inline bool TWI_FailedAcknowledge(Twi *pTwi) { return pTwi->TWI_SR & TWI_SR_NACK; @@ -96,13 +97,20 @@ static inline bool TWI_STATUS_NACK(uint32_t status) { return (status & TWI_SR_NACK) == TWI_SR_NACK; } -TwoWire::TwoWire(Twi *_twi, void(*_beginCb)(void), void(*_endCb)(void)) : - twi(_twi), rxBufferIndex(0), rxBufferLength(0), txAddress(0), +TwoWire::TwoWire(TwoWireBuffers::Interface& _twbi, Twi *_twi, void(*_beginCb)(void), void(*_endCb)(void)) : + buffers(_twbi), twi(_twi), rxBufferIndex(0), rxBufferLength(0), txAddress(0), txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status( UNINITIALIZED), onBeginCallback(_beginCb), onEndCallback(_endCb), twiClock(TWI_CLOCK) { } +uint8_t* TwoWire::srvBuffer()const {return buffers.srvWireBuffer();} +size_t TwoWire::srvBufferCapacity()const {return buffers.srvWireBufferCapacity();} +uint8_t* TwoWire::rxBuffer()const {return buffers.rxWireBuffer();} +size_t TwoWire::rxBufferCapacity()const {return buffers.rxWireBufferCapacity();} +uint8_t* TwoWire::txBuffer()const {return buffers.txWireBuffer();} +size_t TwoWire::txBufferCapacity()const {return buffers.txWireBufferCapacity();} + void TwoWire::begin(void) { if (onBeginCallback) onBeginCallback(); @@ -147,19 +155,21 @@ void TwoWire::setClock(uint32_t frequency) { } uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { - if (quantity > BUFFER_LENGTH) - quantity = BUFFER_LENGTH; + if (quantity > rxBufferCapacity()) + quantity = rxBufferCapacity(); // perform blocking read into buffer int readed = 0; TWI_StartRead(twi, address, iaddress, isize); + + uint8_t* const rxBuf = rxBuffer(); do { // Stop condition must be set during the reception of last byte if (readed + 1 == quantity) TWI_SendSTOPCondition( twi); if (TWI_WaitByteReceived(twi, RECV_TIMEOUT)) - rxBuffer[readed++] = TWI_ReadByte(twi); + rxBuf[readed++] = TWI_ReadByte(twi); else break; } while (readed < quantity); @@ -172,22 +182,6 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres return readed; } -uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, (uint8_t) 0, (uint8_t) sendStop); -} - -uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); -} - -uint8_t TwoWire::requestFrom(int address, int quantity) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true); -} - -uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) { - return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) sendStop); -} - void TwoWire::beginTransmission(uint8_t address) { status = MASTER_SEND; @@ -196,10 +190,6 @@ void TwoWire::beginTransmission(uint8_t address) { txBufferLength = 0; } -void TwoWire::beginTransmission(int address) { - beginTransmission((uint8_t) address); -} - // // Originally, 'endTransmission' was an f(void) function. // It has been modified to take one parameter indicating @@ -216,14 +206,15 @@ void TwoWire::beginTransmission(int address) { uint8_t TwoWire::endTransmission(uint8_t sendStop) { uint8_t error = 0; // transmit buffer (blocking) - TWI_StartWrite(twi, txAddress, 0, 0, txBuffer[0]); + uint8_t* const txBuf = txBuffer(); + TWI_StartWrite(twi, txAddress, 0, 0, txBuf[0]); if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT)) error = 2; // error, got NACK on address transmit if (error == 0) { uint16_t sent = 1; while (sent < txBufferLength) { - TWI_WriteByte(twi, txBuffer[sent++]); + TWI_WriteByte(twi, txBuf[sent++]); if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT)) error = 3; // error, got NACK during data transmmit } @@ -250,30 +241,32 @@ uint8_t TwoWire::endTransmission(void) size_t TwoWire::write(uint8_t data) { if (status == MASTER_SEND) { - if (txBufferLength >= BUFFER_LENGTH) + if (txBufferLength >= txBufferCapacity()) return 0; - txBuffer[txBufferLength++] = data; + txBuffer()[txBufferLength++] = data; return 1; } else { - if (srvBufferLength >= BUFFER_LENGTH) + if (srvBufferLength >= srvBufferCapacity()) return 0; - srvBuffer[srvBufferLength++] = data; + srvBuffer()[srvBufferLength++] = data; return 1; } } size_t TwoWire::write(const uint8_t *data, size_t quantity) { if (status == MASTER_SEND) { + uint8_t* const txBuf = txBuffer(); for (size_t i = 0; i < quantity; ++i) { - if (txBufferLength >= BUFFER_LENGTH) + if (txBufferLength >= txBufferCapacity()) return i; - txBuffer[txBufferLength++] = data[i]; + txBuf[txBufferLength++] = data[i]; } } else { + uint8_t* const srvBuf = srvBuffer(); for (size_t i = 0; i < quantity; ++i) { - if (srvBufferLength >= BUFFER_LENGTH) + if (srvBufferLength >= srvBufferCapacity()) return i; - srvBuffer[srvBufferLength++] = data[i]; + srvBuf[srvBufferLength++] = data[i]; } } return quantity; @@ -285,13 +278,13 @@ int TwoWire::available(void) { int TwoWire::read(void) { if (rxBufferIndex < rxBufferLength) - return rxBuffer[rxBufferIndex++]; + return rxBuffer()[rxBufferIndex++]; return -1; } int TwoWire::peek(void) { if (rxBufferIndex < rxBufferLength) - return rxBuffer[rxBufferIndex]; + return rxBuffer()[rxBufferIndex]; return -1; } @@ -332,7 +325,7 @@ void TwoWire::onService(void) { onRequestCallback(); else // create a default 1-byte response - write((uint8_t) 0); + write(static_cast(0)); } } @@ -341,8 +334,13 @@ void TwoWire::onService(void) { // Copy data into rxBuffer // (allows to receive another packet while the // user program reads actual data) - for (uint8_t i = 0; i < srvBufferLength; ++i) - rxBuffer[i] = srvBuffer[i]; + + uint8_t* const srvBuff = srvBuffer(); + uint8_t* const rxBuff = rxBuffer(); + for (size_t i = 0; i < srvBufferLength; ++i) { + rxBuff[i] = srvBuff[i]; + } + rxBufferIndex = 0; rxBufferLength = srvBufferLength; @@ -359,8 +357,8 @@ void TwoWire::onService(void) { if (status == SLAVE_RECV) { if (TWI_STATUS_RXRDY(sr)) { - if (srvBufferLength < BUFFER_LENGTH) - srvBuffer[srvBufferLength++] = TWI_ReadByte(twi); + if (srvBufferLength < srvBufferCapacity()) + srvBuffer()[srvBufferLength++] = TWI_ReadByte(twi); } } @@ -368,7 +366,7 @@ void TwoWire::onService(void) { if (TWI_STATUS_TXRDY(sr) && !TWI_STATUS_NACK(sr)) { uint8_t c = 'x'; if (srvBufferIndex < srvBufferLength) - c = srvBuffer[srvBufferIndex++]; + c = srvBuffer()[srvBufferIndex++]; TWI_WriteByte(twi, c); } } @@ -405,7 +403,7 @@ static void Wire_Deinit(void) { // and pullups were not enabled } -TwoWire Wire = TwoWire(WIRE_INTERFACE, Wire_Init, Wire_Deinit); +TwoWire Wire = TwoWire(WireBuffers<0>::instance(), WIRE_INTERFACE, Wire_Init, Wire_Deinit); void WIRE_ISR_HANDLER(void) { Wire.onService(); @@ -443,11 +441,12 @@ static void Wire1_Deinit(void) { // and pullups were not enabled } -TwoWire Wire1 = TwoWire(WIRE1_INTERFACE, Wire1_Init, Wire1_Deinit); +TwoWire Wire1 = TwoWire(WireBuffers<1>::instance(), WIRE1_INTERFACE, Wire1_Init, Wire1_Deinit); void WIRE1_ISR_HANDLER(void) { Wire1.onService(); } + #endif #pragma GCC diagnostic pop diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 3913c983..1a32bf83 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -1,5 +1,5 @@ /* - * TwoWire.h - TWI/I2C library for Arduino Due + * Wire.h - TWI/I2C library for Arduino Due * Copyright (c) 2011 Cristian Maglie * All rights reserved. * @@ -27,28 +27,43 @@ #include "Stream.h" #include "variant.h" -#define BUFFER_LENGTH 32 - // WIRE_HAS_END means Wire has end() #define WIRE_HAS_END 1 + +namespace TwoWireBuffers { + class Interface; +} + class TwoWire : public Stream { public: - TwoWire(Twi *twi, void(*begin_cb)(void), void(*end_cb)(void)); + TwoWire(TwoWireBuffers::Interface& twbi, Twi *twi, void(*begin_cb)(void), void(*end_cb)(void)); void begin(); void begin(uint8_t); void begin(int); void end(); void setClock(uint32_t); void beginTransmission(uint8_t); - void beginTransmission(int); + inline void beginTransmission(int address) {beginTransmission(static_cast(address));} uint8_t endTransmission(void); - uint8_t endTransmission(uint8_t); - uint8_t requestFrom(uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint8_t); - uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); - uint8_t requestFrom(int, int); - uint8_t requestFrom(int, int, int); + uint8_t endTransmission(uint8_t); + uint8_t requestFrom(uint8_t, uint8_t, uint32_t, uint8_t, uint8_t); + inline uint8_t requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom(static_cast(address), static_cast(quantity), + static_cast(true)); + } + inline uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { + return requestFrom(static_cast(address), static_cast(quantity), + static_cast(0), static_cast(0), static_cast(sendStop)); + } + inline uint8_t requestFrom(int address, int quantity) { + return requestFrom(static_cast(address), static_cast(quantity), + static_cast(true)); + } + inline uint8_t requestFrom(int address, int quantity, int sendStop) { + return requestFrom(static_cast(address), static_cast(quantity), + static_cast(sendStop)); + } virtual size_t write(uint8_t); virtual size_t write(const uint8_t *, size_t); virtual int available(void); @@ -58,27 +73,34 @@ class TwoWire : public Stream { void onReceive(void(*)(int)); void onRequest(void(*)(void)); - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } - using Print::write; + inline size_t write(unsigned long n) { return write(static_cast(n)); } + inline size_t write(long n) { return write(static_cast(n)); } + inline size_t write(unsigned int n) { return write(static_cast(n)); } + inline size_t write(int n) { return write(static_cast(n)); } + using Print::write; void onService(void); + inline size_t rxBufferCapacity()const; + inline size_t txBufferCapacity()const; + inline size_t srvBufferCapacity()const; + private: + // The buffers to be used for this Wire object. + TwoWireBuffers::Interface& buffers; + // RX Buffer - uint8_t rxBuffer[BUFFER_LENGTH]; + inline uint8_t* rxBuffer()const; uint8_t rxBufferIndex; uint8_t rxBufferLength; // TX Buffer uint8_t txAddress; - uint8_t txBuffer[BUFFER_LENGTH]; + inline uint8_t* txBuffer()const; uint8_t txBufferLength; // Service buffer - uint8_t srvBuffer[BUFFER_LENGTH]; + inline uint8_t* srvBuffer()const; uint8_t srvBufferIndex; uint8_t srvBufferLength; @@ -108,18 +130,20 @@ class TwoWire : public Stream { TwoWireStatus status; // TWI clock frequency - static const uint32_t TWI_CLOCK = 100000; + static constexpr uint32_t TWI_CLOCK = 100000; uint32_t twiClock; // Timeouts ( - static const uint32_t RECV_TIMEOUT = 100000; - static const uint32_t XMIT_TIMEOUT = 100000; + static constexpr uint32_t RECV_TIMEOUT = 100000; + static constexpr uint32_t XMIT_TIMEOUT = 100000; }; #if WIRE_INTERFACES_COUNT > 0 +// The buffers for the Wire object extern TwoWire Wire; #endif #if WIRE_INTERFACES_COUNT > 1 +// The buffers for the Wire1 object extern TwoWire Wire1; #endif