Getting Started With the Arduino SPE Shield

This tutorial will give you an overview of the core features of the SPE Shield.

Learn how to establish Single Pair Ethernet (SPE) communication using the Arduino® UNO SPE Shield, enabling Industrial IoT (IIoT) connectivity with minimal wiring complexity.

Overview

The Arduino® UNO SPE Shield brings industrial-grade Single Pair Ethernet (10BASE-T1S) as well as RS-485 connectivity to Arduino boards, revolutionizing how we connect devices in industrial and IoT applications. This shield combines the simplicity of Ethernet communication with the efficiency of using just a single twisted pair of wires, making it ideal for environments where cable reduction and reliable communication are crucial while still allowing for legacy devices to be part of your network with the option of RS-485.

Arduino UNO SPE Shield
Arduino UNO SPE Shield

In this guide, you'll learn how to set up your first SPE network, understand the fundamentals of 10BASE-T1S communication, and implement both point-to-point and multidrop network configurations.

Hardware and Software Requirements

Hardware Requirements

Software Requirements

Product Overview

The Arduino UNO SPE Shield is a versatile solution for industrial communication, IoT, and automation, combining Single Pair Ethernet (10BASE-T1S) and RS-485. It enables integration into low-power Ethernet networks and robust serial communication systems, ensuring efficient connectivity in embedded environments.

Compatible with the Arduino UNO form factor, it supports SPI, UART, and I2C, facilitating interoperability with various devices. Additionally, it features screw terminals for additional connectivity and power options. Its robust design and advanced protection makes it ideal for applications in industrial environments for remote monitoring and automated control.

Key Features

  • Single Pair Ethernet: 10BASE-T1S standard with 10 Mbps data rate, supporting up to 25 meters in multidrop topology with up to 8 nodes
  • RS-485 Communication: Half-duplex operation at 20 Mbps with 120Ω termination jumper and fail-safe biasing
  • Multiple Interfaces: UART, SPI, and I2C connectivity through Arduino UNO headers
  • Robust Design: Operating temperature range -40°C to +85°C with advanced protection features
  • Dimensions: Standard Arduino shield form factor at 68.58 mm x 53.34 mm

Pinout

The full pinout is available below:

Arduino UNO SPE Shield Pinout
Arduino UNO SPE Shield Pinout

Datasheet

The complete datasheet is available and downloadable as PDF from the link below:

Schematics

The complete schematics are available and downloadable as PDF from the link below:

STEP Files

The complete STEP files are available and downloadable from the link below:

Form Factor

The Arduino UNO SPE Shield follows the standard Arduino UNO shield form factor, ensuring compatibility with all Arduino UNO boards and enabling stackable designs. With dimensions of 68.58 mm x 53.34 mm, the shield maintains the familiar Arduino ecosystem layout while adding industrial-grade communication capabilities.

The shield features the standard Arduino UNO header arrangement with digital and analog pin access, ICSP connector placement, and proper mounting hole alignment.

Simplified Form Factor Dimensions
Simplified Form Factor Dimensions

This standardized form factor allows seamless integration into existing Arduino UNO projects and ensures that the shield can be easily incorporated into enclosures and mounting systems designed for the Arduino UNO ecosystem.

Connectors

The Arduino UNO SPE Shield features several connectors for establishing communication and providing power.

Single Pair Ethernet (SPE)

The shield offers two primary ways to connect to a Single Pair Ethernet (SPE) 10BASE-T1S network:

SPE Connectors
SPE Connectors

  • T1S Connector: The shield includes a dedicated connector for robust, direct SPE connections to compatible devices.
  • Screw Terminals: Screw terminals marked for N (Negative) and P (Positive) pins are also available.

Key Features:

  • Speed: Operates at 10 Mbps under the 10BASE-T1S standard.
  • Maximum Distance: Supports up to 25 meters in multidrop topology (multiple nodes on a single segment).
  • Topology: Allows up to eight nodes in a multidrop network.

RS-485

  • The shield exposes the RS-485 connections marked as A and B, with both GND and +5V through a dedicated screw terminal.
    RS-485 Connector
    RS-485 Connector

