Skip to content

Commit 39e9a79

Browse files
cvaldessclaude
andcommitted
feat: add Raspberry Pi Pico 2 + W5500 + E22-900M30S variant
Adds community variant for Raspberry Pi Pico 2 (RP2350, 4 MB flash) with external WIZnet W5500 Ethernet module and EBYTE E22-900M30S LoRa module (SX1262, 30 dBm PA, 868/915 MHz). Key details: - LoRa on SPI1: GP10/11/12/13 (SCK/MOSI/MISO/CS), RST=GP15, DIO1=GP14, BUSY=GP2, RXEN=GP3 (held HIGH via SX126X_ANT_SW) - W5500 on SPI0: GP16/17/18/19/20 (MISO/CS/SCK/MOSI/RST) - SX126X_DIO2_AS_RF_SWITCH: DIO2→TXEN bridge on module handles PA - SX126X_DIO3_TCXO_VOLTAGE 1.8: TCXO support via EBYTE_E22 flags - DHCP timeout reduced to 10 s to avoid blocking LoRa startup - GPS on UART1/Serial2: GP8 TX, GP9 RX - Reuses WIZNET_5500_EVB_PICO2 code paths for Ethernet init Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 3a87e74 commit 39e9a79

8 files changed

Lines changed: 523 additions & 3 deletions

File tree

src/DebugConfiguration.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ extern "C" void logLegacy(const char *level, const char *fmt, ...);
147147
// Default Bluetooth PIN
148148
#define defaultBLEPin 123456
149149

150-
#if HAS_ETHERNET && !defined(USE_WS5500)
150+
#if HAS_ETHERNET && defined(WIZNET_5500_EVB_PICO2)
151+
#include <Ethernet.h> // arduino-libraries/Ethernet — supports W5500 auto-detect
152+
#elif HAS_ETHERNET && !defined(USE_WS5500)
151153
#include <RAK13800_W5100S.h>
152154
#endif // HAS_ETHERNET
153155

src/mesh/api/ethServerAPI.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
#pragma once
22

33
#include "ServerAPI.h"
4-
#ifndef USE_WS5500
4+
#if !defined(USE_WS5500)
5+
#if defined(WIZNET_5500_EVB_PICO2)
6+
#include <Ethernet.h>
7+
#else
58
#include <RAK13800_W5100S.h>
9+
#endif
610

