From 891b446bca1ef9aabe0b6ffe8c7aa3e65cb41cc0 Mon Sep 17 00:00:00 2001 From: dac1e Date: Sat, 28 Dec 2024 07:14:27 +0100 Subject: [PATCH 01/12] Renamed twi.c to twi.cpp --- libraries/Wire/src/Wire.cpp | 10 ++++------ libraries/Wire/src/utility/{twi.c => twi.cpp} | 0 2 files changed, 4 insertions(+), 6 deletions(-) rename libraries/Wire/src/utility/{twi.c => twi.cpp} (100%) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 001d924df..7c45eb366 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -21,12 +21,10 @@ Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts */ -extern "C" { - #include - #include - #include - #include "utility/twi.h" -} +#include +#include +#include +#include "utility/twi.h" #include "Wire.h" diff --git a/libraries/Wire/src/utility/twi.c b/libraries/Wire/src/utility/twi.cpp similarity index 100% rename from libraries/Wire/src/utility/twi.c rename to libraries/Wire/src/utility/twi.cpp From 9cc9ada37bfc2746642f516f1e554f5285658935 Mon Sep 17 00:00:00 2001 From: dac1e Date: Sat, 28 Dec 2024 07:46:19 +0100 Subject: [PATCH 02/12] Changed static variables of Wire to non static. Some functions only doing type casts and forwarding are now inline which improves speed. Refactored code to more actual C++ style. --- libraries/Wire/src/Wire.cpp | 65 ++++++++++--------------------- libraries/Wire/src/Wire.h | 78 +++++++++++++++++++++++-------------- 2 files changed, 68 insertions(+), 75 deletions(-) diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 7c45eb366..ab58d8632 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -28,24 +28,18 @@ #include "Wire.h" -// Initialize Class Variables ////////////////////////////////////////////////// - -uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; -uint8_t TwoWire::rxBufferIndex = 0; -uint8_t TwoWire::rxBufferLength = 0; - -uint8_t TwoWire::txAddress = 0; -uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; -uint8_t TwoWire::txBufferIndex = 0; -uint8_t TwoWire::txBufferLength = 0; - -uint8_t TwoWire::transmitting = 0; -void (*TwoWire::user_onRequest)(void); -void (*TwoWire::user_onReceive)(int); // Constructors //////////////////////////////////////////////////////////////// TwoWire::TwoWire() + : rxBufferIndex(0) + , rxBufferLength(0) + , txAddress(0) + , txBufferIndex(0) + , txBufferLength(0) + , transmitting(0) + , user_onRequest(nullptr) + , user_onReceive(nullptr) { } @@ -60,8 +54,8 @@ void TwoWire::begin(void) txBufferLength = 0; twi_init(); - twi_attachSlaveTxEvent(onRequestService); // default callback must exist - twi_attachSlaveRxEvent(onReceiveService); // default callback must exist + twi_attachSlaveTxEvent(onRequestService_); // default callback must exist + twi_attachSlaveRxEvent(onReceiveService_); // default callback must exist } void TwoWire::begin(uint8_t address) @@ -70,11 +64,6 @@ void TwoWire::begin(uint8_t address) twi_setAddress(address); } -void TwoWire::begin(int address) -{ - begin((uint8_t)address); -} - void TwoWire::end(void) { twi_disable(); @@ -164,25 +153,6 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres return read; } -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) { // indicate that we are transmitting @@ -194,11 +164,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 @@ -318,6 +283,11 @@ void TwoWire::flush(void) // XXX: to be implemented. } +void TwoWire::onReceiveService_(uint8_t* inBytes, int numBytes) +{ + Wire.onReceiveService(inBytes, numBytes); +} + // behind the scenes function that is called when data is received void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) { @@ -343,6 +313,11 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) user_onReceive(numBytes); } +void TwoWire::onRequestService_() +{ + Wire.onRequestService(); +} + // behind the scenes function that is called when data is requested void TwoWire::onRequestService(void) { diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index e70d72edb..3858036c9 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -20,6 +20,9 @@ Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts */ + +#pragma once + #ifndef TwoWire_h #define TwoWire_h @@ -34,52 +37,67 @@ class TwoWire : public Stream { private: - static uint8_t rxBuffer[]; - static uint8_t rxBufferIndex; - static uint8_t rxBufferLength; - - static uint8_t txAddress; - static uint8_t txBuffer[]; - static uint8_t txBufferIndex; - static uint8_t txBufferLength; - - static uint8_t transmitting; - static void (*user_onRequest)(void); - static void (*user_onReceive)(int); - static void onRequestService(void); - static void onReceiveService(uint8_t*, int); + uint8_t rxBuffer[BUFFER_LENGTH]; + uint8_t rxBufferIndex; + uint8_t rxBufferLength; + + uint8_t txAddress; + uint8_t txBuffer[BUFFER_LENGTH]; + uint8_t txBufferIndex; + uint8_t txBufferLength; + + uint8_t transmitting; + void (*user_onRequest)(void); + void (*user_onReceive)(int); + + static void onRequestService_(void); + static void onReceiveService_(uint8_t*, int); + + void onRequestService(void); + void onReceiveService(uint8_t*, int); public: TwoWire(); void begin(); void begin(uint8_t); - void begin(int); + inline void begin(int address) {begin(static_cast(address));} void end(); void setClock(uint32_t); void setWireTimeout(uint32_t timeout = 25000, bool reset_with_timeout = false); bool getWireTimeoutFlag(void); void clearWireTimeoutFlag(void); void beginTransmission(uint8_t); - void beginTransmission(int); + 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); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *, size_t); - virtual int available(void); - virtual int read(void); - virtual int peek(void); - virtual void flush(void); + inline uint8_t requestFrom(uint8_t address, uint8_t quantity) { + return requestFrom(address, quantity, static_cast(true)); + } + inline uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) { + return requestFrom(address, 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) override; + virtual size_t write(const uint8_t *, size_t) override; + virtual int available(void) override; + virtual int read(void) override; + virtual int peek(void) override; + virtual void flush(void) override; 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); } + 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; }; From 073cd4c221a008c830842e19f3614ac802947cd4 Mon Sep 17 00:00:00 2001 From: dac1e Date: Sat, 28 Dec 2024 10:49:28 +0100 Subject: [PATCH 03/12] Moved macros that are not part of the twi API from twi.h to twi.cpp. Replaced TWI_STATE preprocessor macro by enum TWI_STATE. Added #pragma once in twi.h. --- libraries/Wire/src/utility/twi.cpp | 16 ++++++++++++++++ libraries/Wire/src/utility/twi.h | 18 +++--------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/libraries/Wire/src/utility/twi.cpp b/libraries/Wire/src/utility/twi.cpp index e09a33caf..c9100116a 100644 --- a/libraries/Wire/src/utility/twi.cpp +++ b/libraries/Wire/src/utility/twi.cpp @@ -40,6 +40,22 @@ #include "pins_arduino.h" #include "twi.h" +#ifndef TWI_FREQ +#define TWI_FREQ 100000L +#endif + +#ifndef TWI_BUFFER_LENGTH +#define TWI_BUFFER_LENGTH 32 +#endif + +enum TWI_STATE { + TWI_READY = 0, + TWI_MRX = 1, + TWI_MTX = 2, + TWI_SRX = 3, + TWI_STX = 4, +}; + static volatile uint8_t twi_state; static volatile uint8_t twi_slarw; static volatile uint8_t twi_sendStop; // should the transaction end with a stop diff --git a/libraries/Wire/src/utility/twi.h b/libraries/Wire/src/utility/twi.h index 85b983794..416ed8855 100644 --- a/libraries/Wire/src/utility/twi.h +++ b/libraries/Wire/src/utility/twi.h @@ -19,6 +19,8 @@ Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts */ +#pragma once + #ifndef twi_h #define twi_h @@ -26,20 +28,6 @@ //#define ATMEGA8 - #ifndef TWI_FREQ - #define TWI_FREQ 100000L - #endif - - #ifndef TWI_BUFFER_LENGTH - #define TWI_BUFFER_LENGTH 32 - #endif - - #define TWI_READY 0 - #define TWI_MRX 1 - #define TWI_MTX 2 - #define TWI_SRX 3 - #define TWI_STX 4 - void twi_init(void); void twi_disable(void); void twi_setAddress(uint8_t); @@ -56,4 +44,4 @@ void twi_handleTimeout(bool); bool twi_manageTimeoutFlag(bool); -#endif +#endif // #ifndef twi_h From 7bbadfb7d3723c245806f169f417fd33763dfcc1 Mon Sep 17 00:00:00 2001 From: dac1e Date: Sat, 28 Dec 2024 11:06:45 +0100 Subject: [PATCH 04/12] Use TwiBuffers class for all buffers needed by Wire and twi. Allows optionally tweaking Wire buffer and twi buffer sizes at compile time. enum TWI_STATE : uint8_t becomes uint8_t. twi_state type changed form uint8_t to TWI_STATE. Added examples for customized buffers. Do println() after all received characters have been printed in master_reader.ino. --- .../examples/master_reader/master_reader.ino | 1 + .../master_reader_custombuffer.ino | 73 ++++++++++ .../examples/master_writer/master_writer.ino | 2 +- .../master_writer_custombuffer.ino | 73 ++++++++++ .../slave_receiver_custombuffer.ino | 74 ++++++++++ .../slave_sender_custombuffer.ino | 72 +++++++++ libraries/Wire/src/TwoWireBuffers.cpp | 29 ++++ libraries/Wire/src/TwoWireBuffers.h | 137 ++++++++++++++++++ libraries/Wire/src/Wire.cpp | 73 +++++++--- libraries/Wire/src/Wire.h | 15 +- libraries/Wire/src/utility/twi.cpp | 99 ++++++++----- 11 files changed, 581 insertions(+), 67 deletions(-) create mode 100644 libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino create mode 100644 libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino create mode 100644 libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino create mode 100644 libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino create mode 100644 libraries/Wire/src/TwoWireBuffers.cpp create mode 100644 libraries/Wire/src/TwoWireBuffers.h diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino index e27cac32b..214ffe996 100644 --- a/libraries/Wire/examples/master_reader/master_reader.ino +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -24,6 +24,7 @@ void loop() { 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 000000000..27d7a930c --- /dev/null +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -0,0 +1,73 @@ +// Wire Master Reader Custom Buffer + +// Demonstrates use of the Wire library +// 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 + +// request 6 bytes from slave device #8 +size_t constexpr REQUESTED_BYTE_COUNT = 6; + +/**** Begin Customize buffers ****/ +// Note: If you spell namespace 'WireBuffers' wrongly, all buffer +// sizes of the 'Wire' object stay at default (32 bytes). +namespace WireBuffers { + size_t constexpr RECEIVE_BUFFER_SIZE = REQUESTED_BYTE_COUNT; + size_t constexpr TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + // We operate as a master only, so we use the macro that will set slave buffers to zero. + SET_BUFFERS_FOR_MASTER_ONLY(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE); +} +/**** End Customize buffers ******/ + +// This is just for curiosity. +// Set to false if you don't want to see actual buffer sizes on serial monitor. +#define VERBOSE true + +void setup() { + Wire.begin(); // join I2C bus (address optional for master) + Serial.begin(9600); // start serial for output +#if VERBOSE + printWireBuffers(); +#endif +} + +void loop() { + Wire.requestFrom(8, REQUESTED_BYTE_COUNT); + + 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); +} + +#if VERBOSE +void printWireBuffers() { + delay(100); + Serial.println(); + Serial.print("Wire transmit buffer size is "); + Serial.println(Wire.txBufferCapacity()); + Serial.print("Wire receive buffer size is "); + Serial.println(Wire.rxBufferCapacity()); + + TwoWireBuffers::Interface& buffers = WireBuffers::instance(); + Serial.print("twi_masterBuffer size is "); + Serial.println(buffers.twi_masterBufferCapacity()); + + Serial.print("twi_rxBuffer size is "); + Serial.println(buffers.twi_rxBufferCapacity()); + + Serial.print("twi_txBuffer size is "); + Serial.println(buffers.twi_txBufferCapacity()); + delay(500); +} +#endif diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino index 7a1766874..09bf12d57 100644 --- a/libraries/Wire/examples/master_writer/master_writer.ino +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -16,7 +16,7 @@ void setup() { Wire.begin(); // join I2C bus (address optional for master) } -byte x = 0; +static byte x = 0; void loop() { Wire.beginTransmission(8); // transmit to device #8 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 000000000..df6f3cf7c --- /dev/null +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -0,0 +1,73 @@ +// Wire Master Writer Custom Buffer + +// Demonstrates use of the Wire library +// 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 + +// 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 "; + +/**** Begin Customize buffers ****/ +// Note: If you spell namespace 'WireBuffers' wrongly, all buffer sizes +// of the 'Wire' object stay at default (32 bytes). +namespace WireBuffers { + size_t constexpr RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. + size_t constexpr TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. + // We operate as a master only, so we use the macro that will set slave buffers to zero. + SET_BUFFERS_FOR_MASTER_ONLY(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE); +} +/**** End Customize buffers ******/ + +// This is just for curiosity. +// Set to false if you don't want to see actual buffer sizes on serial monitor. +#define VERBOSE true + +void setup() { + Wire.begin(); // join I2C bus (address optional for master) +#if VERBOSE + Serial.begin(9600); // start serial for output + printWireBuffers(); +#endif +} + +static byte x = 0; + +void loop() { + Wire.beginTransmission(8); // transmit to device #8 + Wire.write(text); // sends five bytes + Wire.write(x); // sends one byte + Wire.endTransmission(); // stop transmitting + + x++; + delay(500); +} + +#if VERBOSE +void printWireBuffers() { + delay(100); + Serial.println(); + Serial.print("Wire transmit buffer size is "); + Serial.println(Wire.txBufferCapacity()); + Serial.print("Wire receive buffer size is "); + Serial.println(Wire.rxBufferCapacity()); + + TwoWireBuffers::Interface& buffers = WireBuffers::instance(); + Serial.print("twi_masterBuffer size is "); + Serial.println(buffers.twi_masterBufferCapacity()); + + Serial.print("twi_rxBuffer size is "); + Serial.println(buffers.twi_rxBufferCapacity()); + + Serial.print("twi_txBuffer size is "); + Serial.println(buffers.twi_txBufferCapacity()); + delay(500); +} +#endif 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 000000000..48f6ca718 --- /dev/null +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -0,0 +1,74 @@ +// Wire Slave Receiver Custom Buffer + +// Demonstrates use of the Wire library +// 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 + +/**** Begin Customize buffers ****/ +// Note: If you spell namespace 'WireBuffers' wrongly, all buffer sizes +// of the 'Wire' object stay at default (32 bytes). +namespace WireBuffers { + size_t constexpr RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. + size_t constexpr TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + // We operate as a slave only, so we use the macro that will set master buffers to zero. + SET_BUFFERS_FOR_SLAVE_ONLY(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE); +} +/**** End Customize buffers ******/ + +// This is just for curiosity. +// Set to false if you don't want to see actual buffer sizes on serial monitor. +#define VERBOSE true + +void setup() { + Wire.begin(8); // join I2C bus with address #8 + Wire.onReceive(receiveEvent); // register event + Serial.begin(9600); // start serial for output +#if VERBOSE + printWireBuffers(); +#endif +} + +void loop() { + delay(100); +} + +// function that executes whenever data is received from master +// this function is registered as an event, see setup() +void receiveEvent(int howMany) { + while (1 < Wire.available()) { // loop through all but the last + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + int x = Wire.read(); // receive byte as an integer + Serial.println(x); // print the integer +} + +#if VERBOSE +void printWireBuffers() { + delay(100); + Serial.println(); + Serial.print("Wire transmit buffer size is "); + Serial.println(Wire.txBufferCapacity()); + Serial.print("Wire receive buffer size is "); + Serial.println(Wire.rxBufferCapacity()); + + TwoWireBuffers::Interface& buffers = WireBuffers::instance(); + Serial.print("twi_masterBuffer size is "); + Serial.println(buffers.twi_masterBufferCapacity()); + + Serial.print("twi_rxBuffer size is "); + Serial.println(buffers.twi_rxBufferCapacity()); + + Serial.print("twi_txBuffer size is "); + Serial.println(buffers.twi_txBufferCapacity()); + delay(500); +} +#endif 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 000000000..6d118f248 --- /dev/null +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -0,0 +1,72 @@ +// Wire Slave Sender Custom Buffer + +// Demonstrates use of the Wire library +// 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 + +static const char text[] = "hello "; // respond with message of 6 bytes + +/**** Begin Customize buffers ****/ +// Note: If you spell namespace 'WireBuffers' wrongly, all buffer sizes +// of the 'Wire' object stay at default (32 bytes). +namespace WireBuffers { + size_t constexpr RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. + size_t constexpr TRANSMIT_BUFFER_SIZE = sizeof(text); // Don't need a byte for the \0 + // We operate as a slave only, so we use the macro that will set master buffers to zero. + SET_BUFFERS_FOR_SLAVE_ONLY(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE); +} +/**** End Customize buffers ******/ + +// This is just for curiosity. +// Set to false if you don't want to see actual buffer sizes on serial monitor. +#define VERBOSE true + +void setup() { + Wire.begin(8); // join I2C bus with address #8 + Wire.onRequest(requestEvent); // register event +#if VERBOSE + Serial.begin(9600); // start serial for output + printWireBuffers(); +#endif +} + +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 +} + +#if VERBOSE +void printWireBuffers() { + delay(100); + Serial.println(); + Serial.print("Wire transmit buffer size is "); + Serial.println(Wire.txBufferCapacity()); + Serial.print("Wire receive buffer size is "); + Serial.println(Wire.rxBufferCapacity()); + + TwoWireBuffers::Interface& buffers = WireBuffers::instance(); + Serial.print("twi_masterBuffer size is "); + Serial.println(buffers.twi_masterBufferCapacity()); + + Serial.print("twi_rxBuffer size is "); + Serial.println(buffers.twi_rxBufferCapacity()); + + Serial.print("twi_txBuffer size is "); + Serial.println(buffers.twi_txBufferCapacity()); + delay(500); +} +#endif diff --git a/libraries/Wire/src/TwoWireBuffers.cpp b/libraries/Wire/src/TwoWireBuffers.cpp new file mode 100644 index 000000000..3c5edcb31 --- /dev/null +++ b/libraries/Wire/src/TwoWireBuffers.cpp @@ -0,0 +1,29 @@ +/* + twi.c - 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" + + +constexpr size_t RX_BUFFER_DEFAULT_LENGTH = 32; +constexpr size_t TX_BUFFER_DEFAULT_LENGTH = 32; + +// Default buffers for the one and only Wire object +namespace WireBuffers { + __attribute__((weak)) SET_BUFFERS_FOR_BOTH(RX_BUFFER_DEFAULT_LENGTH, TX_BUFFER_DEFAULT_LENGTH); +} // namespace Twi diff --git a/libraries/Wire/src/TwoWireBuffers.h b/libraries/Wire/src/TwoWireBuffers.h new file mode 100644 index 000000000..9ac0e1295 --- /dev/null +++ b/libraries/Wire/src/TwoWireBuffers.h @@ -0,0 +1,137 @@ +/* + twi.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 + + Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts +*/ + +#pragma once + +#ifndef TwiBuffers_h +#define TwiBuffers_h + +#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* twi_masterBuffer() = 0; + virtual size_t twi_masterBufferCapacity() = 0; + + virtual uint8_t* twi_rxBuffer() = 0; + virtual size_t twi_rxBufferCapacity() = 0; + + virtual uint8_t* twi_txBuffer() = 0; + virtual size_t twi_txBufferCapacity() = 0; + + virtual uint8_t* rxWireBuffer() = 0; + virtual size_t rxWireBufferCapacity() = 0; + + virtual uint8_t* txWireBuffer() = 0; + virtual size_t txWireBufferCapacity() = 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 + bool ENABLE_MASTER, // If master is disabled, it will save twi master buffer space + bool ENABLE_SLAVE // If slave is disabled, it will save twi slave buffer space + > +class Impl : public Interface { + static_assert(ENABLE_MASTER == true || ENABLE_SLAVE == true, + "You should not disable master and slave together."); + + static constexpr size_t TWI_MASTER_BUFFER_CAPACITY = + RX_CAPACITY > TX_CAPACITY ? RX_CAPACITY : TX_CAPACITY; + + // Set the twi master buffer capacity to 0, if master mode isn't needed. + TwoWireBuffers::StaticBuffer mTwiMasterBuffer; + + // Set the twi slave buffers capacity to 0, if slave mode isn't needed. + TwoWireBuffers::StaticBuffer mTwiRxBuffer; + TwoWireBuffers::StaticBuffer mTwiTxBuffer; + + // Set the capacity for a TwoWire object. + TwoWireBuffers::StaticBuffer mRxWireBuffer; + TwoWireBuffers::StaticBuffer mTxWireBuffer; + +public: + virtual uint8_t* twi_masterBuffer() override {return mTwiMasterBuffer.storage();} + virtual size_t twi_masterBufferCapacity() override {return mTwiMasterBuffer.capacity();} + + virtual uint8_t* twi_rxBuffer() override {return mTwiRxBuffer.storage();} + virtual size_t twi_rxBufferCapacity() override {return mTwiRxBuffer.capacity();} + + virtual uint8_t* twi_txBuffer() override {return mTwiTxBuffer.storage();} + virtual size_t twi_txBufferCapacity() override {return mTwiTxBuffer.capacity();} + + virtual uint8_t* rxWireBuffer() override {return mRxWireBuffer.storage();} + virtual size_t rxWireBufferCapacity() override {return mRxWireBuffer.capacity();} + + virtual uint8_t* txWireBuffer() override {return mTxWireBuffer.storage();} + virtual size_t txWireBufferCapacity() override {return mTxWireBuffer.capacity();} +}; + +} // namespace TwoWireBuffers + +namespace WireBuffers { // The buffers for the one and only Wire object + extern TwoWireBuffers::Interface& instance(); +} + +#define SET_BUFFERS_FOR_MASTER_ONLY(RX_BUFFER_CAPACITY, TX_BUFFER_CAPACITY) \ + TwoWireBuffers::Interface& instance() { \ + static TwoWireBuffers::Impl instance; \ + return instance; \ + } + +#define SET_BUFFERS_FOR_SLAVE_ONLY(RX_BUFFER_CAPACITY, TX_BUFFER_CAPACITY) \ + TwoWireBuffers::Interface& instance() { \ + static TwoWireBuffers::Impl instance; \ + return instance; \ + } + +#define SET_BUFFERS_FOR_BOTH(RX_BUFFER_CAPACITY, TX_BUFFER_CAPACITY) \ + TwoWireBuffers::Interface& instance() { \ + static TwoWireBuffers::Impl instance; \ + return instance; \ + } + +#endif /* TwiBuffers_h */ diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index ab58d8632..31242ef67 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -27,6 +27,8 @@ #include "utility/twi.h" #include "Wire.h" +#include "TwoWireBuffers.h" + // Constructors //////////////////////////////////////////////////////////////// @@ -43,6 +45,24 @@ TwoWire::TwoWire() { } +// Private Methods ///////////////////////////////////////////////////////////// + +uint8_t* TwoWire::rxBuffer() { + return WireBuffers::instance().rxWireBuffer(); +} + +size_t TwoWire::rxBufferCapacity() { + return WireBuffers::instance().rxWireBufferCapacity(); +} + +uint8_t* TwoWire::txBuffer() { + return WireBuffers::instance().txWireBuffer(); +} + +size_t TwoWire::txBufferCapacity() { + return WireBuffers::instance().txWireBufferCapacity(); +} + // Public Methods ////////////////////////////////////////////////////////////// void TwoWire::begin(void) @@ -123,29 +143,34 @@ void TwoWire::clearWireTimeoutFlag(void){ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { if (isize > 0) { - // send internal address; this mode allows sending a repeated start to access - // some devices' internal registers. This function is executed by the hardware - // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) - beginTransmission(address); + beginTransmission(address); - // the maximum size of internal address is 3 bytes - if (isize > 3){ - isize = 3; - } + // the maximum size of internal address is 3 bytes + if (isize > 3){ + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) + { + write(static_cast(iaddress >> (isize*8))); + } - // write internal register address - most significant byte first - while (isize-- > 0) - write((uint8_t)(iaddress >> (isize*8))); - endTransmission(false); + endTransmission(false); } // clamp to buffer length - if(quantity > BUFFER_LENGTH){ - quantity = BUFFER_LENGTH; + const size_t capacity = rxBufferCapacity(); + if(quantity > capacity){ + quantity = capacity; } // perform blocking read into buffer - uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop); + const uint8_t read = capacity > 0 ? + twi_readFrom(address, rxBuffer(), quantity, sendStop) : 0; // set rx buffer iterator vars rxBufferIndex = 0; rxBufferLength = read; @@ -180,7 +205,7 @@ void TwoWire::beginTransmission(uint8_t address) uint8_t TwoWire::endTransmission(uint8_t sendStop) { // transmit buffer (blocking) - uint8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop); + const uint8_t ret = twi_writeTo(txAddress, txBuffer(), txBufferLength, 1, sendStop); // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; @@ -205,12 +230,12 @@ size_t TwoWire::write(uint8_t data) if(transmitting){ // in master transmitter mode // don't bother if buffer is full - if(txBufferLength >= BUFFER_LENGTH){ + if(txBufferLength >= txBufferCapacity()){ setWriteError(); return 0; } // put byte in tx buffer - txBuffer[txBufferIndex] = data; + txBuffer()[txBufferIndex] = data; ++txBufferIndex; // update amount in buffer txBufferLength = txBufferIndex; @@ -257,7 +282,7 @@ int TwoWire::read(void) // get each successive byte on each call if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; + value = rxBuffer()[rxBufferIndex]; ++rxBufferIndex; } @@ -272,7 +297,7 @@ int TwoWire::peek(void) int value = -1; if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; + value = rxBuffer()[rxBufferIndex]; } return value; @@ -292,7 +317,7 @@ void TwoWire::onReceiveService_(uint8_t* inBytes, int numBytes) void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) { // don't bother if user hasn't registered a callback - if(!user_onReceive){ + if(user_onReceive == nullptr){ return; } // don't bother if rx buffer is in use by a master requestFrom() op @@ -303,8 +328,8 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) } // copy twi rx buffer into local read buffer // this enables new reads to happen in parallel - for(uint8_t i = 0; i < numBytes; ++i){ - rxBuffer[i] = inBytes[i]; + for(size_t i = 0; i < numBytes; ++i){ + rxBuffer()[i] = inBytes[i]; } // set rx iterator vars rxBufferIndex = 0; @@ -322,7 +347,7 @@ void TwoWire::onRequestService_() void TwoWire::onRequestService(void) { // don't bother if user hasn't registered a callback - if(!user_onRequest){ + if(user_onRequest == nullptr){ return; } // reset tx buffer iterator vars diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 3858036c9..741db315b 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -29,20 +29,21 @@ #include #include "Stream.h" -#define BUFFER_LENGTH 32 - // WIRE_HAS_END means Wire has end() #define WIRE_HAS_END 1 +// Forward declaration of Twi::IStaticBuffer +namespace TwoWireBuffers { + class IStaticBuffer; +} + class TwoWire : public Stream { private: - uint8_t rxBuffer[BUFFER_LENGTH]; uint8_t rxBufferIndex; uint8_t rxBufferLength; uint8_t txAddress; - uint8_t txBuffer[BUFFER_LENGTH]; uint8_t txBufferIndex; uint8_t txBufferLength; @@ -50,6 +51,8 @@ class TwoWire : public Stream void (*user_onRequest)(void); void (*user_onReceive)(int); + static inline uint8_t* rxBuffer(); + static inline uint8_t* txBuffer(); static void onRequestService_(void); static void onReceiveService_(uint8_t*, int); @@ -85,6 +88,7 @@ class TwoWire : public Stream return requestFrom(static_cast(address), static_cast(quantity) , static_cast(sendStop)); } + virtual size_t write(uint8_t) override; virtual size_t write(const uint8_t *, size_t) override; virtual int available(void) override; @@ -99,6 +103,9 @@ class TwoWire : public Stream 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; + + static inline size_t rxBufferCapacity(); + static inline size_t txBufferCapacity(); }; extern TwoWire Wire; diff --git a/libraries/Wire/src/utility/twi.cpp b/libraries/Wire/src/utility/twi.cpp index c9100116a..d57a38f18 100644 --- a/libraries/Wire/src/utility/twi.cpp +++ b/libraries/Wire/src/utility/twi.cpp @@ -27,6 +27,9 @@ #include #include #include + +#include "../TwoWireBuffers.h" + #include "Arduino.h" // for digitalWrite and micros #ifndef cbi @@ -44,11 +47,7 @@ #define TWI_FREQ 100000L #endif -#ifndef TWI_BUFFER_LENGTH -#define TWI_BUFFER_LENGTH 32 -#endif - -enum TWI_STATE { +enum TWI_STATE : uint8_t { TWI_READY = 0, TWI_MRX = 1, TWI_MTX = 2, @@ -56,7 +55,7 @@ enum TWI_STATE { TWI_STX = 4, }; -static volatile uint8_t twi_state; +static volatile TWI_STATE twi_state; static volatile uint8_t twi_slarw; static volatile uint8_t twi_sendStop; // should the transaction end with a stop static volatile uint8_t twi_inRepStart; // in the middle of a repeated start @@ -71,19 +70,24 @@ static volatile uint32_t twi_timeout_us = 0ul; static volatile bool twi_timed_out_flag = false; // a timeout has been seen static volatile bool twi_do_reset_on_timeout = false; // reset the TWI registers on timeout + static void (*twi_onSlaveTransmit)(void); static void (*twi_onSlaveReceive)(uint8_t*, int); -static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_masterBufferIndex; static volatile uint8_t twi_masterBufferLength; +static inline uint8_t* twi_masterBuffer() {return WireBuffers::instance().twi_masterBuffer();} +static inline size_t twi_masterBufferCapacity() {return WireBuffers::instance().twi_masterBufferCapacity();} + -static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_txBufferIndex; static volatile uint8_t twi_txBufferLength; +static inline uint8_t* twi_txBuffer() {return WireBuffers::instance().twi_txBuffer();} +static inline size_t twi_txBufferCapacity() {return WireBuffers::instance().twi_txBufferCapacity();} -static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_rxBufferIndex; +static inline uint8_t* twi_rxBuffer() {return WireBuffers::instance().twi_rxBuffer();} +static inline size_t twi_rxBufferCapacity() {return WireBuffers::instance().twi_rxBufferCapacity();} static volatile uint8_t twi_error; @@ -93,7 +97,7 @@ static volatile uint8_t twi_error; * Input none * Output none */ -void twi_init(void) +void twi_init() { // initialize state twi_state = TWI_READY; @@ -174,13 +178,12 @@ void twi_setFrequency(uint32_t frequency) */ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) { - uint8_t i; - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ + if(twi_masterBufferCapacity() < length){ return 0; } + // wait until twi is ready, become master receiver uint32_t startMicros = micros(); while(TWI_READY != twi_state){ @@ -243,10 +246,12 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen } // copy twi buffer to data - for(i = 0; i < length; ++i){ - data[i] = twi_masterBuffer[i]; + { + uint8_t* const masterBuffer = twi_masterBuffer(); + for(size_t i = 0; i < length; ++i){ + data[i] = masterBuffer[i]; + } } - return length; } @@ -268,10 +273,8 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen */ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) { - uint8_t i; - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ + if(twi_masterBufferCapacity() < length){ return 1; } @@ -293,8 +296,11 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait twi_masterBufferLength = length; // copy data to twi buffer - for(i = 0; i < length; ++i){ - twi_masterBuffer[i] = data[i]; + { + uint8_t* const masterBuffer = twi_masterBuffer(); + for(size_t i = 0; i < length; ++i){ + masterBuffer[i] = data[i]; + } } // build sla+w, slave device address + w bit @@ -357,10 +363,8 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait */ uint8_t twi_transmit(const uint8_t* data, uint8_t length) { - uint8_t i; - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < (twi_txBufferLength+length)){ + if(twi_txBufferCapacity() < (twi_txBufferLength+length)){ return 1; } @@ -370,8 +374,11 @@ uint8_t twi_transmit(const uint8_t* data, uint8_t length) } // set length and copy data into tx buffer - for(i = 0; i < length; ++i){ - twi_txBuffer[twi_txBufferLength+i] = data[i]; + { + uint8_t* const txBuffer = twi_txBuffer(); + for(size_t i = 0; i < length; ++i){ + txBuffer[twi_txBufferLength+i] = data[i]; + } } twi_txBufferLength += length; @@ -509,7 +516,7 @@ void twi_handleTimeout(bool reset){ * Output the value of twi_timed_out_flag when the function was called */ bool twi_manageTimeoutFlag(bool clear_flag){ - bool flag = twi_timed_out_flag; + const bool flag = twi_timed_out_flag; if (clear_flag){ twi_timed_out_flag = false; } @@ -533,7 +540,8 @@ ISR(TWI_vect) // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // copy data to output register and ack - TWDR = twi_masterBuffer[twi_masterBufferIndex++]; + uint8_t* const masterBuffer = twi_masterBuffer(); + TWDR = masterBuffer[twi_masterBufferIndex++]; twi_reply(1); }else{ if (twi_sendStop){ @@ -563,8 +571,11 @@ ISR(TWI_vect) // Master Receiver case TW_MR_DATA_ACK: // data received, ack sent - // put byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + { + // put byte into buffer + uint8_t* const masterBuffer = twi_masterBuffer(); + masterBuffer[twi_masterBufferIndex++] = TWDR; + } __attribute__ ((fallthrough)); case TW_MR_SLA_ACK: // address sent, ack received // ack if more bytes are expected, otherwise nack @@ -575,8 +586,10 @@ ISR(TWI_vect) } break; case TW_MR_DATA_NACK: // data received, nack sent + { // put final byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + uint8_t* const masterBuffer = twi_masterBuffer(); + masterBuffer[twi_masterBufferIndex++] = TWDR; if (twi_sendStop){ twi_stop(); } else { @@ -588,6 +601,7 @@ ISR(TWI_vect) twi_state = TWI_READY; } break; + } case TW_MR_SLA_NACK: // address sent, nack received twi_stop(); break; @@ -607,9 +621,10 @@ ISR(TWI_vect) case TW_SR_DATA_ACK: // data received, returned ack case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack // if there is still room in the rx buffer - if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + if(twi_rxBufferIndex < twi_rxBufferCapacity()){ // put byte in buffer and ack - twi_rxBuffer[twi_rxBufferIndex++] = TWDR; + uint8_t* const rxBuffer = twi_rxBuffer(); + rxBuffer[twi_rxBufferIndex++] = TWDR; twi_reply(1); }else{ // otherwise nack @@ -620,11 +635,15 @@ ISR(TWI_vect) // ack future responses and leave slave receiver state twi_releaseBus(); // put a null char after data if there's room - if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ - twi_rxBuffer[twi_rxBufferIndex] = '\0'; + if(twi_rxBufferIndex < twi_rxBufferCapacity()){ + uint8_t* const rxBuffer = twi_rxBuffer(); + rxBuffer[twi_rxBufferIndex] = '\0'; } // callback to user defined callback - twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + { + uint8_t* const rxBuffer = twi_rxBuffer(); + twi_onSlaveReceive(rxBuffer, twi_rxBufferIndex); + } // since we submit rx buffer to "wire" library, we can reset it twi_rxBufferIndex = 0; break; @@ -648,14 +667,17 @@ ISR(TWI_vect) twi_onSlaveTransmit(); // if they didn't change buffer & length, initialize it if(0 == twi_txBufferLength){ + uint8_t* const txBuffer = twi_txBuffer(); twi_txBufferLength = 1; - twi_txBuffer[0] = 0x00; + txBuffer[0] = 0x00; } __attribute__ ((fallthrough)); // transmit first byte from buffer, fall case TW_ST_DATA_ACK: // byte sent, ack returned + { // copy data to output register - TWDR = twi_txBuffer[twi_txBufferIndex++]; + uint8_t* const txBuffer = twi_txBuffer(); + TWDR = txBuffer[twi_txBufferIndex++]; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ twi_reply(1); @@ -663,6 +685,7 @@ ISR(TWI_vect) twi_reply(0); } break; + } case TW_ST_DATA_NACK: // received nack, we are done case TW_ST_LAST_DATA: // received ack, but we are done already! // ack future responses From 78a9f6052d5e8e67ed124f60f4445f6611b9f8b9 Mon Sep 17 00:00:00 2001 From: dac1e Date: Sat, 28 Dec 2024 11:06:45 +0100 Subject: [PATCH 05/12] Use TwiBuffers class for all buffers needed by Wire and twi. Allows optionally tweaking Wire buffer and twi buffer sizes at compile time. enum TWI_STATE : uint8_t becomes uint8_t. twi_state type changed form uint8_t to TWI_STATE. Added examples for customized buffers. Do println() after all received characters have been printed in master_reader.ino. Corrected setting of transmit buffer size in example sketch. Use template struct for wire WireBuffers instead of namespace. Use only a single macro SET_WIRE_BUFFERS(). --- .../examples/master_reader/master_reader.ino | 1 + .../master_reader_custombuffer.ino | 62 +++++++++ .../examples/master_writer/master_writer.ino | 2 +- .../master_writer_custombuffer.ino | 62 +++++++++ .../slave_receiver_custombuffer.ino | 63 +++++++++ .../slave_sender_custombuffer.ino | 61 ++++++++ libraries/Wire/src/TwoWireBuffers.cpp | 29 ++++ libraries/Wire/src/TwoWireBuffers.h | 130 ++++++++++++++++++ libraries/Wire/src/Wire.cpp | 73 ++++++---- libraries/Wire/src/Wire.h | 15 +- libraries/Wire/src/utility/twi.cpp | 99 ++++++++----- 11 files changed, 530 insertions(+), 67 deletions(-) create mode 100644 libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino create mode 100644 libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino create mode 100644 libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino create mode 100644 libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino create mode 100644 libraries/Wire/src/TwoWireBuffers.cpp create mode 100644 libraries/Wire/src/TwoWireBuffers.h diff --git a/libraries/Wire/examples/master_reader/master_reader.ino b/libraries/Wire/examples/master_reader/master_reader.ino index e27cac32b..214ffe996 100644 --- a/libraries/Wire/examples/master_reader/master_reader.ino +++ b/libraries/Wire/examples/master_reader/master_reader.ino @@ -24,6 +24,7 @@ void loop() { 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 000000000..bdac3693a --- /dev/null +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -0,0 +1,62 @@ +// Wire Master Reader Custom Buffer + +// Demonstrates use of the Wire library +// 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" + +// 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. + +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 can be removed + printWireBuffersCapacity(Serial); +} + +void loop() { + Wire.requestFrom(8, REQUESTED_BYTE_COUNT); + + 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); +} + +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("twi_masterBuffer size is "); + stream.println(buffers.twi_masterBufferCapacity()); + + stream.print("twi_rxBuffer size is "); + stream.println(buffers.twi_rxBufferCapacity()); + + stream.print("twi_txBuffer size is "); + stream.println(buffers.twi_txBufferCapacity()); +} diff --git a/libraries/Wire/examples/master_writer/master_writer.ino b/libraries/Wire/examples/master_writer/master_writer.ino index 7a1766874..09bf12d57 100644 --- a/libraries/Wire/examples/master_writer/master_writer.ino +++ b/libraries/Wire/examples/master_writer/master_writer.ino @@ -16,7 +16,7 @@ void setup() { Wire.begin(); // join I2C bus (address optional for master) } -byte x = 0; +static byte x = 0; void loop() { Wire.beginTransmission(8); // transmit to device #8 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 000000000..29e64a1f4 --- /dev/null +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -0,0 +1,62 @@ +// Wire Master Writer Custom Buffer + +// Demonstrates use of the Wire library +// 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" + +// 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 "; + +size_t constexpr RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +size_t constexpr TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. + +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 can 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 five 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("twi_masterBuffer size is "); + stream.println(buffers.twi_masterBufferCapacity()); + + stream.print("twi_rxBuffer size is "); + stream.println(buffers.twi_rxBufferCapacity()); + + stream.print("twi_txBuffer size is "); + stream.println(buffers.twi_txBufferCapacity()); +} 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 000000000..10d5fdec4 --- /dev/null +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -0,0 +1,63 @@ +// Wire Slave Receiver Custom Buffer + +// Demonstrates use of the Wire library +// 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" + +size_t constexpr RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. +size_t constexpr TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. + +SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no 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 can 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() +void receiveEvent(int howMany) { + while (1 < Wire.available()) { // loop through all but the last + char c = Wire.read(); // receive byte as a character + Serial.print(c); // print the character + } + 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("twi_masterBuffer size is "); + stream.println(buffers.twi_masterBufferCapacity()); + + stream.print("twi_rxBuffer size is "); + stream.println(buffers.twi_rxBufferCapacity()); + + stream.print("twi_txBuffer size is "); + stream.println(buffers.twi_txBufferCapacity()); +} 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 000000000..b8859d859 --- /dev/null +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -0,0 +1,61 @@ +// Wire Slave Sender Custom Buffer + +// Demonstrates use of the Wire library +// 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" + +static const char text[] = "hello "; // respond with message of 6 bytes + +size_t constexpr RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. +size_t constexpr TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 + +SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, + true /* master buffers needed */, false /* no 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 can 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("twi_masterBuffer size is "); + stream.println(buffers.twi_masterBufferCapacity()); + + stream.print("twi_rxBuffer size is "); + stream.println(buffers.twi_rxBufferCapacity()); + + stream.print("twi_txBuffer size is "); + stream.println(buffers.twi_txBufferCapacity()); +} diff --git a/libraries/Wire/src/TwoWireBuffers.cpp b/libraries/Wire/src/TwoWireBuffers.cpp new file mode 100644 index 000000000..0f921a244 --- /dev/null +++ b/libraries/Wire/src/TwoWireBuffers.cpp @@ -0,0 +1,29 @@ +/* + twi.c - 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" + +constexpr size_t RX_BUFFER_DEFAULT_LENGTH = 32; +constexpr size_t TX_BUFFER_DEFAULT_LENGTH = 32; + +// Default buffers for the one and only Wire object +template<> __attribute__((weak)) TwoWireBuffers::Interface& WireBuffers<0>::instance() { \ + static TwoWireBuffers::Impl buffers; \ + return buffers; \ +} diff --git a/libraries/Wire/src/TwoWireBuffers.h b/libraries/Wire/src/TwoWireBuffers.h new file mode 100644 index 000000000..8f6c9a5d2 --- /dev/null +++ b/libraries/Wire/src/TwoWireBuffers.h @@ -0,0 +1,130 @@ +/* + twi.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 + + Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts +*/ + +#pragma once + +#ifndef TwiBuffers_h +#define TwiBuffers_h + +#include +#include +#include "Wire.h" + +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* twi_masterBuffer() = 0; + virtual size_t twi_masterBufferCapacity() = 0; + + virtual uint8_t* twi_rxBuffer() = 0; + virtual size_t twi_rxBufferCapacity() = 0; + + virtual uint8_t* twi_txBuffer() = 0; + virtual size_t twi_txBufferCapacity() = 0; + + virtual uint8_t* rxWireBuffer() = 0; + virtual size_t rxWireBufferCapacity() = 0; + + virtual uint8_t* txWireBuffer() = 0; + virtual size_t txWireBufferCapacity() = 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 + bool ENABLE_MASTER, // If master is disabled, it will save twi master buffer space + bool ENABLE_SLAVE // If slave is disabled, it will save twi slave buffer space + > +class Impl : public Interface { + static_assert(ENABLE_MASTER == true || ENABLE_SLAVE == true, + "You should not disable master and slave together."); + + static constexpr size_t TWI_MASTER_BUFFER_CAPACITY = + RX_CAPACITY > TX_CAPACITY ? RX_CAPACITY : TX_CAPACITY; + + // Set the twi master buffer capacity to 0, if master mode isn't needed. + TwoWireBuffers::StaticBuffer mTwiMasterBuffer; + + // Set the twi slave buffers capacity to 0, if slave mode isn't needed. + TwoWireBuffers::StaticBuffer mTwiRxBuffer; + TwoWireBuffers::StaticBuffer mTwiTxBuffer; + + // Set the capacity for a TwoWire object. + TwoWireBuffers::StaticBuffer mRxWireBuffer; + TwoWireBuffers::StaticBuffer mTxWireBuffer; + +public: + virtual uint8_t* twi_masterBuffer() override {return mTwiMasterBuffer.storage();} + virtual size_t twi_masterBufferCapacity() override {return mTwiMasterBuffer.capacity();} + + virtual uint8_t* twi_rxBuffer() override {return mTwiRxBuffer.storage();} + virtual size_t twi_rxBufferCapacity() override {return mTwiRxBuffer.capacity();} + + virtual uint8_t* twi_txBuffer() override {return mTwiTxBuffer.storage();} + virtual size_t twi_txBufferCapacity() override {return mTwiTxBuffer.capacity();} + + virtual uint8_t* rxWireBuffer() override {return mRxWireBuffer.storage();} + virtual size_t rxWireBufferCapacity() override {return mRxWireBuffer.capacity();} + + virtual uint8_t* txWireBuffer() override {return mTxWireBuffer.storage();} + virtual size_t txWireBufferCapacity() override {return mTxWireBuffer.capacity();} +}; + +} // namespace TwoWireBuffers + +// For avr there is currently only a single Wire object that is associated with wireNum 0 +template struct WireBuffers { // The buffers for the Wire object + static TwoWireBuffers::Interface& instance(); +}; + +#define SET_WIRE_BUFFERS(rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) \ + template<> TwoWireBuffers::Interface& WireBuffers<0>::instance() { \ + static TwoWireBuffers::Impl buffers; \ + return buffers; \ + } + +#define GET_WIRE_BUFFERS() \ + WireBuffers<0>::instance(); + +#endif /* TwiBuffers_h */ diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index ab58d8632..120e32c77 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -27,6 +27,8 @@ #include "utility/twi.h" #include "Wire.h" +#include "TwoWireBuffers.h" + // Constructors //////////////////////////////////////////////////////////////// @@ -43,6 +45,24 @@ TwoWire::TwoWire() { } +// Private Methods ///////////////////////////////////////////////////////////// + +uint8_t* TwoWire::rxBuffer() { + return WireBuffers<0>::instance().rxWireBuffer(); +} + +size_t TwoWire::rxBufferCapacity() { + return WireBuffers<0>::instance().rxWireBufferCapacity(); +} + +uint8_t* TwoWire::txBuffer() { + return WireBuffers<0>::instance().txWireBuffer(); +} + +size_t TwoWire::txBufferCapacity() { + return WireBuffers<0>::instance().txWireBufferCapacity(); +} + // Public Methods ////////////////////////////////////////////////////////////// void TwoWire::begin(void) @@ -123,29 +143,34 @@ void TwoWire::clearWireTimeoutFlag(void){ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) { if (isize > 0) { - // send internal address; this mode allows sending a repeated start to access - // some devices' internal registers. This function is executed by the hardware - // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) + // send internal address; this mode allows sending a repeated start to access + // some devices' internal registers. This function is executed by the hardware + // TWI module on other processors (for example Due's TWI_IADR and TWI_MMR registers) - beginTransmission(address); + beginTransmission(address); - // the maximum size of internal address is 3 bytes - if (isize > 3){ - isize = 3; - } + // the maximum size of internal address is 3 bytes + if (isize > 3){ + isize = 3; + } + + // write internal register address - most significant byte first + while (isize-- > 0) + { + write(static_cast(iaddress >> (isize*8))); + } - // write internal register address - most significant byte first - while (isize-- > 0) - write((uint8_t)(iaddress >> (isize*8))); - endTransmission(false); + endTransmission(false); } // clamp to buffer length - if(quantity > BUFFER_LENGTH){ - quantity = BUFFER_LENGTH; + const size_t capacity = rxBufferCapacity(); + if(quantity > capacity){ + quantity = capacity; } // perform blocking read into buffer - uint8_t read = twi_readFrom(address, rxBuffer, quantity, sendStop); + const uint8_t read = capacity > 0 ? + twi_readFrom(address, rxBuffer(), quantity, sendStop) : 0; // set rx buffer iterator vars rxBufferIndex = 0; rxBufferLength = read; @@ -180,7 +205,7 @@ void TwoWire::beginTransmission(uint8_t address) uint8_t TwoWire::endTransmission(uint8_t sendStop) { // transmit buffer (blocking) - uint8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop); + const uint8_t ret = twi_writeTo(txAddress, txBuffer(), txBufferLength, 1, sendStop); // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; @@ -205,12 +230,12 @@ size_t TwoWire::write(uint8_t data) if(transmitting){ // in master transmitter mode // don't bother if buffer is full - if(txBufferLength >= BUFFER_LENGTH){ + if(txBufferLength >= txBufferCapacity()){ setWriteError(); return 0; } // put byte in tx buffer - txBuffer[txBufferIndex] = data; + txBuffer()[txBufferIndex] = data; ++txBufferIndex; // update amount in buffer txBufferLength = txBufferIndex; @@ -257,7 +282,7 @@ int TwoWire::read(void) // get each successive byte on each call if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; + value = rxBuffer()[rxBufferIndex]; ++rxBufferIndex; } @@ -272,7 +297,7 @@ int TwoWire::peek(void) int value = -1; if(rxBufferIndex < rxBufferLength){ - value = rxBuffer[rxBufferIndex]; + value = rxBuffer()[rxBufferIndex]; } return value; @@ -292,7 +317,7 @@ void TwoWire::onReceiveService_(uint8_t* inBytes, int numBytes) void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) { // don't bother if user hasn't registered a callback - if(!user_onReceive){ + if(user_onReceive == nullptr){ return; } // don't bother if rx buffer is in use by a master requestFrom() op @@ -303,8 +328,8 @@ void TwoWire::onReceiveService(uint8_t* inBytes, int numBytes) } // copy twi rx buffer into local read buffer // this enables new reads to happen in parallel - for(uint8_t i = 0; i < numBytes; ++i){ - rxBuffer[i] = inBytes[i]; + for(size_t i = 0; i < numBytes; ++i){ + rxBuffer()[i] = inBytes[i]; } // set rx iterator vars rxBufferIndex = 0; @@ -322,7 +347,7 @@ void TwoWire::onRequestService_() void TwoWire::onRequestService(void) { // don't bother if user hasn't registered a callback - if(!user_onRequest){ + if(user_onRequest == nullptr){ return; } // reset tx buffer iterator vars diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 3858036c9..741db315b 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -29,20 +29,21 @@ #include #include "Stream.h" -#define BUFFER_LENGTH 32 - // WIRE_HAS_END means Wire has end() #define WIRE_HAS_END 1 +// Forward declaration of Twi::IStaticBuffer +namespace TwoWireBuffers { + class IStaticBuffer; +} + class TwoWire : public Stream { private: - uint8_t rxBuffer[BUFFER_LENGTH]; uint8_t rxBufferIndex; uint8_t rxBufferLength; uint8_t txAddress; - uint8_t txBuffer[BUFFER_LENGTH]; uint8_t txBufferIndex; uint8_t txBufferLength; @@ -50,6 +51,8 @@ class TwoWire : public Stream void (*user_onRequest)(void); void (*user_onReceive)(int); + static inline uint8_t* rxBuffer(); + static inline uint8_t* txBuffer(); static void onRequestService_(void); static void onReceiveService_(uint8_t*, int); @@ -85,6 +88,7 @@ class TwoWire : public Stream return requestFrom(static_cast(address), static_cast(quantity) , static_cast(sendStop)); } + virtual size_t write(uint8_t) override; virtual size_t write(const uint8_t *, size_t) override; virtual int available(void) override; @@ -99,6 +103,9 @@ class TwoWire : public Stream 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; + + static inline size_t rxBufferCapacity(); + static inline size_t txBufferCapacity(); }; extern TwoWire Wire; diff --git a/libraries/Wire/src/utility/twi.cpp b/libraries/Wire/src/utility/twi.cpp index c9100116a..d6a9e518c 100644 --- a/libraries/Wire/src/utility/twi.cpp +++ b/libraries/Wire/src/utility/twi.cpp @@ -27,6 +27,9 @@ #include #include #include + +#include "../TwoWireBuffers.h" + #include "Arduino.h" // for digitalWrite and micros #ifndef cbi @@ -44,11 +47,7 @@ #define TWI_FREQ 100000L #endif -#ifndef TWI_BUFFER_LENGTH -#define TWI_BUFFER_LENGTH 32 -#endif - -enum TWI_STATE { +enum TWI_STATE : uint8_t { TWI_READY = 0, TWI_MRX = 1, TWI_MTX = 2, @@ -56,7 +55,7 @@ enum TWI_STATE { TWI_STX = 4, }; -static volatile uint8_t twi_state; +static volatile TWI_STATE twi_state; static volatile uint8_t twi_slarw; static volatile uint8_t twi_sendStop; // should the transaction end with a stop static volatile uint8_t twi_inRepStart; // in the middle of a repeated start @@ -71,19 +70,24 @@ static volatile uint32_t twi_timeout_us = 0ul; static volatile bool twi_timed_out_flag = false; // a timeout has been seen static volatile bool twi_do_reset_on_timeout = false; // reset the TWI registers on timeout + static void (*twi_onSlaveTransmit)(void); static void (*twi_onSlaveReceive)(uint8_t*, int); -static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_masterBufferIndex; static volatile uint8_t twi_masterBufferLength; +static inline uint8_t* twi_masterBuffer() {return WireBuffers<0>::instance().twi_masterBuffer();} +static inline size_t twi_masterBufferCapacity() {return WireBuffers<0>::instance().twi_masterBufferCapacity();} + -static uint8_t twi_txBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_txBufferIndex; static volatile uint8_t twi_txBufferLength; +static inline uint8_t* twi_txBuffer() {return WireBuffers<0>::instance().twi_txBuffer();} +static inline size_t twi_txBufferCapacity() {return WireBuffers<0>::instance().twi_txBufferCapacity();} -static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; static volatile uint8_t twi_rxBufferIndex; +static inline uint8_t* twi_rxBuffer() {return WireBuffers<0>::instance().twi_rxBuffer();} +static inline size_t twi_rxBufferCapacity() {return WireBuffers<0>::instance().twi_rxBufferCapacity();} static volatile uint8_t twi_error; @@ -93,7 +97,7 @@ static volatile uint8_t twi_error; * Input none * Output none */ -void twi_init(void) +void twi_init() { // initialize state twi_state = TWI_READY; @@ -174,13 +178,12 @@ void twi_setFrequency(uint32_t frequency) */ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) { - uint8_t i; - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ + if(twi_masterBufferCapacity() < length){ return 0; } + // wait until twi is ready, become master receiver uint32_t startMicros = micros(); while(TWI_READY != twi_state){ @@ -243,10 +246,12 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen } // copy twi buffer to data - for(i = 0; i < length; ++i){ - data[i] = twi_masterBuffer[i]; + { + uint8_t* const masterBuffer = twi_masterBuffer(); + for(size_t i = 0; i < length; ++i){ + data[i] = masterBuffer[i]; + } } - return length; } @@ -268,10 +273,8 @@ uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sen */ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait, uint8_t sendStop) { - uint8_t i; - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < length){ + if(twi_masterBufferCapacity() < length){ return 1; } @@ -293,8 +296,11 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait twi_masterBufferLength = length; // copy data to twi buffer - for(i = 0; i < length; ++i){ - twi_masterBuffer[i] = data[i]; + { + uint8_t* const masterBuffer = twi_masterBuffer(); + for(size_t i = 0; i < length; ++i){ + masterBuffer[i] = data[i]; + } } // build sla+w, slave device address + w bit @@ -357,10 +363,8 @@ uint8_t twi_writeTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t wait */ uint8_t twi_transmit(const uint8_t* data, uint8_t length) { - uint8_t i; - // ensure data will fit into buffer - if(TWI_BUFFER_LENGTH < (twi_txBufferLength+length)){ + if(twi_txBufferCapacity() < (twi_txBufferLength+length)){ return 1; } @@ -370,8 +374,11 @@ uint8_t twi_transmit(const uint8_t* data, uint8_t length) } // set length and copy data into tx buffer - for(i = 0; i < length; ++i){ - twi_txBuffer[twi_txBufferLength+i] = data[i]; + { + uint8_t* const txBuffer = twi_txBuffer(); + for(size_t i = 0; i < length; ++i){ + txBuffer[twi_txBufferLength+i] = data[i]; + } } twi_txBufferLength += length; @@ -509,7 +516,7 @@ void twi_handleTimeout(bool reset){ * Output the value of twi_timed_out_flag when the function was called */ bool twi_manageTimeoutFlag(bool clear_flag){ - bool flag = twi_timed_out_flag; + const bool flag = twi_timed_out_flag; if (clear_flag){ twi_timed_out_flag = false; } @@ -533,7 +540,8 @@ ISR(TWI_vect) // if there is data to send, send it, otherwise stop if(twi_masterBufferIndex < twi_masterBufferLength){ // copy data to output register and ack - TWDR = twi_masterBuffer[twi_masterBufferIndex++]; + uint8_t* const masterBuffer = twi_masterBuffer(); + TWDR = masterBuffer[twi_masterBufferIndex++]; twi_reply(1); }else{ if (twi_sendStop){ @@ -563,8 +571,11 @@ ISR(TWI_vect) // Master Receiver case TW_MR_DATA_ACK: // data received, ack sent - // put byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + { + // put byte into buffer + uint8_t* const masterBuffer = twi_masterBuffer(); + masterBuffer[twi_masterBufferIndex++] = TWDR; + } __attribute__ ((fallthrough)); case TW_MR_SLA_ACK: // address sent, ack received // ack if more bytes are expected, otherwise nack @@ -575,8 +586,10 @@ ISR(TWI_vect) } break; case TW_MR_DATA_NACK: // data received, nack sent + { // put final byte into buffer - twi_masterBuffer[twi_masterBufferIndex++] = TWDR; + uint8_t* const masterBuffer = twi_masterBuffer(); + masterBuffer[twi_masterBufferIndex++] = TWDR; if (twi_sendStop){ twi_stop(); } else { @@ -588,6 +601,7 @@ ISR(TWI_vect) twi_state = TWI_READY; } break; + } case TW_MR_SLA_NACK: // address sent, nack received twi_stop(); break; @@ -607,9 +621,10 @@ ISR(TWI_vect) case TW_SR_DATA_ACK: // data received, returned ack case TW_SR_GCALL_DATA_ACK: // data received generally, returned ack // if there is still room in the rx buffer - if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ + if(twi_rxBufferIndex < twi_rxBufferCapacity()){ // put byte in buffer and ack - twi_rxBuffer[twi_rxBufferIndex++] = TWDR; + uint8_t* const rxBuffer = twi_rxBuffer(); + rxBuffer[twi_rxBufferIndex++] = TWDR; twi_reply(1); }else{ // otherwise nack @@ -620,11 +635,15 @@ ISR(TWI_vect) // ack future responses and leave slave receiver state twi_releaseBus(); // put a null char after data if there's room - if(twi_rxBufferIndex < TWI_BUFFER_LENGTH){ - twi_rxBuffer[twi_rxBufferIndex] = '\0'; + if(twi_rxBufferIndex < twi_rxBufferCapacity()){ + uint8_t* const rxBuffer = twi_rxBuffer(); + rxBuffer[twi_rxBufferIndex] = '\0'; } // callback to user defined callback - twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + { + uint8_t* const rxBuffer = twi_rxBuffer(); + twi_onSlaveReceive(rxBuffer, twi_rxBufferIndex); + } // since we submit rx buffer to "wire" library, we can reset it twi_rxBufferIndex = 0; break; @@ -648,14 +667,17 @@ ISR(TWI_vect) twi_onSlaveTransmit(); // if they didn't change buffer & length, initialize it if(0 == twi_txBufferLength){ + uint8_t* const txBuffer = twi_txBuffer(); twi_txBufferLength = 1; - twi_txBuffer[0] = 0x00; + txBuffer[0] = 0x00; } __attribute__ ((fallthrough)); // transmit first byte from buffer, fall case TW_ST_DATA_ACK: // byte sent, ack returned + { // copy data to output register - TWDR = twi_txBuffer[twi_txBufferIndex++]; + uint8_t* const txBuffer = twi_txBuffer(); + TWDR = txBuffer[twi_txBufferIndex++]; // if there is more to send, ack, otherwise nack if(twi_txBufferIndex < twi_txBufferLength){ twi_reply(1); @@ -663,6 +685,7 @@ ISR(TWI_vect) twi_reply(0); } break; + } case TW_ST_DATA_NACK: // received nack, we are done case TW_ST_LAST_DATA: // received ack, but we are done already! // ack future responses From 258e7dbcfe47afbdc42edd0afc72d3e7ba4b8954 Mon Sep 17 00:00:00 2001 From: dac1e Date: Wed, 1 Jan 2025 18:38:28 +0100 Subject: [PATCH 06/12] Fixed comment. Moved constexpr. --- .../master_writer_custombuffer.ino | 8 ++++---- .../slave_receiver_custombuffer.ino | 8 ++++---- .../slave_sender_custombuffer.ino | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino index 29e64a1f4..014aa9f27 100644 --- a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -16,8 +16,8 @@ // 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 "; -size_t constexpr RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. -size_t constexpr TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters. +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. SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, true /* master buffers needed */, false /* no slave buffers needed */ ); @@ -34,8 +34,8 @@ static byte x = 0; void loop() { Wire.beginTransmission(8); // transmit to device #8 - Wire.write(text); // sends five bytes - Wire.write(x); // sends one byte + Wire.write(text); // sends multiple bytes + Wire.write(x); // sends one byte Wire.endTransmission(); // stop transmitting x++; diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino index 10d5fdec4..0eb9c838b 100644 --- a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -13,8 +13,8 @@ #include #include "Arduino.h" -size_t constexpr RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message. -size_t constexpr TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. +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. SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, true /* master buffers needed */, false /* no slave buffers needed */ ); @@ -36,10 +36,10 @@ void loop() { // this function is registered as an event, see setup() void receiveEvent(int howMany) { while (1 < Wire.available()) { // loop through all but the last - char c = Wire.read(); // receive byte as a character + const char c = Wire.read(); // receive byte as a character Serial.print(c); // print the character } - int x = Wire.read(); // receive byte as an integer + const int x = Wire.read(); // receive byte as an integer Serial.println(x); // print the integer } diff --git a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino index b8859d859..08a4f254a 100644 --- a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -15,8 +15,8 @@ static const char text[] = "hello "; // respond with message of 6 bytes -size_t constexpr RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch. -size_t constexpr TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0 +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 SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, true /* master buffers needed */, false /* no slave buffers needed */ ); From 3d3019469cd70db9becdfc49731ff298202449fb Mon Sep 17 00:00:00 2001 From: dac1e Date: Wed, 1 Jan 2025 18:48:55 +0100 Subject: [PATCH 07/12] Fixed wrong master slave buffer configuration in examples. --- .../master_reader_custombuffer/master_reader_custombuffer.ino | 2 +- .../master_writer_custombuffer/master_writer_custombuffer.ino | 2 +- .../slave_receiver_custombuffer.ino | 4 ++-- .../slave_sender_custombuffer/slave_sender_custombuffer.ino | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino index bdac3693a..a1697fabf 100644 --- a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -26,7 +26,7 @@ void setup() { Wire.begin(); // join I2C bus (address optional for master) Serial.begin(9600); // start serial for output - // This is just for curiosity and can be removed + // This is just for curiosity and could be removed printWireBuffersCapacity(Serial); } diff --git a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino index 014aa9f27..ed37b0d81 100644 --- a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -25,7 +25,7 @@ SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, void setup() { Wire.begin(); // join I2C bus (address optional for master) - // This is just for curiosity and can be removed + // This is just for curiosity and could be removed Serial.begin(9600); // start serial for output printWireBuffersCapacity(Serial); } diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino index 0eb9c838b..8ac951610 100644 --- a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -17,14 +17,14 @@ constexpr size_t RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characte constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch. SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, - true /* master buffers needed */, false /* no slave buffers needed */ ); + 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 can be removed + // This is just for curiosity and could be removed printWireBuffersCapacity(Serial); } diff --git a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino index 08a4f254a..3e26b675f 100644 --- a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -19,13 +19,13 @@ 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 SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, - true /* master buffers needed */, false /* no slave buffers needed */ ); + 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 can be removed + // This is just for curiosity and could be removed Serial.begin(9600); printWireBuffersCapacity(Serial); } From 3d818b794a6e2ad505c325a4532ecccc6d56c56f Mon Sep 17 00:00:00 2001 From: dac1e Date: Thu, 2 Jan 2025 09:31:58 +0100 Subject: [PATCH 08/12] Enhanced comments in expample sketches. --- .../master_reader_custombuffer/master_reader_custombuffer.ino | 2 +- .../master_writer_custombuffer/master_writer_custombuffer.ino | 2 +- .../slave_receiver_custombuffer/slave_receiver_custombuffer.ino | 2 +- .../slave_sender_custombuffer/slave_sender_custombuffer.ino | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino index a1697fabf..d82f56f29 100644 --- a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -1,6 +1,6 @@ // Wire Master Reader Custom Buffer -// Demonstrates use of the Wire library +// 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 diff --git a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino index ed37b0d81..bab4d0305 100644 --- a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -1,6 +1,6 @@ // Wire Master Writer Custom Buffer -// Demonstrates use of the Wire library +// 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 diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino index 8ac951610..37acc4e6e 100644 --- a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -1,6 +1,6 @@ // Wire Slave Receiver Custom Buffer -// Demonstrates use of the Wire library +// 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 diff --git a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino index 3e26b675f..a22105dd6 100644 --- a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -1,6 +1,6 @@ // Wire Slave Sender Custom Buffer -// Demonstrates use of the Wire library +// 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 From 69a3d4c8b5ed73602b69a05c3db73b0e2dfd62f5 Mon Sep 17 00:00:00 2001 From: dac1e Date: Thu, 2 Jan 2025 10:35:51 +0100 Subject: [PATCH 09/12] Added hint about receiveEvent interrupt context. --- .../master_reader_custombuffer.ino | 2 +- .../slave_receiver_custombuffer.ino | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino index d82f56f29..b922b40af 100644 --- a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -34,7 +34,7 @@ void loop() { Wire.requestFrom(8, REQUESTED_BYTE_COUNT); while (Wire.available()) { // slave may send less than requested - char c = Wire.read(); // receive a byte as character + char c = Wire.read(); // receive a byte as character Serial.print(c); // print the character } Serial.println(); diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino index 37acc4e6e..8136dbcbc 100644 --- a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -34,12 +34,17 @@ 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 - const char c = Wire.read(); // receive byte as a character - Serial.print(c); // print the character + 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 + const int x = Wire.read(); // receive byte as an integer Serial.println(x); // print the integer } @@ -60,4 +65,5 @@ void printWireBuffersCapacity(Stream& stream) { stream.print("twi_txBuffer size is "); stream.println(buffers.twi_txBufferCapacity()); + delay(250); // Give time to free up Serial output buffer. } From 7fe8e74a2caf5091c34a254200caa231c10ba1a4 Mon Sep 17 00:00:00 2001 From: dac1e Date: Thu, 2 Jan 2025 11:25:05 +0100 Subject: [PATCH 10/12] Fixed wrong comments. --- libraries/Wire/src/TwoWireBuffers.h | 4 +--- libraries/Wire/src/Wire.h | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/Wire/src/TwoWireBuffers.h b/libraries/Wire/src/TwoWireBuffers.h index 8f6c9a5d2..f856a4575 100644 --- a/libraries/Wire/src/TwoWireBuffers.h +++ b/libraries/Wire/src/TwoWireBuffers.h @@ -15,8 +15,6 @@ 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 - - Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts */ #pragma once @@ -30,7 +28,7 @@ namespace TwoWireBuffers { -/* Template class that implements an compile time fixed size array. */ +/* Template class that implements a compile time fixed size array. */ template class StaticBuffer { uint8_t mByteArray[CAPACITY]; diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 741db315b..771e133ae 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -20,7 +20,6 @@ Modified 2020 by Greyson Christoforo (grey@christoforo.net) to implement timeouts */ - #pragma once #ifndef TwoWire_h @@ -88,7 +87,6 @@ class TwoWire : public Stream return requestFrom(static_cast(address), static_cast(quantity) , static_cast(sendStop)); } - virtual size_t write(uint8_t) override; virtual size_t write(const uint8_t *, size_t) override; virtual int available(void) override; From f282f1b945067a4541d8314163ef56eac9e8587b Mon Sep 17 00:00:00 2001 From: dac1e Date: Thu, 2 Jan 2025 14:07:58 +0100 Subject: [PATCH 11/12] Changed SET_WIRE_BUFFERS and GET_WIRE_BUFFERS tpo SET_Wire_BUFFERS respectively GET_Wire_BUFFERS. --- .../master_reader_custombuffer/master_reader_custombuffer.ino | 4 ++-- .../master_writer_custombuffer/master_writer_custombuffer.ino | 4 ++-- .../slave_receiver_custombuffer.ino | 4 ++-- .../slave_sender_custombuffer/slave_sender_custombuffer.ino | 4 ++-- libraries/Wire/src/TwoWireBuffers.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino index b922b40af..cf71e52e0 100644 --- a/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino +++ b/libraries/Wire/examples/master_reader_custombuffer/master_reader_custombuffer.ino @@ -19,7 +19,7 @@ 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. -SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, true /* master buffers needed */, false /* no slave buffers needed */ ); void setup() { @@ -43,7 +43,7 @@ void loop() { } void printWireBuffersCapacity(Stream& stream) { - const auto& buffers = GET_WIRE_BUFFERS(); + const auto& buffers = GET_Wire_BUFFERS(); stream.print("Wire transmit buffer size is "); stream.println(buffers.txWireBufferCapacity()); diff --git a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino index bab4d0305..67126fb72 100644 --- a/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino +++ b/libraries/Wire/examples/master_writer_custombuffer/master_writer_custombuffer.ino @@ -19,7 +19,7 @@ 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. -SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, true /* master buffers needed */, false /* no slave buffers needed */ ); void setup() { @@ -43,7 +43,7 @@ void loop() { } void printWireBuffersCapacity(Stream& stream) { - const auto& buffers = GET_WIRE_BUFFERS(); + const auto& buffers = GET_Wire_BUFFERS(); stream.print("Wire transmit buffer size is "); stream.println(buffers.txWireBufferCapacity()); diff --git a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino index 8136dbcbc..8e0421a63 100644 --- a/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino +++ b/libraries/Wire/examples/slave_receiver_custombuffer/slave_receiver_custombuffer.ino @@ -16,7 +16,7 @@ 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. -SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, false /* no master buffers needed */, true /* slave buffers needed */ ); void setup() { @@ -49,7 +49,7 @@ void receiveEvent(int howMany) { } void printWireBuffersCapacity(Stream& stream) { - const auto& buffers = GET_WIRE_BUFFERS(); + const auto& buffers = GET_Wire_BUFFERS(); stream.print("Wire transmit buffer size is "); stream.println(buffers.txWireBufferCapacity()); diff --git a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino index a22105dd6..6da7ce083 100644 --- a/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino +++ b/libraries/Wire/examples/slave_sender_custombuffer/slave_sender_custombuffer.ino @@ -18,7 +18,7 @@ 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 -SET_WIRE_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, +SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE, false /* no master buffers needed */, true /* slave buffers needed */ ); void setup() { @@ -42,7 +42,7 @@ void requestEvent() { } void printWireBuffersCapacity(Stream& stream) { - const auto& buffers = GET_WIRE_BUFFERS(); + const auto& buffers = GET_Wire_BUFFERS(); stream.print("Wire transmit buffer size is "); stream.println(buffers.txWireBufferCapacity()); diff --git a/libraries/Wire/src/TwoWireBuffers.h b/libraries/Wire/src/TwoWireBuffers.h index f856a4575..e986a6a0d 100644 --- a/libraries/Wire/src/TwoWireBuffers.h +++ b/libraries/Wire/src/TwoWireBuffers.h @@ -116,13 +116,13 @@ template struct WireBuffers { // The buffers for the Wire object static TwoWireBuffers::Interface& instance(); }; -#define SET_WIRE_BUFFERS(rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) \ +#define SET_Wire_BUFFERS(rxBufferCapacity, txBufferCapacity, enableMaster, enableSlave) \ template<> TwoWireBuffers::Interface& WireBuffers<0>::instance() { \ static TwoWireBuffers::Impl buffers; \ return buffers; \ } -#define GET_WIRE_BUFFERS() \ +#define GET_Wire_BUFFERS() \ WireBuffers<0>::instance(); #endif /* TwiBuffers_h */ From bfde36ff8bf5671393f5a603624ffb150dfc5fa0 Mon Sep 17 00:00:00 2001 From: dac1e Date: Thu, 2 Jan 2025 14:19:52 +0100 Subject: [PATCH 12/12] Fixed comment lines. --- libraries/Wire/src/TwoWireBuffers.cpp | 2 +- libraries/Wire/src/TwoWireBuffers.h | 2 +- libraries/Wire/src/Wire.cpp | 2 +- libraries/Wire/src/Wire.h | 2 +- libraries/Wire/src/utility/twi.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/Wire/src/TwoWireBuffers.cpp b/libraries/Wire/src/TwoWireBuffers.cpp index 0f921a244..076513f90 100644 --- a/libraries/Wire/src/TwoWireBuffers.cpp +++ b/libraries/Wire/src/TwoWireBuffers.cpp @@ -1,5 +1,5 @@ /* - twi.c - TWI/I2C library for Wiring & Arduino + 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 diff --git a/libraries/Wire/src/TwoWireBuffers.h b/libraries/Wire/src/TwoWireBuffers.h index e986a6a0d..15162cca6 100644 --- a/libraries/Wire/src/TwoWireBuffers.h +++ b/libraries/Wire/src/TwoWireBuffers.h @@ -1,5 +1,5 @@ /* - twi.h - TWI/I2C library for Wiring & Arduino + 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 diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index 120e32c77..b41ab5184 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -1,5 +1,5 @@ /* - TwoWire.cpp - TWI/I2C library for Wiring & Arduino + Wire.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 diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index 771e133ae..41e2a7009 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -1,5 +1,5 @@ /* - TwoWire.h - TWI/I2C library for Arduino & Wiring + Wire.h - TWI/I2C library for Arduino & Wiring Copyright (c) 2006 Nicholas Zambetti. All right reserved. This library is free software; you can redistribute it and/or diff --git a/libraries/Wire/src/utility/twi.cpp b/libraries/Wire/src/utility/twi.cpp index d6a9e518c..43a403636 100644 --- a/libraries/Wire/src/utility/twi.cpp +++ b/libraries/Wire/src/utility/twi.cpp @@ -1,5 +1,5 @@ /* - twi.c - TWI/I2C library for Wiring & Arduino + twi.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