Key Features:

  • Speed: Up to 20 Mbps for short distances (<15 m).
  • Maximum Distance: Supports up to 1,200 m with reduced speeds.
  • Topology: Works in a bus topology, supporting up to 80 nodes.

Power

A screw connector for powering the board and Shield assembly is provided with two positions for GND and two for VIN (7.0 to 24.0 V).

Power Screw Connector
Power Screw Connector

Note: The UNO SPE Shield can safely operate with a 24 VDC power supply. While the Arduino UNO R4 is designed to handle this voltage without issue, caution is advised, 24 V can potentially damage UNO R3 boards or any third-party UNO-compatible board.

Termination Jumpers:

SPE Termination Jumper:

To enable the onboard termination resistors for the SPE bus, there are two pairs of contacts you can bridge.

Termination jumpers
Termination jumpers

  • Point-to-Point Setup: Use jumpers to enable the termination at endpoints for proper signal integrity.
  • Multidrop Setup: Terminations are disabled internally; only the furthest nodes in the network should be terminated.

RS-485 Termination Jumper:

The same principle applies to the RS-485 connector however in this case there is only a single jumper that needs to be bridged.

Termination jumpers
Termination jumpers
Termination: Includes a 120 Ω termination jumper to match the bus impedance. Proper termination minimizes signal reflections, critical for long-distance communication stability.

First Use of the UNO SPE Shield

Stack the Shield

  1. Align the Arduino UNO SPE Shield with your Arduino board
  2. Carefully press down on the headers to ensure proper connection
  3. Verify all pins are properly seated

Power the Board

The shield can be powered through multiple sources:

  • A - USB Power: Via the host board USB connection.
  • B - Power Jack: Via the host board power jack.
  • C - External Power: Through the VIN screw terminal (7.0 to 24.0 V). Note: The UNO SPE Shield can safely operate with a 24 VDC power supply. While the Arduino UNO R4 is designed to handle this voltage without issue, caution is advised, 24 V can potentially damage UNO R3 boards or any third-party UNO-compatible board.
  • D - Power over Data Line (PoDL): Through the T1SP screw terminal or dedicated connector.

Powering your board

Simple Broadcast Example

This example demonstrates a simple broadcast communication system between multiple nodes on an SPE network. Each node can broadcast messages to all other nodes, and automatically responds with "pong" when it receives a "ping" message. This creates an interactive network where you can test connectivity and response times between different devices.

Overview of the Ping/Pong example

Hardware Setup

  1. Configure Termination Jumpers: For point-to-point connections, close the termination jumpers on both shields
  2. Connect the SPE Cable: Wire the twisted pair between the two shields' SPE screw terminals or using a T1S dedicated cable.
  3. Power Both Systems: Ensure both Arduino boards are powered

Sketch

The system uses UDP broadcasting to send messages to all nodes simultaneously, making it perfect for testing your SPE network setup and verifying that all nodes are communicating properly. Each node operates independently, listening for incoming messages while also being able to send its own broadcasts.

Important: Before uploading this code to each board, you must change the

NODE_ID
constant to a unique value between 0 and 7. Each node on the network must have a different ID to ensure proper communication and avoid conflicts. For example:

  • First board:
    MY_NODE_NUMBER = 0;
  • Second board:
    MY_NODE_NUMBER = 1;
  • Third board (optional):
    MY_NODE_NUMBER = 2;

Remember that any termination nodes should have the termination headers properly closed, more info on the Arduino UNO SPE Shield datasheet.

The node ID determines the device's IP address (192.168.42.100 + NODE_ID) and its position in the PLCA (Physical Layer Collision Avoidance) cycle. When you type a message in the Serial Monitor and press Enter, it's broadcast to all nodes on the network. If any node receives the word "ping", it automatically responds with "pong" to the sender.