711
/**
812
* Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs

src/mesh/eth/ethClient.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
#include "main.h"
77
#include "mesh/api/ethServerAPI.h"
88
#include "target_specific.h"
9+
#ifdef WIZNET_5500_EVB_PICO2
10+
#include <Ethernet.h> // arduino-libraries/Ethernet — supports W5100/W5200/W5500
11+
#else
912
#include <RAK13800_W5100S.h>
13+
#endif
1014
#include <SPI.h>
1115

1216
#if HAS_NETWORKING
@@ -69,13 +73,21 @@ static int32_t reconnectETH()
6973
delay(100);
7074
#endif
7175

76+
#ifdef WIZNET_5500_EVB_PICO2 // Re-configure SPI0 for the on-board W5500
77+
SPI.setRX(ETH_SPI0_MISO);
78+
SPI.setSCK(ETH_SPI0_SCK);
79+
SPI.setTX(ETH_SPI0_MOSI);
80+
SPI.begin();
81+
Ethernet.init(PIN_ETHERNET_SS);
82+
#else
7283
#ifdef RAK11310
7384
ETH_SPI_PORT.setSCK(PIN_SPI0_SCK);
7485
ETH_SPI_PORT.setTX(PIN_SPI0_MOSI);
7586
ETH_SPI_PORT.setRX(PIN_SPI0_MISO);
7687
ETH_SPI_PORT.begin();
7788
#endif
7889
Ethernet.init(ETH_SPI_PORT, PIN_ETHERNET_SS);
90+
#endif
7991

8092
int status = 0;
8193
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_DHCP) {
@@ -182,13 +194,21 @@ bool initEthernet()
182194
digitalWrite(PIN_ETHERNET_RESET, HIGH); // Reset Time.
183195
#endif
184196

197+
#ifdef WIZNET_5500_EVB_PICO2 // Configure SPI0 for the on-board W5500
198+
SPI.setRX(ETH_SPI0_MISO);
199+
SPI.setSCK(ETH_SPI0_SCK);
200+
SPI.setTX(ETH_SPI0_MOSI);
201+
SPI.begin();
202+
Ethernet.init(PIN_ETHERNET_SS);
203+
#else
185204
#ifdef RAK11310 // Initialize the SPI port
186205
ETH_SPI_PORT.setSCK(PIN_SPI0_SCK);
187206
ETH_SPI_PORT.setTX(PIN_SPI0_MOSI);
188207
ETH_SPI_PORT.setRX(PIN_SPI0_MISO);
189208
ETH_SPI_PORT.begin();
190209
#endif
191210
Ethernet.init(ETH_SPI_PORT, PIN_ETHERNET_SS);
211+
#endif
192212

193213
uint8_t mac[6];
194214

@@ -201,7 +221,7 @@ bool initEthernet()
201221

202222
if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_DHCP) {
203223
LOG_INFO("Start Ethernet DHCP");
204-
status = Ethernet.begin(mac);
224+
status = Ethernet.begin(mac, 10000); // 10s timeout instead of default 60s
205225
} else if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC) {
206226
LOG_INFO("Start Ethernet Static");
207227
Ethernet.begin(mac, config.network.ipv4_config.ip, config.network.ipv4_config.dns, config.network.ipv4_config.gateway,

src/platform/rp2xx0/architecture.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
#define HW_VENDOR meshtastic_HardwareModel_RP2040_LORA
3434
#elif defined(RP2040_FEATHER_RFM95)
3535
#define HW_VENDOR meshtastic_HardwareModel_RP2040_FEATHER_RFM95
36+
#elif defined(WIZNET_5500_EVB_PICO2)
37+
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
3638
#elif defined(PRIVATE_HW)
3739
#define HW_VENDOR meshtastic_HardwareModel_PRIVATE_HW
3840
#endif
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Raspberry Pi Pico 2 + W5500 + E22-900M30S — Meshtastic Variant
2+
3+
Meshtastic support for a **Raspberry Pi Pico 2** (RP2350, 4 MB flash) with an external **W5500** Ethernet module and an **EBYTE E22-900M30S** LoRa module.
4+
5+
---
6+
7+
## Required Hardware
8+
9+
| Component | Model | Notes |
10+
|-----------|-------------------------------|------------------------------------------|
11+
| MCU | Raspberry Pi Pico 2 | RP2350 @ 150 MHz, 512 KB RAM, 4 MB flash |
12+
| Ethernet | W5500 module | Any WIZnet W5500 breakout board |
13+
| LoRa | EBYTE E22-900M30S | SX1262 + 30 dBm PA, 868/915 MHz |
14+
15+
---
16+
17+
## Pinout
18+
19+
### System pins (Pico 2, fixed)
20+
21+
| GPIO | Function |
22+
|------|-----------------------------------------------|
23+
| GP24 | VBUS sense — HIGH when USB is connected |
24+
| GP25 | User LED (heartbeat) |
25+
| GP29 | ADC3 — VSYS/3, measures supply voltage |
26+
27+
### W5500 Ethernet (SPI0)
28+
29+
| W5500 signal | Pico 2 GPIO |
30+
|--------------|-------------|
31+
| MISO | GP16 |
32+
| CS / SCS | GP17 |
33+
| SCK | GP18 |
34+
| MOSI | GP19 |
35+
| RST | GP20 |
36+
| INT | — (nc) |
37+
| VCC | 3.3V |
38+
| GND | GND |
39+
40+
> SPI0 is reserved for the W5500.
41+
42+
### E22-900M30S LoRa (SPI1)
43+
44+
| E22 signal | Pico 2 GPIO | Notes |
45+
|------------|-------------|------------------------------------------------|
46+
| SCK | GP10 | SPI1 clock |
47+
| MOSI | GP11 | SPI1 TX |
48+
| MISO | GP12 | SPI1 RX |
49+
| NSS / CS | GP13 | Chip select |
50+
| RESET | GP15 | Active LOW reset |
51+
| DIO1 | GP14 | IRQ interrupt |
52+
| BUSY | GP2 | Module busy indicator |
53+
| RXEN | GP3 | LNA enable — held HIGH permanently |
54+
| TXEN | ← DIO2 | See wiring note below |
55+
| VCC | 3.3V | Add a 100 µF capacitor close to the module |
56+
| GND | GND ||
57+
58+
> See `wiring.svg` in this directory for the full connection diagram.
59+
60+
---
61+
62+
## Special wiring: DIO2 → TXEN bridge on the E22 module
63+
64+
The E22-900M30S does **not** connect DIO2 to the TXEN pin of its PA internally. They must be bridged with a short wire or solder bridge **on the module itself**:
65+
66+
```
67+
E22 DIO2 pin ──┐
68+
├── wire / solder bridge on the module
69+
E22 TXEN pin ──┘
70+
```
71+
72+
With this bridge in place, `SX126X_DIO2_AS_RF_SWITCH` causes the SX1262 to drive DIO2 HIGH automatically during TX, enabling the PA without needing an RP2350 GPIO for TXEN.
73+
74+
**Without this bridge the module will not transmit.**
75+
76+
---
77+
78+
## Build
79+
80+
```bash
81+
pio run -e pico2_w5500_e22
82+
```
83+
84+
### Flash — BOOTSEL mode
85+
86+
1. Hold the **BOOTSEL** button on the Pico 2.
87+
2. Connect USB to the PC — it appears as a `RPI-RP2` storage drive.
88+
3. Copy the `.uf2` file:
89+
90+
```
91+
.pio/build/pico2_w5500_e22/firmware-pico2_w5500_e22-*.uf2
92+
```
93+
94+
Or directly with picotool:
95+
96+
```bash
97+
pio run -e pico2_w5500_e22 -t upload
98+
```
99+
100+
---
101+
102+
## Network usage
103+
104+
This board uses Ethernet (no Wi-Fi). From the Meshtastic app:
105+
106+
- **Enable Ethernet** under `Config → Network → Ethernet Enabled`
107+
- **DHCP** by default; static IP can also be configured
108+
109+
Services available once connected:
110+
111+
| Service | Details |
112+
|---------|-----------------------------|
113+
| NTP | Time synchronization |
114+
| MQTT | Messages to external broker |
115+
| API | TCP socket on port 4403 |
116+
| Syslog | Remote logging (optional) |
117+
118+
---
119+
120+
## Technical notes
121+
122+
### LoRa — RF control
123+
124+
| Define | Effect |
125+
|--------------------------------|---------------------------------------------------------------|
126+
| `SX126X_ANT_SW 3` | GP3 (RXEN) driven HIGH at init and never toggled again |
127+
| `SX126X_DIO2_AS_RF_SWITCH` | SX1262 drives DIO2 HIGH during TX → enables TXEN via bridge |
128+
| `SX126X_DIO3_TCXO_VOLTAGE 1.8` | E22 TCXO controlled by DIO3 |
129+
| `-D EBYTE_E22` | Enables TCXO support in firmware |
130+
| `-D EBYTE_E22_900M30S` | Sets `TX_GAIN_LORA=10`, max power 22 dBm |
131+
132+
> RXEN and TXEN may both be HIGH simultaneously during TX — this is safe for the E22 RF switch.
133+
134+
### Ethernet
135+
136+
- Library: `arduino-libraries/Ethernet@^2.0.2` (supports W5100/W5200/W5500 auto-detection).
137+
- SPI0 is explicitly initialized with pins GP16/18/19 before `Ethernet.init()`.
138+
- DHCP timeout is set to 10 s (instead of the default 60 s) to avoid blocking LoRa startup.
139+
140+
### HW_VENDOR
141+
142+
Mapped to `meshtastic_HardwareModel_PRIVATE_HW` — no dedicated model exists in the Meshtastic protobuf for this hardware combination yet.
143+
144+
---
145+
146+
## Memory usage (reference build)
147+
148+
| Resource | Used | Total | % |
149+
|----------|---------|----------|-------|
150+
| RAM | 94 KB | 512 KB | 18% |
151+
| Flash | 964 KB | 3.58 MB | 26.3% |
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[env:pico2_w5500_e22]
2+
extends = rp2350_base
3+
board = rpipico2
4+
board_level = community
5+
upload_protocol = picotool
6+
7+
build_flags =
8+
${rp2350_base.build_flags}
9+
-ULED_BUILTIN # avoid "LED_BUILTIN redefined" warnings from framework common.h
10+
-D WIZNET_5500_EVB_PICO2 # reuse same code paths as EVB variant
11+
-I variants/rp2350/pico2_w5500_e22
12+
-D DEBUG_RP2040_PORT=Serial
13+
-D HW_SPI1_DEVICE
14+
-D EBYTE_E22 # activates TCXO support (SX126X_DIO3_TCXO_VOLTAGE)
15+
-D EBYTE_E22_900M30S # activates TX_GAIN_LORA=7 / SX126X_MAX_POWER=22
16+
17+
# Re-enable Ethernet and API source paths excluded in rp2350_base
18+
build_src_filter = ${rp2350_base.build_src_filter} +<mesh/eth/> +<mesh/api/> +<mqtt/>
19+
20+
lib_deps =
21+
${rp2350_base.lib_deps}
22+
${networking_base.lib_deps}
23+
${networking_extra.lib_deps}
24+
# Standard WIZnet Ethernet library — supports W5100/W5200/W5500 auto-detect
25+
arduino-libraries/Ethernet@^2.0.2
26+
27+
debug_build_flags = ${rp2350_base.build_flags}, -g
28+
debug_tool = cmsis-dap
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Raspberry Pi Pico 2 + external W5500 Ethernet module + EBYTE E22-900M30S
2+
// RP2350 (4 MB flash) — wire modules to the GPIO pins listed below
3+
//
4+
// LoRa (SX1262 / E22-900M30S) on SPI1:
5+
// SCK=GP10 MOSI=GP11 MISO=GP12 CS=GP13
6+
// RST=GP15 DIO1/IRQ=GP14 BUSY=GP2 RXEN=GP3
7+
// TXEN: bridge E22_DIO2 → E22_TXEN on the module (no RP2350 GPIO needed)
8+
//
9+
// W5500 Ethernet on SPI0:
10+
// MISO=GP16 CS=GP17 SCK=GP18 MOSI=GP19 RST=GP20
11+
//
12+
// See wiring.svg in this directory for a complete connection diagram.
13+
14+
#define ARDUINO_ARCH_AVR
15+
16+
// Onboard LED (GP25 on Pico 2)
17+
#define LED_POWER PIN_LED
18+
19+
// Power monitoring
20+
// GP24: VBUS sense – HIGH when USB is present (digital read)
21+
// GP29: ADC3 measures VSYS/3 (200 kΩ / 100 kΩ divider, same as standard Pico 2)
22+
#define EXT_PWR_DETECT 24
23+
#define BATTERY_PIN 29
24+
#define ADC_MULTIPLIER 3.0
25+
#define BATTERY_SENSE_RESOLUTION_BITS 12
26+
// No real battery — suppress false "battery at 100%" while USB powers VSYS
27+
#define NO_BATTERY_LEVEL_ON_CHARGE
28+
29+
// Optional user button — connect a button between GP6 and GND
30+
// #define BUTTON_PIN 6
31+
// #define BUTTON_NEED_PULLUP
32+
33+
// GPS on UART1 (Serial2) — GP8 TX, GP9 RX
34+
// GP8/GP9 belong to UART1, so we must use Serial2 (not the default Serial1/UART0).
35+
// GP0/GP1 (UART0 defaults) are free but the firmware treats pin 0 as "not configured".
36+
// GP4/GP5 occupied by I2C (SCL/SDA for BMP-280).
37+
#define HAS_GPS 1
38+
#define GPS_TX_PIN 8
39+
#define GPS_RX_PIN 9
40+
#define GPS_BAUDRATE 38400
41+
#define GPS_SERIAL_PORT Serial2
42+
43+
// ---- EBYTE E22-900M30S on SPI1 -----------------------------------------
44+
#define USE_SX1262
45+
46+
#undef LORA_SCK
47+
#undef LORA_MISO
48+
#undef LORA_MOSI
49+
#undef LORA_CS
50+
51+
#define LORA_SCK 10
52+
#define LORA_MOSI 11
53+
#define LORA_MISO 12
54+
#define LORA_CS 13
55+
56+
#define LORA_DIO0 RADIOLIB_NC
57+
#define LORA_RESET 15
58+
#define LORA_DIO1 14 // IRQ
59+
#define LORA_DIO2 2 // BUSY
60+
#define LORA_DIO3 RADIOLIB_NC
61+
62+
#ifdef USE_SX1262
63+
#define SX126X_CS LORA_CS
64+
#define SX126X_DIO1 LORA_DIO1
65+
#define SX126X_BUSY LORA_DIO2
66+
#define SX126X_RESET LORA_RESET
67+
// GP3 = RXEN: driven HIGH at init and held there (LNA always enabled).
68+
// SX1262 drives DIO2 HIGH during TX → TXEN via bridge on E22 module.
69+
#define SX126X_ANT_SW 3
70+
#define SX126X_DIO2_AS_RF_SWITCH
71+
#define SX126X_DIO3_TCXO_VOLTAGE 1.8
72+
#endif
73+
74+
// ---- W5500 Ethernet on SPI0 --------------------------------------------
75+
#define HAS_ETHERNET 1
76+
77+
#define ETH_SPI0_MISO 16
78+
#define ETH_SPI0_SCK 18
79+
#define ETH_SPI0_MOSI 19
80+
81+
#define PIN_ETHERNET_RESET 20
82+
#define PIN_ETHERNET_SS 17
83+
#define ETH_SPI_PORT SPI

0 commit comments

Comments
 (0)