|
| 1 | +// Wire Slave "256-Byte Memory" Device |
| 2 | +// by Jan Wagner |
| 3 | + |
| 4 | +// Demonstrates use of the Wire library to emulate a 256-byte memory device, |
| 5 | +// with sequential continued read and sequential continued write access. |
| 6 | +// Operates as an I2C/TWI slave device. |
| 7 | +// |
| 8 | +// The protocol used in this example emulates typical small EEPROMs, |
| 9 | +// or i2c-addressible register banks. The master controls the I2C transaction, |
| 10 | +// doing one of two things within a single transaction: |
| 11 | +// |
| 12 | +// 1) master sends an address-byte and sends optional data-byte(s) that the |
| 13 | +// slave shall store into memory starting from the given address, |
| 14 | +// |
| 15 | +// or |
| 16 | +// |
| 17 | +// 2) master sends an address-byte and immediately changes into receive |
| 18 | +// mode, receiving data-byte(s) from slave memory starting from that address. |
| 19 | +// |
| 20 | +// The number of data bytes in the transaction is not known in advance. |
| 21 | +// The master can at any time stop sending (1) or reading (2) data bytes. |
| 22 | +// Either mode, (1) or (2), is carried out as a single multi-byte I2C transaction. |
| 23 | +// |
| 24 | +// Starting from a base address (between 0 and 255) sent by the master, |
| 25 | +// the slave auto-increments the address for each byte sent or read. |
| 26 | +// When the end of address space is reached it wraps back to 0. |
| 27 | + |
| 28 | +// Master writing address, then writing data (case 1) is handled simply in the |
| 29 | +// onReceive event - receives starting address plus data bytes from master |
| 30 | + |
| 31 | +// Master writing address, then reading data (2) is handled in the |
| 32 | +// onReceive event - receives starting address from master, no other data |
| 33 | +// onRequest event - sends the first requested data to master |
| 34 | +// onRequestMore event - sends more, continually reinvoked while master keeps reading |
| 35 | + |
| 36 | +// Created 18 December 2023 |
| 37 | + |
| 38 | +// This example code is in the public domain. |
| 39 | + |
| 40 | +#include <Wire.h> |
| 41 | + |
| 42 | +static volatile byte shared_memory[256]; |
| 43 | +static volatile unsigned int memory_addr = 0; |
| 44 | + |
| 45 | +void setup() { |
| 46 | + unsigned int i; |
| 47 | + |
| 48 | + // initialize memory with a simple pattern |
| 49 | + for(i=0; i<sizeof(shared_memory); i++) { |
| 50 | + shared_memory[i] = i; |
| 51 | + } |
| 52 | + memory_addr = 0; |
| 53 | + |
| 54 | + // initialise Wire |
| 55 | + Wire.begin(8); // join I2C bus with address #8 |
| 56 | + Wire.onReceive(receiveEvent); // register event |
| 57 | + Wire.onRequest(requestEvent); // register event |
| 58 | + Wire.onRequestMore(requestMoreEvent); // register event |
| 59 | +} |
| 60 | + |
| 61 | +void loop() { |
| 62 | + delay(100); |
| 63 | +} |
| 64 | + |
| 65 | +// Helper to get next address within array bounds |
| 66 | +unsigned int next_addr(unsigned int curr_addr) { |
| 67 | + return (curr_addr + 1) % (sizeof(shared_memory) + 1); |
| 68 | +} |
| 69 | + |
| 70 | +// Function that executes whenever data is sent to slave by master |
| 71 | +// This function is registered as an event, see setup() |
| 72 | +void receiveEvent(int nbytes) { |
| 73 | + if(nbytes > 0) { |
| 74 | + |
| 75 | + // receive the memory address that the master wants to access |
| 76 | + memory_addr = Wire.read(); |
| 77 | + memory_addr = memory_addr % (sizeof(shared_memory) + 1); |
| 78 | + nbytes--; |
| 79 | + |
| 80 | + // receive optional data that master might be pushing into client memory |
| 81 | + while(nbytes > 0) { |
| 82 | + shared_memory[memory_addr] = Wire.read(); |
| 83 | + memory_addr = next_addr(memory_addr); |
| 84 | + nbytes--; |
| 85 | + } |
| 86 | + } |
| 87 | +} |
| 88 | + |
| 89 | +// Function that executes whenever data is first requested by master |
| 90 | +// This function is registered as an event, see setup() |
| 91 | +void requestEvent() { |
| 92 | + // master started reading: send back the first data byte |
| 93 | + Wire.write(shared_memory[memory_addr]); |
| 94 | + memory_addr = next_addr(memory_addr); |
| 95 | +} |
| 96 | + |
| 97 | +// Function that executes each time the master in the current transaction |
| 98 | +// tries to read more than initially provided in the onRequest handler above. |
| 99 | +// This function is registered as an event, see setup() |
| 100 | +void requestMoreEvent() { |
| 101 | + // master continues reading: send back the next data byte |
| 102 | + Wire.write(shared_memory[memory_addr]); |
| 103 | + memory_addr = next_addr(memory_addr); |
| 104 | +} |
0 commit comments