1// Simple 10BASE-T1S Ping-Pong Network
2// Each board can send messages to all others
3// Automatically replies "pong" when it receives "ping"
4
5#include <Arduino_10BASE_T1S.h>
6#include <SPI.h>
7
8// CHANGE THIS NUMBER FOR EACH BOARD (0, 1, 2, 3, etc.)
9const int MY_NODE_NUMBER = 0;
10
11// Network addresses (like house addresses on a street)
12const IPAddress MY_IP_ADDRESS(192, 168, 42, 100 + MY_NODE_NUMBER);
13const IPAddress SUBNET_MASK(255, 255, 255, 0);
14const IPAddress GATEWAY_ADDRESS(192, 168, 42, 100);
15const IPAddress BROADCAST_ADDRESS(192, 168, 42, 255); // Sends to everyone
16const int NETWORK_PORT = 8888;
17
18// Hardware objects (think of these as your network components)
19TC6::TC6_Io* networkIO = nullptr;
20TC6::TC6_Arduino_10BASE_T1S* networkController = nullptr;
21Arduino_10BASE_T1S_UDP* messageService = nullptr;
22
23// For reading typed messages
24char typedMessage[128];
25int messageLength = 0;
26
27void setup() {
28 // Start serial communication
29 Serial.begin(115200);
30 delay(1000);
31
32 // Show which node this is
33 Serial.print("\n=== Network Node #");
34 Serial.print(MY_NODE_NUMBER);
35 Serial.println(" ===");
36 Serial.print("My IP address: ");
37 Serial.println(MY_IP_ADDRESS);
38
39 // Set up the network hardware
40 if (!setupNetwork()) {
41 Serial.println("ERROR: Network setup failed!");
42 while(1) {
43 delay(1000); // Stop here if network won't start
44 }
45 }
46
47 Serial.println("\n✓ Ready to communicate!");
48 Serial.println("Type a message and press Enter to send to everyone");
49 Serial.println("I'll automatically reply 'pong' if someone sends 'ping'\n");
50}
51
52void loop() {
53 // Keep the network running (like keeping your phone connected to WiFi)
54 (*networkController).service();
55
56 // Check if user typed something
57 checkForTypedMessages();
58
59 // Check if someone sent us a message
60 checkForIncomingMessages();
61
62 // Show we're still alive every 10 seconds
63 showHeartbeat();
64}
65
66bool setupNetwork() {
67 Serial.println("Setting up network hardware...");
68
69 // Create the network components
70 networkIO = new TC6::TC6_Io(SPI, CS_PIN, RESET_PIN, IRQ_PIN);
71 networkController = new TC6::TC6_Arduino_10BASE_T1S(networkIO);
72 messageService = new Arduino_10BASE_T1S_UDP();
73
74 // Set up interrupt (this lets the network chip tell us when data arrives)
75 pinMode(IRQ_PIN, INPUT_PULLUP);
76 attachInterrupt(digitalPinToInterrupt(IRQ_PIN), []() {
77 if (networkIO) (*networkIO).onInterrupt();
78 }, FALLING);
79
80 // Start the low-level network interface
81 if (!(*networkIO).begin()) {
82 Serial.println("Failed to start network interface");
83 return false;
84 }
85
86 // Create unique network identity
87 MacAddress myMacAddress = MacAddress::create_from_uid();
88 T1SPlcaSettings plcaSettings(MY_NODE_NUMBER);
89 T1SMacSettings macSettings;
90
91 // Connect to the network with our address
92 if (!(*networkController).begin(MY_IP_ADDRESS, SUBNET_MASK, GATEWAY_ADDRESS,
93 myMacAddress, plcaSettings, macSettings)) {
94 Serial.println("Failed to join network");
95 return false;
96 }
97
98 // Configure output pins (not used in this simple example)
99 (*networkController).digitalWrite(TC6::DIO::A0, false);
100 (*networkController).digitalWrite(TC6::DIO::A1, false);
101
102 // Start the message service
103 if (!(*messageService).begin(NETWORK_PORT)) {
104 Serial.println("Failed to start message service");
105 return false;
106 }
107
108 Serial.print("Network ID (MAC): ");
109 Serial.println(myMacAddress);
110 Serial.println("✓ Network setup complete");
111
112 return true;
113}
114
115void checkForTypedMessages() {
116 // Read characters as user types
117 while (Serial.available()) {
118 char newChar = Serial.read();
119
120 // If user pressed Enter, send the message
121 if (newChar == '\n' || newChar == '\r') {
122 if (messageLength > 0) {
123 typedMessage[messageLength] = '\0'; // End the string
124 sendMessageToEveryone(typedMessage);
125 messageLength = 0; // Reset for next message
126 }
127 }
128 // Add character to our message (if there's room)
129 else if (messageLength < sizeof(typedMessage) - 1) {
130 typedMessage[messageLength] = newChar;
131 messageLength++;
132 }
133 }
134}
135
136void sendMessageToEveryone(const char* message) {
137 // Don't send empty messages
138 if (!messageService || strlen(message) == 0) {
139 return;
140 }
141
142 // Send to broadcast address (everyone on network gets it)
143 (*messageService).beginPacket(BROADCAST_ADDRESS, NETWORK_PORT);
144 (*messageService).write((const uint8_t*)message, strlen(message));
145 (*messageService).endPacket();
146
147 Serial.print("📤 Sent to all: ");
148 Serial.println(message);
149}
150
151void checkForIncomingMessages() {
152 // See if a message arrived
153 int messageSize = (*messageService).parsePacket();
154
155 // No message or message too big
156 if (messageSize <= 0 || messageSize >= 256) {
157 return;
158 }
159
160 // Read the message
161 char receivedMessage[256] = {0};
162 IPAddress senderAddress = (*messageService).remoteIP();
163
164 int bytesRead = (*messageService).read((uint8_t*)receivedMessage,
165 min(messageSize, 255));
166 if (bytesRead <= 0) {
167 return;
168 }
169
170 receivedMessage[bytesRead] = '\0'; // End the string properly
171
172 // Show who sent what
173 Serial.print("📥 From ");
174 Serial.print(senderAddress);
175 Serial.print(": ");
176 Serial.println(receivedMessage);
177
178 // If someone sent "ping", automatically reply "pong"
179 if (strcmp(receivedMessage, "ping") == 0) {
180 // Small delay to avoid message collisions (each node waits different time)
181 delay(10 + (MY_NODE_NUMBER * 5));
182 replyPongTo(senderAddress);
183 }
184}
185
186void replyPongTo(IPAddress targetAddress) {
187 // Send "pong" back to whoever sent "ping"
188 (*messageService).beginPacket(targetAddress, NETWORK_PORT);
189 (*messageService).write((const uint8_t*)"pong", 4);
190 (*messageService).endPacket();
191
192 Serial.println("🏓 Auto-replied: pong");
193}
194
195void showHeartbeat() {
196 static unsigned long lastHeartbeat = 0;
197
198 // Every 10 seconds, show we're still running
199 if (millis() - lastHeartbeat > 10000) {
200 lastHeartbeat = millis();
201 Serial.println("💓 [System running normally]");
202 }
203}

