10000 Support wired network interfaces (W5500, W5100, ENC28J60) (#1703) · sleemanj/arduino-pico@1f3d501 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1f3d501

Browse files
Support wired network interfaces (W5500, W5100, ENC28J60) (earlephilhower#1703)
Enable use of wired Ethernet modules as first-class LWIP citizens. All networking classes like MDNS, WebServer, HTTPClient, WiFiClient, and OTA can use a wired Ethernet adapter just like built-in WiFi. Two examples updated to show proper use. Uses the Async Context support built into the Pico SDK. When running on the Pico it will use the CYW43 async instance. Uses modified wired Ethernet drivers, thanks Nicholas Humfrey! Note, the classic, non-LWIP integrated `Ethernet` and related libraries should still work fine (but not be able to use WebServer/HTTPS/etc.) Fixes earlephilhower#775
1 parent 3950b94 commit 1f3d501

File tree

43 files changed

+3739
-176
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3739
-176
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ The installed tools include a version of OpenOCD (in the pqt-openocd directory)
202202
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
203203
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
204204
* WiFi (Pico W)
205+
* Ethernet (Wired W5500, W5100, ENC28J60)
205206
* HTTP client and server (WebServer)
206207
* SSL/TLS/HTTPS
207208
* Over-the-Air (OTA) upgrades

cores/rp2040/lwip_wrap.cpp

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1919
*/
2020

21+
#include <Arduino.h>
2122
#include <pico/mutex.h>
2223
#include <lwip/pbuf.h>
2324
#include <lwip/udp.h>
@@ -26,20 +27,61 @@
2627
#include <lwip/raw.h>
2728
#include <lwip/timeouts.h>
2829
#include <pico/cyw43_arch.h>
30+
#include <pico/mutex.h>
31+
#include <sys/lock.h>
32+
33+
#if !defined(ARDUINO_RASPBERRY_PI_PICO_W)
34+
extern void ethernet_arch_lwip_begin() __attribute__((weak));
35+
extern void ethernet_arch_lwip_end() __attribute__((weak));
36+
37+
auto_init_recursive_mutex(__lwipMutex); // Only for non-PicoW case
38+
#endif
2939

3040
class LWIPMutex {
3141
public:
3242
LWIPMutex() {
33-
cyw43_arch_lwip_begin();
43+
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
44+
if (rp2040.isPicoW()) {
45+
cyw43_arch_lwip_begin();
46+
return;
47+
}
48+
#else
49+
if (ethernet_arch_lwip_begin) {
50+
ethernet_arch_lwip_begin();
51+
} else {
52+
recursive_mutex_enter_blocking(&__lwipMutex);
53+
}
54+
#endif
3455
}
3556

3657
~LWIPMutex() {
37-
cyw43_arch_lwip_end();
58+
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
59+
if (rp2040.isPicoW()) {
60+
cyw43_arch_lwip_end();
61+
return;
62+
}
63+
#else
64+
if (ethernet_arch_lwip_end) {
65+
ethernet_arch_lwip_end();
66+
} else {
67+
recursive_mutex_exit(&__lwipMutex);
68+
}
69+
#endif
3870
}
3971
};
4072

4173
extern "C" {
4274

75+
// Avoid calling lwip_init multiple times
76+
extern void __real_lwip_init();
77+
void __wrap_lwip_init() {
78+
static bool initted = false;
79+
if (!initted) {
80+
__real_lwip_init();
81+
initted = true;
82+
}
83+
}
84+
4385
extern u8_t __real_pbuf_header(struct pbuf *p, s16_t header_size);
4486
u8_t __wrap_pbuf_header(struct pbuf *p, s16_t header_size) {
4587
LWIPMutex m;

docs/ethernet.rst

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
EthernetLWIP (Wired Ethernet) Support
2+
=====================================
3+
4+
Wired Ethernet interfaces are supported for all the internal networking
5+
libraries (``WiFiClient``, ``WiFiClientSecure``, ``WiFiServer``,
6+
``WiFiServerSecure``, ``WiFiUDP``, ``WebServer``, ``Updater``,
7+
``HTTPClient``, etc.).
8+
9+
Using these wired interfaces is very similar to using the Pico-W WiFi
10+
so most examples in the core only require minor modifications to use
11+
a wired interface.
12+
13+
Supported Wired Ethernet Modules
14+
--------------------------------
15+
16+
* Wiznet W5100
17+
18+
* Wiznet W5500
19+
20+
* ENC28J60
21+
22+
23+
Enabling Wired Ethernet
24+
-----------------------
25+
26+
Simply replace the WiFi include at the top with:
27+
28+
.. code:: cpp
29+
30+
#include <W5500lwIP.h> // Or W5100lwIP.h or ENC28J60.h
31+
32+
33+
And add a global Ethernet object of the same type:
34+
35+
.. code:: cpp
36+
37+
Wiznet5500lwIP eth(1); // Parameter is the Chip Select pin
38+
39+
In your ``setup()`` you may adjust the SPI pins you're using to
40+
match your hardware (be sure they are legal for the RP2040!), or
41+
skip this if you're using the default ones:
42+
43+
.. code:: cpp
44+
45+
void setup() {
46+
SPI.setRX(0);
47+
SPI.setCS(1);
48+
SPI.setSCK(2);
49+
SPI.setTX(3);
50+
....
51+
}
52+
53+
And finally replace the ``WiFi.begin()`` and ``WiFi.connected()``
54+
calls with ``eth.begin()`` and ``eth.connected()``:
55+
56+
.. code:: cpp
57+
58+
void setup() {
59+
....
60+
// WiFi.begin(SSID, PASS)
61+
eth.begin();
62+
63+
//while (!WiFi.connected()) {
64+
while (!eth.connected()) {
65+
Serial.print(".");
66+
}
67+
68+
Serial.print("IP address: ");
69+
//Serial.println(WiFi.localIP());
70+
Serial.println(eth.localIP());
71+
72+
....
73+
}
74+
75+
Adjusting LWIP Polling
76+
----------------------
77+
78+
LWIP operates in a polling mode for the wired Ethernet devices. By default it will run
79+
every 20ms, meaning that on average it will take half that time (10ms) before a packet
80+
received in the Ethernet module is received and operated upon by the Pico. This gives
81+
very low CPU utilization but in some cases this latency can affect performance.
82+
83+
Adding a call to ``lwipPollingPeriod(XXX)`` (where ``XXXX`` is the polling period in
84+
milliseconds) can adjust this setting on the fly. Note that if you set it too low, the
85+
Pico may not have enough time to service the Ethernet port before the timer fires again,
86+
leading to a lock up and hang.
87+
88+
89+
Adjusting SPI Speed
90+
-------------------
91+
92+
By default a 4MHz clock will be used to clock data into and out of the Ethernet module.
93+
Depending on the module and your wiring, a higher SPI clock may increase performance (but
94+
too high of a clock will cause communications problems or hangs).
95+
96+
This value may be adjusted using the ``eth.setSPISpeed(hz)`` call **before** starting the
97+
device. (You may also use custom ``SPISettings`` instead via ``eth.setSPISettings(spis)```)
98+
99+
For example, to set the W5500 to use a 30MHZ clock:
100+
101+
.. code:: cpp
102+
103+
#include <W5500lwIP.h>
104+
Wiznet5500lwIP eth(1);
105+
106+
void setup() {
107+
eth.setSPISpeed(30000000);
108+
lwipPollingPeriod(3);
109+
...
110+
eth.begin();
111+
...
112+
}
113+
114+
115+
Example Code
116+
------------
117+
118+
The following examples allow switching between WiFi and Ethernet:
119+
120+
* ``WebServer/AdvancedWebServer``
121+
122+
* ``HTTPClient/BasicHTTPSClient``
123+
124+
Caveats
125+
-------
126+
127+
The same restrictions for ``WiFi`` apply to these Ethernet classes, namely:
128+
129+
* Only core 0 may run any networking related code.
130+
131+
* In FreeRTOS, only the ``setup`` and ``loop`` task can call networking libraries, not any tasks.
132+
133+
Special Thanks
134+
--------------
135+
136+
* LWIPEthernet classes come from the ESP8266 Arduino team
137+
138+
* Individual Ethernet drivers were written by Nicholas Humfrey
139+

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
5050
FreeRTOS SMP (multicore) <freertos>
5151

5252
WiFi (Pico-W Support) <wifi>
53+
Ethernet (Wired) <ethernet>
5354
WiFiClient <wificlient>
5455
WiFiServer <wifiserver>
5556
WiFiUDP <wifiudp>

lib/platform_wrap.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,8 @@
152152
-Wl,--wrap=realloc
153153
-Wl,--wrap=free
154154

155+
-Wl,--wrap=lwip_init
156+
155157
-Wl,--wrap=pbuf_header
156158
-Wl,--wrap=pbuf_free
157159
-Wl,--wrap=pbuf_alloc

libraries/HTTPClient/examples/BasicHttpsClient/BasicHttpsClient.ino

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@
66
*/
77

88
#include <Arduino.h>
9+
10+
11+
// Example works with either Wired or WiFi Ethernet, define one of these values to 1, other to 0
12+
#define USE_WIFI 1
13+
#define USE_WIRED 0
14+
15+
#if USE_WIFI
916
#include <WiFi.h>
17+
#elif USE_WIRED
18+
#include <W5500lwIP.h> // Or W5100lwIP.h or ENC28J60lwIP.h
19+
Wiznet5500lwIP eth(1 /* chip select */); // or Wiznet5100lwIP or ENC28J60lwIP
20+
#endif
21+
1022
#include <HTTPClient.h>
1123

1224
#ifndef STASSID
@@ -34,8 +46,33 @@ void setup() {
3446
delay(1000);
3547
}
3648

49+
#if USE_WIFI
3750
WiFi.mode(WIFI_STA);
3851
WiFiMulti.addAP(ssid, pass);
52+
#elif USE_WIRED
53+
// Set up SPI pinout to match your HW
54+
SPI.setRX(0);
55+
SPI.setCS(1);
56+
SPI.setSCK(2);
57+
SPI.setTX(3);
58+
59+
// Start the Ethernet port
60+
if (!eth.begin()) {
61+
Serial.println("No wired Ethernet hardware detected. Check pinouts, wiring.");
62+
while (1) {
63+
delay(1000);
64+
}
65+
}
66+
67+
// Wait for connection
68+
while (eth.status() != WL_CONNECTED) {
69+
delay(500);
70+
Serial.print(".");
71+
}
72+
Serial.print("IP address: ");
73+
Serial.println(eth.localIP());
74+
#endif
75+
3976
}
4077

4178
const char *jigsaw_cert = R"EOF(
@@ -74,8 +111,12 @@ N6K5xrmaof185pVCxACPLc/BoKyUwMeC8iXCm00=
74111
static int cnt = 0;
75112

76113
void loop() {
77-
// wait for WiFi connection
78-
if ((WiFiMulti.run() == WL_CONNECTED)) {
114+
#if USE_WIFI
115+
// wait for WiFi connection
116+
if ((WiFiMulti.run() == WL_CONNECTED)) {
117+
#elif USE_WIRED
118+
if (eth.connected()) {
119+
#endif
79120
HTTPClient https;
80121
switch (cnt) {
81122
case 0:

libraries/WebServer/examples/AdvancedWebServer/AdvancedWebServer.ino

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,17 @@
2828
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2929
*/
3030

31+
// Example works with either Wired or WiFi Ethernet, define one of these values to 1, other to 0
32+
#define USE_WIFI 1
33+
#define USE_WIRED 0
34+
35+
#if USE_WIFI
3136
#include <WiFi.h>
37+
#elif USE_WIRED
38+
#include <W5500lwIP.h> // Or W5100lwIP.h or ENC28J60lwIP.h
39+
Wiznet5500lwIP eth(1 /* chip select */); // or Wiznet5100lwIP or ENC28J60lwIP
40+
#endif
41+
3242
#include <WiFiClient.h>
3343
#include <WebServer.h>
3444
#include <LEAmDNS.h>
@@ -58,13 +68,13 @@ void handleRoot() {
5868
temp.printf("<html>\
5969
<head>\
6070
<meta http-equiv='refresh' content='5'/>\
61-
<title>Pico-W Demo</title>\
71+
<title>" BOARD_NAME " Demo</title>\
6272
<style>\
6373
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
6474
</style>\
6575
</head>\
6676
<body>\
67-
<h1>Hello from the Pico W!</h1>\
77+
<h1>Hello from the " BOARD_NAME "!</h1>\
6878
<p>Uptime: %02d:%02d:%02d</p>\
6979
<p>Free Memory: %d</p>\
7080
<p>Page Count: %d</p>\
@@ -117,6 +127,8 @@ void setup(void) {
117127
pinMode(led, OUTPUT);
118128
digitalWrite(led, 0);
119129
Serial.begin(115200);
130+
131+
#if USE_WIFI
120132
WiFi.mode(WIFI_STA);
121133
WiFi.begin(ssid, password);
122134
Serial.println("");
@@ -130,8 +142,32 @@ void setup(void) {
130142
Serial.println("");
131143
Serial.print("Connected to ");
132144
Serial.println(ssid);
145+
133146
Serial.print("IP address: ");
134147
Serial.println(WiFi.localIP());
148+
#elif USE_WIRED
149+
// Set up SPI pinout to match your HW
150+
SPI.setRX(0);
151+
SPI.setCS(1);
152+
SPI.setSCK(2);
153+
SPI.setTX(3);
154+
155+
// Start the Ethernet port
156+
if (!eth.begin()) {
157+
Serial.println("No wired Ethernet hardware detected. Check pinouts, wiring.");
158+
while (1) {
159+
delay(1000);
160+
}
161+
}
162+
163+
// Wait for connection
164+
while (eth.status() != WL_CONNECTED) {
165+
delay(500);
166+
Serial.print(".");
167+
}
168+
Serial.print("IP address: ");
169+
Serial.println(eth.localIP());
170+
#endif
135171

136172
if (MDNS.begin("picow")) {
137173
Serial.println("MDNS responder started");

libraries/WiFi/examples/WiFiClient/WiFiClient.ino

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void loop() {
6161
// This will send a string to the server
6262
Serial.println("sending data to server");
6363
if (client.connected()) {
64-
client.println("hello from ESP8266");
64+
client.println("hello from RP2040");
6565
}
6666

6767
// wait for data to be available

0 commit comments

Comments
 (0)
0