Introduction
Welcome to the Pico Multi-Protocol Demo! In this tutorial, we’ll explore how to use the Raspberry Pi Pico (RP2040) to communicate over multiple protocols simultaneously: Serial, I2C, SPI, and ADC. This is an advanced example that brings together several key skills for embedded development. We’ll build the circuit in the Velxio simulator, write the code, and walk through each part step by step.

Circuit Walkthrough
Let’s look at the components and wiring. The circuit uses a Raspberry Pi Pico (Nano RP2040 Connect) and several peripherals:
- Blue LED (led-i2c): Connected to pin D12 (GP12) through a current-limiting resistor. The anode (A) connects to D12, cathode (C) to GND.
- Yellow LED (led-spi): Connected to pin D7 (GP7) similarly.
- Potentiometer (pot-adc): The signal pin (SIG) connects to A0 (GP26). VCC goes to 3.3V, GND to GND.
- Green LED (led-gpio): Connected to pin D2 (GP2).
All LEDs share a common ground. The potentiometer is powered from the 3.3V rail. The wiring is straightforward, but note that we’re using the Pico’s built-in I2C and SPI peripherals (though not shown explicitly in the schematic, the code assumes they are available on the default pins).
Code Walkthrough
The code is written in Arduino C++ and uses the Wire and SPI libraries. Let’s break it down section by section.
Setup
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200);
delay(500);
Serial.println("==============================");
Serial.println(" Pico Multi-Protocol Demo");
Serial.println("==============================");
Serial.println();
We start by initializing the built-in LED and Serial at 115200 baud. The delay gives time for the serial monitor to connect.
1. I2C Scanner
Wire.begin();
Serial.println("[I2C] Scanning bus...");
int found = 0;
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
found++;
Serial.print(" Found device at 0x");
if (addr < 16) Serial.print('0');
Serial.println(addr, HEX);
}
}
Serial.print(" Total devices: "); Serial.println(found);
Serial.println();
This scans all possible I2C addresses (1-126) and reports any that acknowledge. In the simulator, you may see virtual devices at addresses like 0x50 (EEPROM) and 0x68 (RTC).
2. I2C EEPROM R/W
Serial.println("[I2C] EEPROM test at 0x50...");
Wire.beginTransmission(0x50);
Wire.write(0x00); // register 0
Wire.write(0x42); // data
Wire.endTransmission();
delay(5);
Wire.beginTransmission(0x50);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(0x50, 1);
if (Wire.available()) {
byte val = Wire.read();
Serial.print(" Wrote 0x42, Read 0x");
Serial.print(val, HEX);
Serial.println(val == 0x42 ? " — OK" : " — FAIL");
}
Serial.println();
We write the value 0x42 to register 0 of the EEPROM at address 0x50, then read it back to verify. This tests basic I2C read/write.
3. I2C RTC
Serial.println("[I2C] Reading DS1307 RTC at 0x68...");
Wire.beginTransmission(0x68);
Wire.write(0x00);
Wire.endTransmission();
Wire.requestFrom(0x68, 3);
if (Wire.available() >= 3) {
byte sec = ((Wire.read() & 0x7F) >> 4) * 10 + (Wire.read() & 0x0F);
byte min2 = Wire.read();
(void)sec; (void)min2;
Serial.println(" RTC responded OK");
}
Serial.println();
Here we attempt to read the time registers from a DS1307 RTC at address 0x68. The code reads three bytes (seconds, minutes, hours) but only checks if the device responded.
4. SPI Loopback
Serial.println("[SPI] Loopback test...");
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
byte tx = 0xAB;
byte rx = SPI.transfer(tx);
Serial.print(" TX: 0x"); Serial.print(tx, HEX);
Serial.print(" RX: 0x"); Serial.println(rx, HEX);
SPI.endTransaction();
Serial.println();
This performs a simple SPI loopback: it sends 0xAB and reads back whatever is received. In the simulator, the MISO and MOSI are not connected externally, so the received value may be 0xFF or something else. This tests the SPI hardware.
5. ADC
Serial.println("[ADC] Reading analog channels...");
analogReadResolution(12);
int a0 = analogRead(A0);
Serial.print(" A0 (GP26): "); Serial.println(a0);
Serial.println();
We set the ADC resolution to 12 bits and read the value from A0 (GP26). The potentiometer’s wiper voltage is read, giving a value between 0 and 4095.
6. GPIO Blink
Serial.println("[GPIO] Blinking LED...");
for (int i = 0; i < 3; i++) {
digitalWrite(LED_BUILTIN, HIGH);
delay(200);
digitalWrite(LED_BUILTIN, LOW);
delay(200);
}
Serial.println(" 3 blinks done");
Serial.println();
Serial.println("=== All protocol tests complete ===");
}
Finally, we blink the built-in LED three times to indicate the setup is complete.
Loop
void loop() {
// Heartbeat
static unsigned long last = 0;
if (millis() - last >= 3000) {
last = millis();
Serial.print("[Heartbeat] ");
Serial.print(millis() / 1000);
Serial.println("s");
}
}
The loop prints a heartbeat message every 3 seconds to show the program is still running.
Key Concepts
- Multi-protocol integration: Combining Serial, I2C, SPI, and ADC in one sketch teaches you how to manage multiple peripherals without conflicts.
- I2C addressing: Understanding how to scan and communicate with devices at specific addresses.
- SPI configuration: Setting clock speed, bit order, and mode.
- ADC resolution: Using
analogReadResolution()to get higher precision. - Serial debugging: Using the Serial Monitor to output real-time data.
Common Pitfalls & Debugging Tips
- I2C pull-up resistors: The Pico has internal pull-ups, but external ones may be needed for longer wires. In the simulator, this is handled automatically.
- SPI loopback: Without a physical loopback, the received data may be garbage. Use a jumper wire between MOSI and MISO for a true loopback test.
- ADC noise: Potentiometers can be noisy; adding a capacitor across the wiper to ground helps.
- Serial baud rate mismatch: Ensure your Serial Monitor is set to 115200 baud.
Suggested Extensions
- Add an external I2C sensor (e.g., temperature/humidity) and display its readings.
- Use SPI to control an OLED display.
- Implement a simple data logger that reads the ADC and stores values in the EEPROM.
- Add a button to trigger different test modes.
Try It Yourself!
Ready to experiment? Open the live example in Velxio and run the simulation. You can modify the code, add components, and see the results instantly.
Launch the Pico Multi-Protocol Demo on Velxio



Happy hacking!