SPI/RS-485 Network Example

This example demonstrates a hierarchical control system where a central SPE controller manages multiple Arduino Opta boards through gateway nodes. The system uses SPE (Single Pair Ethernet) for the main network backbone and RS-485 for connecting to end devices, combining the benefits of modern Ethernet with the reliability of industrial serial communication.

The architecture consists of three layers: a central control node that issues commands, gateway nodes that translate between SPE and RS-485 protocols, and Opta boards that execute the actual control operations. This design allows for scalable industrial automation where multiple Opta boards can be distributed across a facility while being managed from a single control point.

Central Control Node (Server)

The central control node (Node 7) acts as the command center of the system, sending LED control commands to specific Opta boards through their associated gateway nodes. Operating on the SPE network, this node provides a simple serial interface where operators can type commands like "LED 3" to toggle the LEDs on remote Optas.

Central SPE Controller
Central SPE Controller

1// SPE Server Node 7 - Sends LED commands
2#include <Arduino_10BASE_T1S.h>
3#include <SPI.h>
4
5const uint8_t MY_ID = 7;
6
7IPAddress myIP(192, 168, 42, 107);
8IPAddress netmask(255, 255, 255, 0);
9IPAddress gateway(192, 168, 42, 100);
10
11TC6::TC6_Io* io;
12TC6::TC6_Arduino_10BASE_T1S* network;
13Arduino_10BASE_T1S_UDP* udp;
14
15void setup() {
16 Serial.begin(115200);
17 delay(1000);
18
19 Serial.println("\nSPE LED Control Server");
20 Serial.println("Type: LED 0, LED 1, etc.\n");
21
22 io = new TC6::TC6_Io(SPI, CS_PIN, RESET_PIN, IRQ_PIN);
23 network = new TC6::TC6_Arduino_10BASE_T1S(io);
24 udp = new Arduino_10BASE_T1S_UDP();
25
26 pinMode(IRQ_PIN, INPUT_PULLUP);
27 attachInterrupt(digitalPinToInterrupt(IRQ_PIN), []() {
28 io->onInterrupt();
29 }, FALLING);
30
31 io->begin();
32
33 MacAddress mac = MacAddress::create_from_uid();
34 T1SPlcaSettings plca(MY_ID);
35 T1SMacSettings mac_settings;
36
37 network->begin(myIP, netmask, gateway, mac, plca, mac_settings);
38 network->digitalWrite(TC6::DIO::A0, false);
39 network->digitalWrite(TC6::DIO::A1, false);
40
41 udp->begin(8888);
42
43 Serial.println("Ready!");
44}
45
46void loop() {
47 network->service();
48
49 if (Serial.available()) {
50 String cmd = Serial.readStringUntil('\n');
51 cmd.trim();
52 cmd.toUpperCase();
53
54 if (cmd.startsWith("LED ")) {
55 int node = cmd.substring(4).toInt();
56 IPAddress targetIP(192, 168, 42, 100 + node);
57
58 udp->beginPacket(targetIP, 8888);
59 udp->print(cmd);
60 udp->endPacket();
61
62 Serial.print("Sent to node ");
63 Serial.println(node);
64 }
65 }
66}

