Skip to content

Allow customization of transmit and receive buffer sizes for I2C 'Wire' and 'Wire1' objects. #149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Wire Master Reader Custom Buffer

// Demonstrates use of the Wire library with customized buffers
// Reads data from an I2C/TWI slave device
// Refer to the "Wire Slave Sender Custom Buffer" example for use with this

// Created 31 Dec 2024

// This example code is in the public domain.


#include <Wire.h>
#include <WireBuffer.h>
#include "Arduino.h"

#define USE_WIRE1 false // Set to true for using Wire1

// request 6 bytes from slave device #8
constexpr size_t REQUESTED_BYTE_COUNT = 6;

constexpr size_t RECEIVE_BUFFER_SIZE = REQUESTED_BYTE_COUNT;
constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch.

#if not USE_WIRE1

SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
true /* master buffers needed */, false /* no slave buffers needed */ );

void setup() {
Wire.begin(); // join I2C bus (address optional for master)
Serial.begin(9600); // start serial for output

// This is just for curiosity and could be removed
printWireBufferSize(Serial);
}

void loop() {
Wire.requestFrom(8, REQUESTED_BYTE_COUNT);

while (Wire.available()) { // slave may send less than requested
const char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}
Serial.println();

delay(500);
}

void printWireBufferSize(Stream& stream) {
using namespace WireBuffer;
stream.print("Wire receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

#else

SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
true /* master buffers needed */, false /* no slave buffers needed */ );

void setup() {
Wire1.begin(); // join I2C bus (address optional for master)
Serial.begin(9600); // start serial for output

// This is just for curiosity and could be removed
printWire1BufferSize(Serial);
}

void loop() {
Wire1.requestFrom(8, REQUESTED_BYTE_COUNT);

while (Wire1.available()) { // slave may send less than requested
const char c = Wire1.read(); // receive a byte as character
Serial.print(c); // print the character
}
Serial.println();

delay(500);
}

void printWire1BufferSize(Stream& stream) {
using namespace Wire1Buffer;
stream.print("Wire1 receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire1 transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire1 service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Wire Master Writer Custom Buffer

// Demonstrates use of the Wire library with customized buffers
// Writes data to an I2C/TWI slave device
// Refer to the "Wire Slave Receiver Custom Buffer" example for use with this

// Created 31 Dec 2024

// This example code is in the public domain.


#include <Wire.h>
#include <WireBuffer.h>
#include "Arduino.h"

#define USE_WIRE1 false // Set to true for using Wire1

// The following text will not fit into the default buffer of 32 bytes.
static const char text[] = "You really won't believe it, but x is ";

constexpr size_t RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch.
constexpr size_t TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters.

#if not USE_WIRE1

SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
true /* master buffers needed */, false /* no slave buffers needed */ );

void setup() {
Wire.begin(); // join I2C bus (address optional for master)

// This is just for curiosity and could be removed
Serial.begin(9600); // start serial for output
printWireBufferSize(Serial);
}

static byte x = 0;

void loop() {
Wire.beginTransmission(8); // transmit to device #8
Wire.write(text); // sends multiple bytes
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting

x++;
delay(500);
}

void printWireBufferSize(Stream& stream) {
using namespace WireBuffer;
stream.print("Wire receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

#else

SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
true /* master buffers needed */, false /* no slave buffers needed */ );

void setup() {
Wire1.begin(); // join I2C bus (address optional for master)

// This is just for curiosity and could be removed
Serial.begin(9600); // start serial for output
printWire1BufferSize(Serial);
}

static byte x = 0;

void loop() {
Wire1.beginTransmission(8); // transmit to device #8
Wire1.write(text); // sends multiple bytes
Wire1.write(x); // sends one byte
Wire1.endTransmission(); // stop transmitting

x++;
delay(500);
}

void printWire1BufferSize(Stream& stream) {
using namespace Wire1Buffer;
stream.print("Wire1 receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire1 transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire1 service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Wire1 connnected to Wire. (scl <-> scl1, sda <-> sda1)

// Demonstrates use of the Wire library on a single Arduino board
// with 2 Wire interfaces (like Arduino Due).
// Uses the option of customizing the buffers.
//
// Wire data to an I2C/TWI slave device
// Wire1 receives data as an I2C/TWI slave device

// Created 02 Jan 2025

// This example code is in the public domain.


#include <Wire.h>
#include <WireBuffer.h>
#include "Arduino.h"

static_assert(WIRE_INTERFACES_COUNT > 1, "You need two I2C interfaces on the Arduino board to run this sketch");

static const char text[] = "You really won't believe it, but x is ";

// Wire is the master writer
constexpr size_t M_RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch.
constexpr size_t M_TRANSMIT_BUFFER_SIZE = 42; // Enhance the buffer to 42 characters.
SET_Wire_BUFFERS(M_RECEIVE_BUFFER_SIZE, M_TRANSMIT_BUFFER_SIZE,
true /* master buffers needed */, false /* no slave buffers needed */ );

// Wire1 is the slave receiver
constexpr size_t S_RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message.
constexpr size_t S_TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch.
SET_Wire1_BUFFERS(S_RECEIVE_BUFFER_SIZE, S_TRANSMIT_BUFFER_SIZE,
false /* no master buffers needed */, true /* slave buffers needed */ );

void setup() {
Serial.begin(9600); // start serial for output
Wire.begin(); // master joins I2C bus (address optional for master)
Wire1.begin(8); // slave joins I2C bus with address #8
Wire1.onReceive(receiveEvent); // register event

// This is just for curiosity and could be removed
printWireBufferSize(Serial);
printWire1BufferSize(Serial);
}

static byte x = 0;

void loop() {
Wire.beginTransmission(8); // transmit to device #8
Wire.write(text); // sends multiple bytes
Wire.write(x); // sends one byte
Wire.endTransmission(); // stop transmitting

x++;
delay(500);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
//
// Hint: This function is called within an interrupt context.
// That means, that there must be enough space in the Serial output
// buffer for the characters to be printed. Otherwise the
// Serial.print() call will lock up.
void receiveEvent(int howMany) {
while (1 < Wire1.available()) { // loop through all but the last
const char c = Wire1.read(); // receive byte as a character
Serial.print(c); // print the character
}
const int x = Wire1.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

void printWireBufferSize(Stream& stream) {
using namespace WireBuffer;
stream.print("Wire receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
delay(250); // Give time to free up Serial output buffer.
}

void printWire1BufferSize(Stream& stream) {
using namespace Wire1Buffer;
stream.print("Wire1 receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire1 transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire1 service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
delay(250); // Give time to free up Serial output buffer.
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// Wire Slave Receiver Custom Buffer

// Demonstrates use of the Wire library with customized buffers
// Receives data as an I2C/TWI slave device
// Refer to the "Wire Master Writer Custom Buffer" example for use with this

// Created 31 Dec 2024

// This example code is in the public domain.


#include <Wire.h>
#include <WireBuffer.h>
#include "Arduino.h"

#define USE_WIRE1 false // Set to true for using Wire1

constexpr size_t RECEIVE_BUFFER_SIZE = 42; // Be able receive up to 42 characters in one message.
constexpr size_t TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch.

#if not USE_WIRE1

SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
false /* no master buffers needed */, true /* slave buffers needed */ );

void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output

// This is just for curiosity and could be removed
printWireBufferSize(Serial);
}

void loop() {
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
//
// Hint: This function is called within an interrupt context.
// That means, that there must be enough space in the Serial output
// buffer for the characters to be printed. Otherwise the
// Serial.print() call will lock up.
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
const char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
const int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

void printWireBufferSize(Stream& stream) {
using namespace WireBuffer;
stream.print("Wire receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
delay(250); // Give time to free up Serial output buffer.
}

#else

SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
false /* no master buffers needed */, true /* slave buffers needed */ );

void setup() {
Wire1.begin(8); // join I2C bus with address #8
Wire1.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output

// This is just for curiosity and could be removed
printWire1BufferSize(Serial);
}

void loop() {
delay(100);
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
//
// Hint: This function is called within an interrupt context.
// That means, that there must be enough space in the Serial output
// buffer for the characters to be printed. Otherwise the
// Serial.print() call will lock up.
void receiveEvent(int howMany) {
while (1 < Wire1.available()) { // loop through all but the last
const char c = Wire1.read(); // receive byte as a character
Serial.print(c); // print the character
}
const int x = Wire1.read(); // receive byte as an integer
Serial.println(x); // print the integer
}

void printWire1BufferSize(Stream& stream) {
using namespace Wire1Buffer;
stream.print("Wire1 receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire1 transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire1 service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
delay(250); // Give time to free up Serial output buffer.
}

#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Wire1 connnected to Wire. (scl <-> scl1, sda <-> sda1)

// Demonstrates use of the Wire library on a single Arduino board
// with 2 Wire interfaces (like Arduino Due).
// Uses the option of customizing the buffers.
//
// Wire reads data from an I2C/TWI slave device
// Wire1 sends data as an I2C/TWI slave device

// Created 02 Jan 2025

// This example code is in the public domain.


#include <Wire.h>
#include <WireBuffer.h>
#include "Arduino.h"

static_assert(WIRE_INTERFACES_COUNT > 1, "You need two I2C interfaces on the Arduino board to run this sketch");

static const char text[] = "hello "; // respond with message of 6 bytes

// Wire is the master reader
constexpr size_t M_RECEIVE_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0
constexpr size_t M_TRANSMIT_BUFFER_SIZE = 0; // There is no transmit in this sketch.
SET_Wire_BUFFERS(M_RECEIVE_BUFFER_SIZE, M_TRANSMIT_BUFFER_SIZE,
true /* master buffers needed */, false /* no slave buffers needed */ );

// Wire1 is the slave sender
constexpr size_t S_RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch.
constexpr size_t S_TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0
SET_Wire1_BUFFERS(S_RECEIVE_BUFFER_SIZE, S_TRANSMIT_BUFFER_SIZE,
false /* no master buffers needed */, true /* slave buffers needed */ );

void setup() {
Serial.begin(9600); // start serial for output
Wire.begin(); // master joins I2C bus (address optional for master)
Wire1.begin(8); // slave joins I2C bus with address #8
Wire1.onRequest(requestEvent); // register slave event

// This is just for curiosity and could be removed
printWireBufferSize(Serial);
printWire1BufferSize(Serial);
}

void loop() {
Wire.requestFrom(8, M_RECEIVE_BUFFER_SIZE);

while (Wire.available()) {
const char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}
Serial.println();

delay(500);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Wire1.write(text);
// as expected by master
}

void printWireBufferSize(Stream& stream) {
using namespace WireBuffer;
stream.print("Wire receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

void printWire1BufferSize(Stream& stream) {
using namespace Wire1Buffer;
stream.print("Wire1 receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire1 transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire1 service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Wire Slave Sender Custom Buffer

// Demonstrates use of the Wire library with customized buffers
// Sends data as an I2C/TWI slave device
// Refer to the "Wire Master Reader Custom Buffer" example for use with this

// Created 31 Dec 2024

// This example code is in the public domain.


#include <Wire.h>
#include <WireBuffer.h>
#include "Arduino.h"

#define USE_WIRE1 false // Set to true for using Wire1

static const char text[] = "hello "; // respond with message of 6 bytes

constexpr size_t RECEIVE_BUFFER_SIZE = 0; // There is no receive in this sketch.
constexpr size_t TRANSMIT_BUFFER_SIZE = sizeof(text)-1; // Don't need a byte for the \0

#if not USE_WIRE1

SET_Wire_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
false /* no master buffers needed */, true /* slave buffers needed */ );

void setup() {
Wire.begin(8); // join I2C bus with address #8
Wire.onRequest(requestEvent); // register event

// This is just for curiosity and could be removed
Serial.begin(9600);
printWireBufferSize(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 printWireBufferSize(Stream& stream) {
using namespace WireBuffer;
stream.print("Wire receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

#else

SET_Wire1_BUFFERS(RECEIVE_BUFFER_SIZE, TRANSMIT_BUFFER_SIZE,
false /* no master buffers needed */, true /* slave buffers needed */ );

void setup() {
Wire1.begin(8); // join I2C bus with address #8
Wire1.onRequest(requestEvent); // register event

// This is just for curiosity and could be removed
Serial.begin(9600);
printWire1BufferSize(Serial);
}

void loop() {
delay(100);
}

// function that executes whenever data is requested by master
// this function is registered as an event, see setup()
void requestEvent() {
Wire1.write(text);
// as expected by master
}

void printWire1BufferSize(Stream& stream) {
using namespace Wire1Buffer;
stream.print("Wire1 receive buffer size is ");
stream.println(buffers.RX_BUFFER_SIZE);
stream.print("Wire1 transmit buffer size is ");
stream.println(buffers.TX_BUFFER_SIZE);
stream.print("Wire1 service buffer size is ");
stream.println(buffers.SRV_BUFFER_SIZE);
}

#endif
90 changes: 42 additions & 48 deletions libraries/Wire/src/Wire.cpp
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ extern "C" {
#include <string.h>
}

#include "WireBuffer.h"
#include "Wire.h"

static inline bool TWI_FailedAcknowledge(Twi *pTwi) {
@@ -96,11 +97,24 @@ static inline bool TWI_STATUS_NACK(uint32_t status) {
return (status & TWI_SR_NACK) == TWI_SR_NACK;
}

TwoWire::TwoWire(Twi *_twi, void(*_beginCb)(void), void(*_endCb)(void)) :
uint8_t* TwoWire:: srvBuffer()const {
return buffers.srvBuffer;
}

uint8_t* TwoWire:: rxBuffer()const {
return buffers.rxBuffer;
}

uint8_t* TwoWire:: txBuffer()const {
return buffers.txBuffer;
}

TwoWire::TwoWire(const TwoWireBuffer::Buffers& _buffers,
Twi *_twi, void(*_beginCb)(void), void(*_endCb)(void)) : buffers(_buffers),
twi(_twi), rxBufferIndex(0), rxBufferLength(0), txAddress(0),
txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status(
UNINITIALIZED), onBeginCallback(_beginCb),
onEndCallback(_endCb), twiClock(TWI_CLOCK) {
txBufferLength(0), srvBufferIndex(0), srvBufferLength(0), status(UNINITIALIZED),
onBeginCallback(_beginCb), onEndCallback(_endCb), twiClock(TWI_CLOCK),
onReceiveCallback(nullptr), onRequestCallback(nullptr) {
}

void TwoWire::begin(void) {
@@ -128,7 +142,7 @@ void TwoWire::begin(uint8_t address) {
}

void TwoWire::begin(int address) {
begin((uint8_t) address);
begin(static_cast<uint8_t>(address));
}

void TwoWire::end(void) {
@@ -147,8 +161,8 @@ void TwoWire::setClock(uint32_t frequency) {
}

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddress, uint8_t isize, uint8_t sendStop) {
if (quantity > BUFFER_LENGTH)
quantity = BUFFER_LENGTH;
if (quantity > buffers.RX_BUFFER_SIZE)
quantity = buffers.RX_BUFFER_SIZE;

// perform blocking read into buffer
int readed = 0;
@@ -159,7 +173,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
TWI_SendSTOPCondition( twi);

if (TWI_WaitByteReceived(twi, RECV_TIMEOUT))
rxBuffer[readed++] = TWI_ReadByte(twi);
rxBuffer()[readed++] = TWI_ReadByte(twi);
else
break;
} while (readed < quantity);
@@ -172,22 +186,6 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres
return readed;
}

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint32_t) 0, (uint8_t) 0, (uint8_t) sendStop);
}

uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true);
}

uint8_t TwoWire::requestFrom(int address, int quantity) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) true);
}

uint8_t TwoWire::requestFrom(int address, int quantity, int sendStop) {
return requestFrom((uint8_t) address, (uint8_t) quantity, (uint8_t) sendStop);
}

void TwoWire::beginTransmission(uint8_t address) {
status = MASTER_SEND;

@@ -196,10 +194,6 @@ void TwoWire::beginTransmission(uint8_t address) {
txBufferLength = 0;
}

void TwoWire::beginTransmission(int address) {
beginTransmission((uint8_t) address);
}

//
// Originally, 'endTransmission' was an f(void) function.
// It has been modified to take one parameter indicating
@@ -216,14 +210,14 @@ void TwoWire::beginTransmission(int address) {
uint8_t TwoWire::endTransmission(uint8_t sendStop) {
uint8_t error = 0;
// transmit buffer (blocking)
TWI_StartWrite(twi, txAddress, 0, 0, txBuffer[0]);
TWI_StartWrite(twi, txAddress, 0, 0, txBuffer()[0]);
if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT))
error = 2; // error, got NACK on address transmit

if (error == 0) {
uint16_t sent = 1;
while (sent < txBufferLength) {
TWI_WriteByte(twi, txBuffer[sent++]);
TWI_WriteByte(twi, txBuffer()[sent++]);
if (!TWI_WaitByteSent(twi, XMIT_TIMEOUT))
error = 3; // error, got NACK during data transmmit
}
@@ -250,30 +244,30 @@ uint8_t TwoWire::endTransmission(void)

size_t TwoWire::write(uint8_t data) {
if (status == MASTER_SEND) {
if (txBufferLength >= BUFFER_LENGTH)
if (txBufferLength >= buffers.TX_BUFFER_SIZE)
return 0;
txBuffer[txBufferLength++] = data;
txBuffer()[txBufferLength++] = data;
return 1;
} else {
if (srvBufferLength >= BUFFER_LENGTH)
if (srvBufferLength >= buffers.SRV_BUFFER_SIZE)
return 0;
srvBuffer[srvBufferLength++] = data;
srvBuffer()[srvBufferLength++] = data;
return 1;
}
}

size_t TwoWire::write(const uint8_t *data, size_t quantity) {
if (status == MASTER_SEND) {
for (size_t i = 0; i < quantity; ++i) {
if (txBufferLength >= BUFFER_LENGTH)
if (txBufferLength >= buffers.TX_BUFFER_SIZE)
return i;
txBuffer[txBufferLength++] = data[i];
txBuffer()[txBufferLength++] = data[i];
}
} else {
for (size_t i = 0; i < quantity; ++i) {
if (srvBufferLength >= BUFFER_LENGTH)
if (srvBufferLength >= buffers.SRV_BUFFER_SIZE)
return i;
srvBuffer[srvBufferLength++] = data[i];
srvBuffer()[srvBufferLength++] = data[i];
}
}
return quantity;
@@ -285,13 +279,13 @@ int TwoWire::available(void) {

int TwoWire::read(void) {
if (rxBufferIndex < rxBufferLength)
return rxBuffer[rxBufferIndex++];
return rxBuffer()[rxBufferIndex++];
return -1;
}

int TwoWire::peek(void) {
if (rxBufferIndex < rxBufferLength)
return rxBuffer[rxBufferIndex];
return rxBuffer()[rxBufferIndex];
return -1;
}

@@ -332,7 +326,7 @@ void TwoWire::onService(void) {
onRequestCallback();
else
// create a default 1-byte response
write((uint8_t) 0);
write(static_cast<uint8_t>(0));
}
}

@@ -341,8 +335,8 @@ void TwoWire::onService(void) {
// Copy data into rxBuffer
// (allows to receive another packet while the
// user program reads actual data)
for (uint8_t i = 0; i < srvBufferLength; ++i)
rxBuffer[i] = srvBuffer[i];
for (size_t i = 0; i < srvBufferLength; ++i)
rxBuffer()[i] = srvBuffer()[i];
rxBufferIndex = 0;
rxBufferLength = srvBufferLength;

@@ -359,16 +353,16 @@ void TwoWire::onService(void) {

if (status == SLAVE_RECV) {
if (TWI_STATUS_RXRDY(sr)) {
if (srvBufferLength < BUFFER_LENGTH)
srvBuffer[srvBufferLength++] = TWI_ReadByte(twi);
if (srvBufferLength < buffers.SRV_BUFFER_SIZE)
srvBuffer()[srvBufferLength++] = TWI_ReadByte(twi);
}
}

if (status == SLAVE_SEND) {
if (TWI_STATUS_TXRDY(sr) && !TWI_STATUS_NACK(sr)) {
uint8_t c = 'x';
if (srvBufferIndex < srvBufferLength)
c = srvBuffer[srvBufferIndex++];
c = srvBuffer()[srvBufferIndex++];
TWI_WriteByte(twi, c);
}
}
@@ -405,7 +399,7 @@ static void Wire_Deinit(void) {
// and pullups were not enabled
}

TwoWire Wire = TwoWire(WIRE_INTERFACE, Wire_Init, Wire_Deinit);
TwoWire Wire = TwoWire(WireBuffer::buffers, WIRE_INTERFACE, Wire_Init, Wire_Deinit);

void WIRE_ISR_HANDLER(void) {
Wire.onService();
@@ -443,7 +437,7 @@ static void Wire1_Deinit(void) {
// and pullups were not enabled
}

TwoWire Wire1 = TwoWire(WIRE1_INTERFACE, Wire1_Init, Wire1_Deinit);
TwoWire Wire1 = TwoWire(Wire1Buffer::buffers, WIRE1_INTERFACE, Wire1_Init, Wire1_Deinit);

void WIRE1_ISR_HANDLER(void) {
Wire1.onService();
79 changes: 50 additions & 29 deletions libraries/Wire/src/Wire.h
Original file line number Diff line number Diff line change
@@ -23,62 +23,83 @@

// Include Atmel CMSIS driver
#include <include/twi.h>

#include "Stream.h"
#include "variant.h"

#define BUFFER_LENGTH 32
// Forward declaration of TwoWireBuffer::Buffers
namespace TwoWireBuffer {
struct Buffers;
}

// WIRE_HAS_END means Wire has end()
#define WIRE_HAS_END 1

class TwoWire : public Stream {
public:
TwoWire(Twi *twi, void(*begin_cb)(void), void(*end_cb)(void));
TwoWire(const TwoWireBuffer::Buffers& _buffers,
Twi *twi, void(*begin_cb)(void), void(*end_cb)(void));
void begin();
void begin(uint8_t);
void begin(int);
void end();
void setClock(uint32_t);
void beginTransmission(uint8_t);
void beginTransmission(int);
inline void beginTransmission(int address) {
beginTransmission(static_cast<uint8_t>(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 endTransmission(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(static_cast<uint8_t>(address),
static_cast<uint8_t>(quantity), static_cast<uint8_t>(true));
}
inline uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop) {
return requestFrom(static_cast<uint8_t>(address),
static_cast<uint8_t>(quantity), static_cast<uint32_t>(0),
static_cast<uint8_t>(0), static_cast<uint8_t>(sendStop));
}
inline uint8_t requestFrom(int address, int quantity) {
return requestFrom(static_cast<uint8_t>(address),
static_cast<uint8_t>(quantity), static_cast<uint8_t>(true));
}
inline uint8_t requestFrom(int address, int quantity, int sendStop) {
return requestFrom(static_cast<uint8_t>(address),
static_cast<uint8_t>(quantity), static_cast<uint8_t>(sendStop));
}
size_t write(uint8_t) override;
size_t write(const uint8_t *, size_t) override;
int available(void) override;
int read(void) override;
int peek(void) override;
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); }
using Print::write;
inline size_t write(unsigned long n) { return write(static_cast<uint8_t>(n)); }
inline size_t write(long n) { return write(static_cast<uint8_t>(n)); }
inline size_t write(unsigned int n) { return write(static_cast<uint8_t>(n)); }
inline size_t write(int n) { return write(static_cast<uint8_t>(n)); }
using Print::write;

void onService(void);

private:
// Container of rxBuffer, txBuffer and srvBuffer
const TwoWireBuffer::Buffers& buffers;

// RX Buffer
uint8_t rxBuffer[BUFFER_LENGTH];
inline uint8_t* rxBuffer() const;
uint8_t rxBufferIndex;
uint8_t rxBufferLength;

// TX Buffer
inline uint8_t* txBuffer() const;
uint8_t txAddress;
uint8_t txBuffer[BUFFER_LENGTH];
uint8_t txBufferLength;

// Service buffer
uint8_t srvBuffer[BUFFER_LENGTH];
inline uint8_t* srvBuffer() const;
uint8_t srvBufferIndex;
uint8_t srvBufferLength;

@@ -87,13 +108,13 @@ class TwoWire : public Stream {
void (*onReceiveCallback)(int);

// Called before initialization
void (*onBeginCallback)(void);
void (*const onBeginCallback)(void);

// Called after deinitialization
void (*onEndCallback)(void);
void (*const onEndCallback)(void);

// TWI instance
Twi *twi;
Twi * const twi;

// TWI state
enum TwoWireStatus {
@@ -108,12 +129,12 @@ class TwoWire : public Stream {
TwoWireStatus status;

// TWI clock frequency
static const uint32_t TWI_CLOCK = 100000;
static constexpr uint32_t TWI_CLOCK = 100000;
uint32_t twiClock;

// Timeouts (
static const uint32_t RECV_TIMEOUT = 100000;
static const uint32_t XMIT_TIMEOUT = 100000;
static constexpr uint32_t RECV_TIMEOUT = 100000;
static constexpr uint32_t XMIT_TIMEOUT = 100000;
};

#if WIRE_INTERFACES_COUNT > 0
49 changes: 49 additions & 0 deletions libraries/Wire/src/WireBuffer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
WireBuffer.cpp - 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
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 <stdint.h>
#include <stddef.h>
#include "variant.h"
#include "WireBuffer.h"

#if WIRE_INTERFACES_COUNT > 0
// Define default buffers as weak buffers
namespace WireBuffer {
extern __attribute__((weak)) const Buffers buffers {
WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE
, srvBuffer, rxBuffer, txBuffer
};
__attribute__((weak)) uint8_t srvBuffer[WIRE_BUFFER_DEFAULT_SIZE];
__attribute__((weak)) uint8_t rxBuffer[WIRE_BUFFER_DEFAULT_SIZE];
__attribute__((weak)) uint8_t txBuffer[WIRE_BUFFER_DEFAULT_SIZE];
}
#endif

#if WIRE_INTERFACES_COUNT > 1
// Define default buffers as weak buffers
namespace Wire1Buffer {
extern __attribute__((weak)) const Buffers buffers {
WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE, WIRE_BUFFER_DEFAULT_SIZE
, srvBuffer, rxBuffer, txBuffer
};
__attribute__((weak)) uint8_t srvBuffer[WIRE_BUFFER_DEFAULT_SIZE];
__attribute__((weak)) uint8_t rxBuffer[WIRE_BUFFER_DEFAULT_SIZE];
__attribute__((weak)) uint8_t txBuffer[WIRE_BUFFER_DEFAULT_SIZE];
}
#endif
80 changes: 80 additions & 0 deletions libraries/Wire/src/WireBuffer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
WireBuffer.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
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#pragma once

#ifndef Wire_WireBuffer_h_
#define Wire_WireBuffer_h_

#include <stdint.h>
#include <stddef.h>
#include "variant.h"


// Use extra namespace to avoid collision with other symbols
namespace TwoWireBuffer {
// Declare twi buffers
typedef size_t bufferSize_t;
constexpr bufferSize_t WIRE_BUFFER_DEFAULT_SIZE = 32;

struct Buffers {
bufferSize_t SRV_BUFFER_SIZE;
bufferSize_t RX_BUFFER_SIZE;
bufferSize_t TX_BUFFER_SIZE;
uint8_t* const srvBuffer;
uint8_t* const rxBuffer;
uint8_t* const txBuffer;
};
}

#define SET_TwoWire_BUFFERS(rxBufferSize, txBufferSize) \
constexpr bufferSize_t srvBufferSize = (rxBufferSize) > (txBufferSize) ? (rxBufferSize) : (txBufferSize); \
const Buffers buffers { (srvBufferSize), (rxBufferSize), (txBufferSize), srvBuffer, rxBuffer, txBuffer }; \
uint8_t srvBuffer[srvBufferSize]; \
uint8_t rxBuffer[(rxBufferSize)];\
uint8_t txBuffer[(txBufferSize)];


#if WIRE_INTERFACES_COUNT > 0
namespace WireBuffer {
using namespace TwoWireBuffer;
extern const Buffers buffers;
extern uint8_t srvBuffer[];
extern uint8_t rxBuffer[];
extern uint8_t txBuffer[];
}

#define SET_Wire_BUFFERS(rxBufferSize, txBufferSize, enableMaster, enableSlave) \
namespace WireBuffer {SET_TwoWire_BUFFERS(rxBufferSize, txBufferSize)}
#endif // WIRE_INTERFACES_COUNT > 0

#if WIRE_INTERFACES_COUNT > 1
namespace Wire1Buffer {
using namespace TwoWireBuffer;
extern const Buffers buffers;
extern uint8_t srvBuffer[];
extern uint8_t rxBuffer[];
extern uint8_t txBuffer[];
}

#define SET_Wire1_BUFFERS(rxBufferSize, txBufferSize, enableMaster, enableSlave) \
namespace Wire1Buffer {SET_TwoWire_BUFFERS(rxBufferSize, txBufferSize)}
#endif // WIRE_INTERFACES_COUNT > 1

#endif /* Wire_WireBuffer_h_ */