Build a task where a Master microcontroller sends 100 KB of data to a Slave microcontroller using I2C first and then SPI respectively.
NOTE: The string of 1KB of data is given below; send it 100 times for 100 KB of data.
Data String
“I2C (Inter-Integrated Circuit) & SPI (Serial Peripheral Interface ) are two common communication protocols used to connect devices like sensors and microcontrollers. I2C uses two lines: SDA (data) and SCL (clock), allowing multiple devices to communicate through unique addresses. It supports multi-master and multi-slave configurations but operates at a slower speed, typically 100kHz to 400 kHz, though it can reach higher speeds in fast modes. I2C is simple and requires fewer connections, but its clock stretching and overhead make it less efficient for high-speed data transfers. SPI, on the other hand, use four lines: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCK (clock), and SS (Slave Select). SPI supports higher speeds (up to tens of MHz), making it better suited for fast data transfers. It's simpler in protocol, with no need for addressing, but it requires more wires and separate SS lines. While I2C is ideal for many devices, SPI excels in fast, reliable communication.”
Expected Output

SPI(Serial Peripheral Interface) is a High-Speed, synchronous, full-duplex, serial Communication protocol.

SPI communication is commonly used to interface such as Memory devices (SD cards, EEPROM, Flash), displays(OLED), sensors, and ADC/DAC.
| Signal | Full Name | Direction | Description |
|---|---|---|---|
| SCK | Serial Clock | Master → Slave | Generated by the master to synchronise data transfer |
| MOSI | Master Out Slave In | Master → Slave | Data from master to slave |
| MISO | Master In Slave Out | Slave → Master | Data from slave to master |
| SS/CS | Slave Select / Chip Select | Master → Slave | Selects which slave is active (Active-Low) |
No Addressing for Slave- SPI uses chip select (SS) lines to select slaves.
SPI has 4 modes, determined by CPOL (Clock Polarity) and CPHA (Clock Phase).
| Mode | CPOL | CPHA | Clock Idle State | Data Sampled On |
|---|---|---|---|---|
| 0 | 0 | 0 | Low | Rising Edge |
| 1 | 0 | 1 | Low | Falling Edge |
| 2 | 1 | 0 | High | Falling Edge |
| 3 | 1 | 1 | High | Rising Edge |
SPI Mode Diagram

Example
Mode 0- In SPI Mode 0 (CPOL=0, CPHA=0), clock polarity is low when idle; data is sampled on the rising edge as shown in the given diagram.
Data sampling w.r.t clock polarity and phase.



Note: This protocol is not designed for a multi-master configuration by default.
SPI is an on-board protocol found in most controllers ( AVR, PIC, ARM, and RISC).
Generally following registers are present in controllers. (with reference to AVR ATmega 328P)
| Registers | Description |
|---|---|
| SPCR | SPI Control Register: enabling SPI and interrupt, selecting Master/Slave mode, clock polarity (CPOL), phase (CPHA), and data order (MSB/LSB first) |
| SPISR | SPI Status Register: flags(SPIF, WCOL) help manage and monitor SPI communication and double the Speed in SPI. |
| SPDR | SPI Data Register - writing/ reading data buffer for SPI communication |
SPI communication pins in Arduino UNO

| Functions | Descriptions |
|---|---|
SPI. begin() | Initializes the SPI bus by setting SCK, MOSI, and SS to outputs |
SPI. beginTransaction(mySettings) | Initializes the SPI bus. Note that calling SPI.begin() is required before calling this one. |
mySetting(speedMaximum, dataOrder, dataMode) | SPISettings object is used with SPI.beginTransaction() for configuration. |
SPI. endTransaction() | Stop using the SPI bus. |
SPI. end() | Disables the SPI bus (leaving pin modes unchanged). |
SPI. setBitOrder(order) | Sets the order of the bits shifted out. |
SPI. setClockDivider(divider) | Sets the SPI clock divider relative to the system clock. |
SPI. setDataMode(mode) | Sets the SPI data mode. |
SPI. transfer() | Transfer and receipt of the data. |
SPI. usingInterrupt() | Inform the SPI library to avoid conflicts with a specific interrupt. |
Master sends 0x80 to the slave using SPI.

Master Code(A1)
#include <SPI.h>
void setup() {
SPI.begin(); // Initialize SPI bus
pinMode(SS, OUTPUT); // Set SS pin as output
digitalWrite(SS, HIGH); // Deselect slave initially
Serial.begin(9600); // For debug (optional)
}
void loop() {
digitalWrite(SS, LOW); // Select slave
byte received = SPI.transfer(0x80); // Send 0x80 and read response
digitalWrite(SS, HIGH); // Deselect slave
Serial.print("Sent: 0x80 | Received: 0x");
Serial.println(received, HEX); // Print slave's response
delay(1000); // Wait 1 second
}
Slave Code(A2)
#include <SPI.h>
volatile byte receivedData;
void setup() {
Serial.begin(9600);
pinMode(MISO, OUTPUT); // Set MISO as output (Slave)
SPCR |= (1 << SPE); // Enable SPI (Slave mode)
SPCR |= (1 << SPIE); // Enable SPI Interrupt
}
ISR(SPI_STC_vect) { // SPI Interrupt Service Routine
receivedData = SPDR; // Store received byte
Serial.print("Received: 0x");
if (receivedData < 0x10)
Serial.print("0"); // Pad single digit hex
Serial.println(receivedData, HEX); // Print in HEX
}
void loop() {
// Do nothing (SPI runs via interrupt)
}