Transducer Node SPE/RS-485

The gateway nodes serve as protocol translators between the SPE network and RS-485 devices. Each gateway consists of an Arduino board with an SPE shield, where the board's hardware serial port (Serial1) connects to the RS-485 transceiver on the shield. These nodes receive UDP packets from the SPE network, extract the command data, and forward it to the RS-485 bus.

Shields Addressing the Endpoints Across Protocols
Shields Addressing the Endpoints Across Protocols

1// SPE/RS-485 Gateway
2#include <Arduino_10BASE_T1S.h>
3#include <SPI.h>
4
5const uint8_t MY_ID = 0; // Change for each gateway
6
7IPAddress myIP(192, 168, 42, 100 + MY_ID);
8IPAddress netmask(255, 255, 255, 0);
9IPAddress gateway(192, 168, 42, 100);
10
11TC6::TC6_Io* io;
12TC6::TC6_Arduino_10BASE_T1S* network;
13Arduino_10BASE_T1S_UDP* udp;
14
15void setup() {
16 Serial.begin(115200);
17 Serial1.begin(9600);
18 delay(1000);
19
20 Serial.print("\nGateway Node ");
21 Serial.println(MY_ID);
22
23 pinMode(7, OUTPUT); // RS485_DE
24 pinMode(8, OUTPUT); // RS485_RE
25 digitalWrite(7, HIGH);
26 digitalWrite(8, HIGH);
27
28 io = new TC6::TC6_Io(SPI, CS_PIN, RESET_PIN, IRQ_PIN);
29 network = new TC6::TC6_Arduino_10BASE_T1S(io);
30 udp = new Arduino_10BASE_T1S_UDP();
31
32 pinMode(IRQ_PIN, INPUT_PULLUP);
33 attachInterrupt(digitalPinToInterrupt(IRQ_PIN), []() {
34 io->onInterrupt();
35 }, FALLING);
36
37 io->begin();
38
39 MacAddress mac = MacAddress::create_from_uid();
40 T1SPlcaSettings plca(MY_ID);
41 T1SMacSettings mac_settings;
42
43 network->begin(myIP, netmask, gateway, mac, plca, mac_settings);
44 network->digitalWrite(TC6::DIO::A0, false);
45 network->digitalWrite(TC6::DIO::A1, false);
46
47 udp->begin(8888);
48
49 Serial.println("Ready!");
50}
51
52void loop() {
53 network->service();
54
55 if (udp->parsePacket()) {
56 char buffer[64] = {0};
57 udp->read((byte*)buffer, 63);
58
59 String cmd = String(buffer);
60 cmd.trim();
61
62 if (cmd == "LED " + String(MY_ID)) {
63 Serial1.println("T");
64 Serial1.flush();
65 Serial.println("Toggle sent");
66 }
67 }
68}

