Microcontroller boards can communicate with a wide variety of sensors using several standard protocols. This guide serves as a practical resource for quickly referencing the pin connections for I2C, SPI, and UART communication on popular microcontroller boards, including Arduino, ESP32, and Raspberry Pi.
I2C (Inter-Integrated Circuit)
Diagram courtesy of SparkFun
I2C is a master-slave protocol where the Arduino acts as the master and sensors are slaves. Each device has a unique 7-bit or 10-bit address, allowing multiple devices to share the same SDA and SCL lines. The master initiates communication by sending the device address followed by read or write commands. Data is transmitted in bytes, synchronized by the clock line, and both master and slave can acknowledge receipt of each byte.
Pin Descriptions
| Pin | Type | Description |
|---|---|---|
| SDA | Data | Carries data between master and slave devices |
| SCL | Clock | Synchronizes data transfer |
Pin Mapping
| Board | SDA | SCL | Notes |
|---|---|---|---|
| Arduino Uno / Nano / Mini | A4 | A5 | Fixed hardware pins |
| Arduino Mega 2560 | 20 | 21 | Fixed hardware pins |
| Arduino Leonardo / Micro | 2 | 3 | Fixed hardware pins |
| Arduino Due / Zero | 20 | 21 | Fixed hardware pins |
| ESP32 | 21 (default) | 22 (default) - configurable via code | Can be reassigned in software |
| ESP8266 (NodeMCU) | D2 (GPIO4) | D1 (GPIO5) - configurable via code | Can be reassigned in software |
| Raspberry Pi Pico / Pico 2 | I2C0: GP0 I2C1: GP2 |
I2C0: GP1 I2C1: GP3 |
2 I2C buses (I2C0 default) |
SPI (Serial Peripheral Interface)
Diagram courtesy of SparkFun
SPI uses a master-slave setup with separate lines for data transmission (MOSI / PICO), data reception (MISO / POCI), clock (SCK), and a unique chip select (CS) for each device. The master controls the clock, and communication occurs full-duplex, meaning data can be sent and received simultaneously. Each slave listens only when its CS pin is active, allowing multiple devices to share the SPI bus.
Pin Descriptions
| Pin | Type | Description |
|---|---|---|
| MOSI / PICO | Data Out | Sends data from master to slave |
| MISO / POCI | Data In | Receives data from slave to master |
| SCK | Clock | Synchronizes data transfer |
| CS / SS | Chip Select | Selects the active slave device |
Pin Mapping
| Board | MOSI / PICO | MISO / POCI | SCK | CS / SS |
|---|---|---|---|---|
| Arduino Uno / Nano / Mini | 11 | 12 | 13 | 10 (default SS) |
| Arduino Mega 2560 | 51 | 50 | 52 | 53 (default SS) |
| Arduino Leonardo / Micro | D16 | D14 | D15 | 10 (default SS) |
| ESP32 | 23 (default) | 19 (default) | 18 (default) | 5 (default) - configurable |
| ESP8266 (NodeMCU) | D7 (GPIO13) | D6 (GPIO12) | D5 (GPIO14) | D8 (GPIO15) |
| Raspberry Pi Pico / Pico 2 | GP3 / GP7 | GP4 / GP8 | GP2 / GP6 | Custom |
UART / Serial
Diagram courtesy of SparkFun
UART is a point-to-point, asynchronous protocol that sends data as a stream of bits using TX and RX lines. There are no addresses; each device connects directly to another. The data is framed with start and stop bits, and both devices must agree on a baud rate to ensure accurate timing.
Pin Descriptions
| Pin | Type | Description |
|---|---|---|
| TX | Transmit | Sends data from this device to another UART device |
| RX | Receive | Receives data from another UART device |
Pin Mapping
| Board | TX | RX | Notes |
|---|---|---|---|
| Arduino Uno / Nano / Mini | 1 | 0 | Single hardware UART |
| Arduino Mega 2560 | TX0: 1 TX1: 18 TX2: 16 TX3: 14 |
RX0: 0 RX1: 19 RX2: 17 RX3: 15 |
Four hardware UARTs |
| Arduino Leonardo / Micro | TX: 1 (USB Serial via MCU) | RX: 0 (USB Serial via MCU) | Hardware Serial available on pins 0/1, plus USB Serial |
| ESP32 | TX0: 1 TX1: 17 TX2: 16 |
RX0: 3 RX1: 16 RX2: 17 |
Multiple UARTs, configurable pins |
| ESP8266 (NodeMCU) | TX: D10 (GPIO1) | RX: D9 (GPIO3) | Single hardware UART |
| Raspberry Pi Pico / Pico 2 | TX0: GP0 TX1: GP4 |
RX0: GP1 RX1: GP5 |
Two UARTs, pins configurable |
Comparison of I2C, SPI, and UART
Each communication protocol has its own advantages and typical use cases depending on the number of devices, speed requirements, and wiring complexity. Here's a detailed comparison:
| Category | I2C | SPI | UART / Serial |
|---|---|---|---|
| Number of Wires | 2 (SDA, SCL) | 4 minimum (MOSI / PICO, MISO / POCI, SCK, CS per device) | 2 (TX, RX) |
| Speed | Standard: 100 kbps Fast: 400 kbps Fast+: 1 Mbps |
Fast: typically up to 10–50 Mbps (depending on MCU) | Standard baud rates: 9600–115200 bps, can be higher |
| Device Addressing | Each slave has a unique 7-bit or 10-bit address | No addressing, each slave has dedicated CS line | Point-to-point (no addressing) |
| Typical Use Cases | Multiple sensors, EEPROMs, RTCs, display modules | High-speed sensors, SD cards, displays, ADC/DAC modules | GPS modules, Bluetooth modules, serial debugging, simple devices |
| Pros | Few wires, supports multiple devices on same bus, widely used | Very fast, full-duplex communication, simple protocol | Simple to implement, widely supported, long cable distance possible |
| Cons | Slower than SPI, limited cable length, may need pull-up resistors | More wires required, limited number of CS lines, each device needs separate CS | Only supports 1-to-1 communication per hardware UART, slower than SPI for multiple devices |
When to Use Which Protocol
- I2C: Use when you have multiple low-to-medium speed devices that need to share the same bus with minimal wiring, like temperature sensors, EEPROMs, RTCs, or small displays.
- SPI: Use when you need high-speed communication, full-duplex data transfer, or when working with SD cards, TFT displays, ADC/DAC chips, or any device where speed is critical.
- UART / Serial: Use for simple point-to-point communication, debugging via serial console, or modules like GPS, Bluetooth, or other serial peripherals where only two wires are needed.