Skip to content
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

Feature/wire on request more #550

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
104 changes: 104 additions & 0 deletions libraries/Wire/examples/slave_memory/slave_memory.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Wire Slave "256-Byte Memory" Device
// by Jan Wagner

// Demonstrates use of the Wire library to emulate a 256-byte memory device,
// with sequential continued read and sequential continued write access.
// Operates as an I2C/TWI slave device.
//
// The protocol used in this example emulates typical small EEPROMs,
// or i2c-addressible register banks. The master controls the I2C transaction,
// doing one of two things within a single transaction:
//
// 1) master sends an address-byte and sends optional data-byte(s) that the
// slave shall store into memory starting from the given address,
//
// or
//
// 2) master sends an address-byte and immediately changes into receive
// mode, receiving data-byte(s) from slave memory starting from that address.
//
// The number of data bytes in the transaction is not known in advance.
// The master can at any time stop sending (1) or reading (2) data bytes.
// Either mode, (1) or (2), is carried out as a single multi-byte I2C transaction.
//
// Starting from a base address (between 0 and 255) sent by the master,
// the slave auto-increments the address for each byte sent or read.
// When the end of address space is reached it wraps back to 0.

// Master writing address, then writing data (case 1) is handled simply in the
// onReceive event - receives starting address plus data bytes from master

// Master writing address, then reading data (2) is handled in the
// onReceive event - receives starting address from master, no other data
// onRequest event - sends the first requested data to master
// onRequestMore event - sends more, continually reinvoked while master keeps reading

// Created 18 December 2023

// This example code is in the public domain.

#include <Wire.h>

static volatile byte shared_memory[256];
static volatile unsigned int memory_addr = 0;

void setup() {
unsigned int i;

// initialize memory with a simple pattern
for(i=0; i<sizeof(shared_memory); i++) {
shared_memory[i] = i;
}
memory_addr = 0;

// initialise Wire
Wire.begin(8); // join I2C bus with address #8
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register event
Wire.onRequestMore(requestMoreEvent); // register event
}

void loop() {
delay(100);
}

// Helper to get next address within array bounds
unsigned int next_addr(unsigned int curr_addr) {
return (curr_addr + 1) % (sizeof(shared_memory) + 1);
}

// Function that executes whenever data is sent to slave by master
// This function is registered as an event, see setup()
void receiveEvent(int nbytes) {
if(nbytes > 0) {

// receive the memory address that the master wants to access
memory_addr = Wire.read();
memory_addr = memory_addr % (sizeof(shared_memory) + 1);
nbytes--;

// receive optional data that master might be pushing into client memory
while(nbytes > 0) {
shared_memory[memory_addr] = Wire.read();
memory_addr = next_addr(memory_addr);
nbytes--;
}
}
}

// Function that executes whenever data is first requested by master
// This function is registered as an event, see setup()
void requestEvent() {
// master started reading: send back the first data byte
Wire.write(shared_memory[memory_addr]);
memory_addr = next_addr(memory_addr);
}

// Function that executes each time the master in the current transaction
// tries to read more than initially provided in the onRequest handler above.
// This function is registered as an event, see setup()
void requestMoreEvent() {
// master continues reading: send back the next data byte
Wire.write(shared_memory[memory_addr]);
memory_addr = next_addr(memory_addr);
}
19 changes: 19 additions & 0 deletions libraries/Wire/src/Wire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ uint8_t TwoWire::txBufferLength = 0;

uint8_t TwoWire::transmitting = 0;
void (*TwoWire::user_onRequest)(void);
void (*TwoWire::user_onRequestMore)(void);
void (*TwoWire::user_onReceive)(int);

// Constructors ////////////////////////////////////////////////////////////////
Expand All @@ -63,6 +64,7 @@ void TwoWire::begin(void)

twi_init();
twi_attachSlaveTxEvent(onRequestService); // default callback must exist
twi_attachSlaveTxMoreEvent(onRequestMoreService); // default callback must exist
twi_attachSlaveRxEvent(onReceiveService); // default callback must exist
}

Expand Down Expand Up @@ -360,6 +362,17 @@ void TwoWire::onRequestService(void)
user_onRequest();
}

// behind the scenes function that is called when more data is requested
void TwoWire::onRequestMoreService(void)
{
// don't bother if user hasn't registered a callback
if(!user_onRequestMore){
return;
}
// alert user program
user_onRequestMore();
}

// sets function called on slave write
void TwoWire::onReceive( void (*function)(int) )
{
Expand All @@ -372,6 +385,12 @@ void TwoWire::onRequest( void (*function)(void) )
user_onRequest = function;
}

// sets function called on slave read
void TwoWire::onRequestMore( void (*function)(void) )
{
user_onRequestMore = function;
}

// Preinstantiate Objects //////////////////////////////////////////////////////

TwoWire Wire = TwoWire();
Expand Down
3 changes: 3 additions & 0 deletions libraries/Wire/src/Wire.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ class TwoWire : public Stream

static uint8_t transmitting;
static void (*user_onRequest)(void);
static void (*user_onRequestMore)(void);
static void (*user_onReceive)(int);
static void onRequestService(void);
static void onRequestMoreService(void);
static void onReceiveService(uint8_t*, int);
public:
TwoWire();
Expand Down Expand Up @@ -75,6 +77,7 @@ class TwoWire : public Stream
virtual void flush(void);
void onReceive( void (*)(int) );
void onRequest( void (*)(void) );
void onRequestMore( 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); }
Expand Down
16 changes: 16 additions & 0 deletions libraries/Wire/src/utility/twi.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ 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_onSlaveTransmitMore)(void);
static void (*twi_onSlaveReceive)(uint8_t*, int);

static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH];
Expand Down Expand Up @@ -384,6 +385,17 @@ void twi_attachSlaveTxEvent( void (*function)(void) )
twi_onSlaveTransmit = function;
}

/*
* Function twi_attachSlaveTxMoreEvent
* Desc sets function called before a slave cont'd sequential data write operation
* Input function: callback function to use
* Output none
*/
void twi_attachSlaveTxMoreEvent( void (*function)(void) )
{
twi_onSlaveTransmitMore = function;
}

/*
* Function twi_reply
* Desc sends byte or readys receive line
Expand Down Expand Up @@ -640,6 +652,10 @@ ISR(TWI_vect)
case TW_ST_DATA_ACK: // byte sent, ack returned
// copy data to output register
TWDR = twi_txBuffer[twi_txBufferIndex++];
// if the buffer emptied, request it to be topped up
if (twi_txBufferIndex >= twi_txBufferLength) {
twi_onSlaveTransmitMore();
}
// if there is more to send, ack, otherwise nack
if(twi_txBufferIndex < twi_txBufferLength){
twi_reply(1);
Expand Down
1 change: 1 addition & 0 deletions libraries/Wire/src/utility/twi.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
uint8_t twi_transmit(const uint8_t*, uint8_t);
void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) );
void twi_attachSlaveTxEvent( void (*)(void) );
void twi_attachSlaveTxMoreEvent( void (*)(void) );
void twi_reply(uint8_t);
void twi_stop(void);
void twi_releaseBus(void);
Expand Down
Loading