Opta RS-485 Interface

The Arduino Opta boards represent the end devices in this system, receiving commands via RS-485 and executing the requested actions.

Opta as Endpoint
Opta as Endpoint

When an Opta receives a command, it parses the instruction, performs the requested operation. This simple protocol allows the central SPE controller to remotely monitor and control multiple Opta boards across the RS-485 network, creating a flexible and scalable system.

1// Arduino Opta - Toggles built-in LED on command
2#include <ArduinoRS485.h>
3
4bool ledState = false;
5
6void setup() {
7 Serial.begin(115200); // USB debug
8 delay(2000);
9
10 Serial.println("\n=== Opta LED Controller ===");
11 Serial.println("Toggles built-in LED on command");
12
13 // Initialize RS-485 with delays
14 RS485.begin(9600);
15 RS485.setDelays(1000, 1000); // Pre and post delays in microseconds
16 RS485.receive(); // Set to receive mode
17
18 // Setup built-in LED
19 pinMode(LED_BUILTIN, OUTPUT);
20 digitalWrite(LED_BUILTIN, LOW);
21
22 // Flash LED to show ready
23 for (int i = 0; i < 3; i++) {
24 digitalWrite(LED_BUILTIN, HIGH);
25 delay(200);
26 digitalWrite(LED_BUILTIN, LOW);
27 delay(200);
28 }
29
30 Serial.println("Ready for commands!");
31}
32
33void loop() {
34 // Read RS-485 character by character
35 while (RS485.available()) {
36 char c = RS485.read();
37
38 // 0xDE = toggle
39 if ((byte)c == 0xDE) {
40 Serial.println("LED Toggle - received");
41 ledState = !ledState;
42 digitalWrite(LED_BUILTIN, ledState);
43 }
44 }
45}

Troubleshooting

Common Issues and Solutions

No Communication

  • Verify termination jumpers are correctly set (closed for P2P, only endpoints for multidrop)
  • Check cable connections and polarity
  • Ensure twisted pair cable is used

Intermittent Communication

  • Reduce cable length (maximum 25 m)
  • Check for proper grounding
  • Verify stub lengths in multidrop (< 5 cm)

Power Issues

  • When using PoDL, ensure power supply can provide sufficient current
  • Check voltage levels are within specification (7/24 VDC)
  • Verify Arduino board voltage compatibility

LED Indicators

The shield provides status LEDs for diagnostics:

  • PWR: Power status
  • SPE: Link activity
  • TX/RX: Data transmission indicators

Summary

In this guide, you've learned how to:

  • Set up the Arduino UNO SPE Shield for Single Pair Ethernet communication
  • Implement point-to-point and multidrop network configurations
  • Use Power over Data Line for remote device powering
  • Bridge industrial protocols like RS-485 over SPE
  • Troubleshoot common connectivity issues

The Arduino UNO SPE Shield opens up new possibilities for industrial IoT applications, providing reliable, cost-effective communication with minimal wiring requirements.

Next Steps

Suggest changes

The content on docs.arduino.cc is facilitated through a public GitHub repository. If you see anything wrong, you can edit this page here.

License

The Arduino documentation is licensed under the Creative Commons Attribution-Share Alike 4.0 license.