|
| 1 | +diff --git a/libraries/Wire/examples/slave_memory/slave_memory.ino b/libraries/Wire/examples/slave_memory/slave_memory.ino |
| 2 | +new file mode 100644 |
| 3 | +index 000000000..942aa023f |
| 4 | +--- /dev/null |
| 5 | ++++ b/libraries/Wire/examples/slave_memory/slave_memory.ino |
| 6 | +@@ -0,0 +1,104 @@ |
| 7 | ++// Wire Slave "256-Byte Memory" Device |
| 8 | ++// by Jan Wagner |
| 9 | ++ |
| 10 | ++// Demonstrates use of the Wire library to emulate a 256-byte memory device, |
| 11 | ++// with sequential continued read and sequential continued write access. |
| 12 | ++// Operates as an I2C/TWI slave device. |
| 13 | ++// |
| 14 | ++// The protocol used in this example emulates typical small EEPROMs, |
| 15 | ++// or i2c-addressible register banks. The master controls the I2C transaction, |
| 16 | ++// doing one of two things within a single transaction: |
| 17 | ++// |
| 18 | ++// 1) master sends an address-byte and sends optional data-byte(s) that the |
| 19 | ++// slave shall store into memory starting from the given address, |
| 20 | ++// |
| 21 | ++// or |
| 22 | ++// |
| 23 | ++// 2) master sends an address-byte and immediately changes into receive |
| 24 | ++// mode, receiving data-byte(s) from slave memory starting from that address. |
| 25 | ++// |
| 26 | ++// The number of data bytes in the transaction is not known in advance. |
| 27 | ++// The master can at any time stop sending (1) or reading (2) data bytes. |
| 28 | ++// Either mode, (1) or (2), is carried out as a single multi-byte I2C transaction. |
| 29 | ++// |
| 30 | ++// Starting from a base address (between 0 and 255) sent by the master, |
| 31 | ++// the slave auto-increments the address for each byte sent or read. |
| 32 | ++// When the end of address space is reached it wraps back to 0. |
| 33 | ++ |
| 34 | ++// Master writing address, then writing data (case 1) is handled simply in the |
| 35 | ++// onReceive event - receives starting address plus data bytes from master |
| 36 | ++ |
| 37 | ++// Master writing address, then reading data (2) is handled in the |
| 38 | ++// onReceive event - receives starting address from master, no other data |
| 39 | ++// onRequest event - sends the first requested data to master |
| 40 | ++// onRequestMore event - sends more, continually reinvoked while master keeps reading |
| 41 | ++ |
| 42 | ++// Created 18 December 2023 |
| 43 | ++ |
| 44 | ++// This example code is in the public domain. |
| 45 | ++ |
| 46 | ++#include <Wire.h> |
| 47 | ++ |
| 48 | ++static volatile byte shared_memory[256]; |
| 49 | ++static volatile unsigned int memory_addr = 0; |
| 50 | ++ |
| 51 | ++void setup() { |
| 52 | ++ unsigned int i; |
| 53 | ++ |
| 54 | ++ // initialize memory with a simple pattern |
| 55 | ++ for(i=0; i<sizeof(shared_memory); i++) { |
| 56 | ++ shared_memory[i] = i; |
| 57 | ++ } |
| 58 | ++ memory_addr = 0; |
| 59 | ++ |
| 60 | ++ // initialise Wire |
| 61 | ++ Wire.begin(8); // join I2C bus with address #8 |
| 62 | ++ Wire.onReceive(receiveEvent); // register event |
| 63 | ++ Wire.onRequest(requestEvent); // register event |
| 64 | ++ Wire.onRequestMore(requestMoreEvent); // register event |
| 65 | ++} |
| 66 | ++ |
| 67 | ++void loop() { |
| 68 | ++ delay(100); |
| 69 | ++} |
| 70 | ++ |
| 71 | ++// Helper to get next address within array bounds |
| 72 | ++unsigned int next_addr(unsigned int curr_addr) { |
| 73 | ++ return (curr_addr + 1) % (sizeof(shared_memory) + 1); |
| 74 | ++} |
| 75 | ++ |
| 76 | ++// Function that executes whenever data is sent to slave by master |
| 77 | ++// This function is registered as an event, see setup() |
| 78 | ++void receiveEvent(int nbytes) { |
| 79 | ++ if(nbytes > 0) { |
| 80 | ++ |
| 81 | ++ // receive the memory address that the master wants to access |
| 82 | ++ memory_addr = Wire.read(); |
| 83 | ++ memory_addr = memory_addr % (sizeof(shared_memory) + 1); |
| 84 | ++ nbytes--; |
| 85 | ++ |
| 86 | ++ // receive optional data that master might be pushing into client memory |
| 87 | ++ while(nbytes > 0) { |
| 88 | ++ shared_memory[memory_addr] = Wire.read(); |
| 89 | ++ memory_addr = next_addr(memory_addr); |
| 90 | ++ nbytes--; |
| 91 | ++ } |
| 92 | ++ } |
| 93 | ++} |
| 94 | ++ |
| 95 | ++// Function that executes whenever data is first requested by master |
| 96 | ++// This function is registered as an event, see setup() |
| 97 | ++void requestEvent() { |
| 98 | ++ // master started reading: send back the first data byte |
| 99 | ++ Wire.write(shared_memory[memory_addr]); |
| 100 | ++ memory_addr = next_addr(memory_addr); |
| 101 | ++} |
| 102 | ++ |
| 103 | ++// Function that executes each time the master in the current transaction |
| 104 | ++// tries to read more than initially provided in the onRequest handler above. |
| 105 | ++// This function is registered as an event, see setup() |
| 106 | ++void requestMoreEvent() { |
| 107 | ++ // master continues reading: send back the next data byte |
| 108 | ++ Wire.write(shared_memory[memory_addr]); |
| 109 | ++ memory_addr = next_addr(memory_addr); |
| 110 | ++} |
| 111 | +diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp |
| 112 | +index 001d924df..bdff763dc 100644 |
| 113 | +--- a/libraries/Wire/src/Wire.cpp |
| 114 | ++++ b/libraries/Wire/src/Wire.cpp |
| 115 | +@@ -43,6 +43,7 @@ uint8_t TwoWire::txBufferLength = 0; |
| 116 | + |
| 117 | + uint8_t TwoWire::transmitting = 0; |
| 118 | + void (*TwoWire::user_onRequest)(void); |
| 119 | ++void (*TwoWire::user_onRequestMore)(void); |
| 120 | + void (*TwoWire::user_onReceive)(int); |
| 121 | + |
| 122 | + // Constructors //////////////////////////////////////////////////////////////// |
| 123 | +@@ -63,6 +64,7 @@ void TwoWire::begin(void) |
| 124 | + |
| 125 | + twi_init(); |
| 126 | + twi_attachSlaveTxEvent(onRequestService); // default callback must exist |
| 127 | ++ twi_attachSlaveTxMoreEvent(onRequestMoreService); // default callback must exist |
| 128 | + twi_attachSlaveRxEvent(onReceiveService); // default callback must exist |
| 129 | + } |
| 130 | + |
| 131 | +@@ -360,6 +362,17 @@ void TwoWire::onRequestService(void) |
| 132 | + user_onRequest(); |
| 133 | + } |
| 134 | + |
| 135 | ++// behind the scenes function that is called when more data is requested |
| 136 | ++void TwoWire::onRequestMoreService(void) |
| 137 | ++{ |
| 138 | ++ // don't bother if user hasn't registered a callback |
| 139 | ++ if(!user_onRequestMore){ |
| 140 | ++ return; |
| 141 | ++ } |
| 142 | ++ // alert user program |
| 143 | ++ user_onRequestMore(); |
| 144 | ++} |
| 145 | ++ |
| 146 | + // sets function called on slave write |
| 147 | + void TwoWire::onReceive( void (*function)(int) ) |
| 148 | + { |
| 149 | +@@ -372,6 +385,12 @@ void TwoWire::onRequest( void (*function)(void) ) |
| 150 | + user_onRequest = function; |
| 151 | + } |
| 152 | + |
| 153 | ++// sets function called on slave read |
| 154 | ++void TwoWire::onRequestMore( void (*function)(void) ) |
| 155 | ++{ |
| 156 | ++ user_onRequestMore = function; |
| 157 | ++} |
| 158 | ++ |
| 159 | + // Preinstantiate Objects ////////////////////////////////////////////////////// |
| 160 | + |
| 161 | + TwoWire Wire = TwoWire(); |
| 162 | +diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h |
| 163 | +index e70d72edb..e3620e241 100644 |
| 164 | +--- a/libraries/Wire/src/Wire.h |
| 165 | ++++ b/libraries/Wire/src/Wire.h |
| 166 | +@@ -45,8 +45,10 @@ class TwoWire : public Stream |
| 167 | + |
| 168 | + static uint8_t transmitting; |
| 169 | + static void (*user_onRequest)(void); |
| 170 | ++ static void (*user_onRequestMore)(void); |
| 171 | + static void (*user_onReceive)(int); |
| 172 | + static void onRequestService(void); |
| 173 | ++ static void onRequestMoreService(void); |
| 174 | + static void onReceiveService(uint8_t*, int); |
| 175 | + public: |
| 176 | + TwoWire(); |
| 177 | +@@ -75,6 +77,7 @@ class TwoWire : public Stream |
| 178 | + virtual void flush(void); |
| 179 | + void onReceive( void (*)(int) ); |
| 180 | + void onRequest( void (*)(void) ); |
| 181 | ++ void onRequestMore( void (*)(void) ); |
| 182 | + |
| 183 | + inline size_t write(unsigned long n) { return write((uint8_t)n); } |
| 184 | + inline size_t write(long n) { return write((uint8_t)n); } |
| 185 | +diff --git a/libraries/Wire/src/utility/twi.c b/libraries/Wire/src/utility/twi.c |
| 186 | +index e09a33caf..391e09b1a 100644 |
| 187 | +--- a/libraries/Wire/src/utility/twi.c |
| 188 | ++++ b/libraries/Wire/src/utility/twi.c |
| 189 | +@@ -56,6 +56,7 @@ static volatile bool twi_timed_out_flag = false; // a timeout has been seen |
| 190 | + static volatile bool twi_do_reset_on_timeout = false; // reset the TWI registers on timeout |
| 191 | + |
| 192 | + static void (*twi_onSlaveTransmit)(void); |
| 193 | ++static void (*twi_onSlaveTransmitMore)(void); |
| 194 | + static void (*twi_onSlaveReceive)(uint8_t*, int); |
| 195 | + |
| 196 | + static uint8_t twi_masterBuffer[TWI_BUFFER_LENGTH]; |
| 197 | +@@ -384,6 +385,17 @@ void twi_attachSlaveTxEvent( void (*function)(void) ) |
| 198 | + twi_onSlaveTransmit = function; |
| 199 | + } |
| 200 | + |
| 201 | ++/* |
| 202 | ++ * Function twi_attachSlaveTxMoreEvent |
| 203 | ++ * Desc sets function called before a slave cont'd sequential data write operation |
| 204 | ++ * Input function: callback function to use |
| 205 | ++ * Output none |
| 206 | ++ */ |
| 207 | ++void twi_attachSlaveTxMoreEvent( void (*function)(void) ) |
| 208 | ++{ |
| 209 | ++ twi_onSlaveTransmitMore = function; |
| 210 | ++} |
| 211 | ++ |
| 212 | + /* |
| 213 | + * Function twi_reply |
| 214 | + * Desc sends byte or readys receive line |
| 215 | +@@ -640,6 +652,10 @@ ISR(TWI_vect) |
| 216 | + case TW_ST_DATA_ACK: // byte sent, ack returned |
| 217 | + // copy data to output register |
| 218 | + TWDR = twi_txBuffer[twi_txBufferIndex++]; |
| 219 | ++ // if the buffer emptied, request it to be topped up |
| 220 | ++ if (twi_txBufferIndex >= twi_txBufferLength) { |
| 221 | ++ twi_onSlaveTransmitMore(); |
| 222 | ++ } |
| 223 | + // if there is more to send, ack, otherwise nack |
| 224 | + if(twi_txBufferIndex < twi_txBufferLength){ |
| 225 | + twi_reply(1); |
| 226 | +diff --git a/libraries/Wire/src/utility/twi.h b/libraries/Wire/src/utility/twi.h |
| 227 | +index 85b983794..ea158d8ea 100644 |
| 228 | +--- a/libraries/Wire/src/utility/twi.h |
| 229 | ++++ b/libraries/Wire/src/utility/twi.h |
| 230 | +@@ -49,6 +49,7 @@ |
| 231 | + uint8_t twi_transmit(const uint8_t*, uint8_t); |
| 232 | + void twi_attachSlaveRxEvent( void (*)(uint8_t*, int) ); |
| 233 | + void twi_attachSlaveTxEvent( void (*)(void) ); |
| 234 | ++ void twi_attachSlaveTxMoreEvent( void (*)(void) ); |
| 235 | + void twi_reply(uint8_t); |
| 236 | + void twi_stop(void); |
| 237 | + void twi_releaseBus(void); |
0 commit comments