aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2025-09-15 16:29:17 +0000
committerGitHub <[email protected]>2025-09-15 16:29:17 +0000
commit92a6fd2946f2cbb15359290f68aa360953da2ff7 (patch)
treefa712b7c0aa26a1a1f21ea808665d016161d5722 /examples
parenta674030f13c5e5ccdcf48eafc10fcfc4cb3126a6 (diff)
parent1c080559fd20eb250e76278ff92d23432b5e0ce8 (diff)
Merge pull request #4658 from Riceman2000/main
Add example for W55RP20-EVB-Pico
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs155
1 files changed, 155 insertions, 0 deletions
diff --git a/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
new file mode 100644
index 000000000..f51df2df9
--- /dev/null
+++ b/examples/rp/src/bin/ethernet_w55rp20_tcp_server.rs
@@ -0,0 +1,155 @@
1//! This example implements a TCP echo server on port 1234 and using DHCP.
2//! Send it some data, you should see it echoed back and printed in the console.
3//!
4//! Example written for the [`WIZnet W55RP20-EVB-Pico`](https://docs.wiznet.io/Product/ioNIC/W55RP20/w55rp20-evb-pico) board.
5//! Note: the W55RP20 is a single package that contains both a RP2040 and the Wiznet W5500 ethernet
6//! controller
7
8#![no_std]
9#![no_main]
10
11use defmt::*;
12use embassy_executor::Spawner;
13use embassy_futures::yield_now;
14use embassy_net::{Stack, StackResources};
15use embassy_net_wiznet::chip::W5500;
16use embassy_net_wiznet::*;
17use embassy_rp::clocks::RoscRng;
18use embassy_rp::gpio::{Input, Level, Output, Pull};
19use embassy_rp::peripherals::PIO0;
20use embassy_rp::pio_programs::spi::Spi;
21use embassy_rp::spi::{Async, Config as SpiConfig};
22use embassy_rp::{bind_interrupts, pio};
23use embassy_time::{Delay, Duration};
24use embedded_hal_bus::spi::ExclusiveDevice;
25use embedded_io_async::Write;
26use static_cell::StaticCell;
27use {defmt_rtt as _, panic_probe as _};
28
29bind_interrupts!(struct Irqs {
30 PIO0_IRQ_0 => pio::InterruptHandler<PIO0>;
31});
32
33#[embassy_executor::task]
34async fn ethernet_task(
35 runner: Runner<
36 'static,
37 W5500,
38 ExclusiveDevice<Spi<'static, PIO0, 0, Async>, Output<'static>, Delay>,
39 Input<'static>,
40 Output<'static>,
41 >,
42) -> ! {
43 runner.run().await
44}
45
46#[embassy_executor::task]
47async fn net_task(mut runner: embassy_net::Runner<'static, Device<'static>>) -> ! {
48 runner.run().await
49}
50
51#[embassy_executor::main]
52async fn main(spawner: Spawner) {
53 let p = embassy_rp::init(Default::default());
54 let mut rng = RoscRng;
55 let mut led = Output::new(p.PIN_19, Level::Low);
56
57 // The W55RP20 uses a PIO unit for SPI communication, once the SPI bus has been formed using a
58 // PIO statemachine everything else is generally unchanged from the other examples that use the W5500
59 let mosi = p.PIN_23;
60 let miso = p.PIN_22;
61 let clk = p.PIN_21;
62
63 let pio::Pio { mut common, sm0, .. } = pio::Pio::new(p.PIO0, Irqs);
64
65 // Construct an SPI driver backed by a PIO state machine
66 let mut spi_cfg = SpiConfig::default();
67 spi_cfg.frequency = 12_500_000; // The PIO SPI program is much less stable than the actual SPI
68 // peripheral, use higher speeds at your peril
69 let spi = Spi::new(&mut common, sm0, clk, mosi, miso, p.DMA_CH0, p.DMA_CH1, spi_cfg);
70
71 // Further control pins
72 let cs = Output::new(p.PIN_20, Level::High);
73 let w5500_int = Input::new(p.PIN_24, Pull::Up);
74 let w5500_reset = Output::new(p.PIN_25, Level::High);
75
76 let mac_addr = [0x02, 0x00, 0x00, 0x00, 0x00, 0x00];
77 static STATE: StaticCell<State<8, 8>> = StaticCell::new();
78 let state = STATE.init(State::<8, 8>::new());
79 let (device, runner) = embassy_net_wiznet::new(
80 mac_addr,
81 state,
82 ExclusiveDevice::new(spi, cs, Delay),
83 w5500_int,
84 w5500_reset,
85 )
86 .await
87 .unwrap();
88 spawner.spawn(unwrap!(ethernet_task(runner)));
89
90 // Generate random seed
91 let seed = rng.next_u64();
92
93 // Init network stack
94 static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
95 let (stack, runner) = embassy_net::new(
96 device,
97 embassy_net::Config::dhcpv4(Default::default()),
98 RESOURCES.init(StackResources::new()),
99 seed,
100 );
101
102 // Launch network task
103 spawner.spawn(unwrap!(net_task(runner)));
104
105 info!("Waiting for DHCP...");
106 let cfg = wait_for_config(stack).await;
107 let local_addr = cfg.address.address();
108 info!("IP address: {:?}", local_addr);
109
110 let mut rx_buffer = [0; 4096];
111 let mut tx_buffer = [0; 4096];
112 let mut buf = [0; 4096];
113 loop {
114 let mut socket = embassy_net::tcp::TcpSocket::new(stack, &mut rx_buffer, &mut tx_buffer);
115 socket.set_timeout(Some(Duration::from_secs(10)));
116
117 led.set_low();
118 info!("Listening on TCP:1234...");
119 if let Err(e) = socket.accept(1234).await {
120 warn!("accept error: {:?}", e);
121 continue;
122 }
123 info!("Received connection from {:?}", socket.remote_endpoint());
124 led.set_high();
125
126 loop {
127 let n = match socket.read(&mut buf).await {
128 Ok(0) => {
129 warn!("read EOF");
130 break;
131 }
132 Ok(n) => n,
133 Err(e) => {
134 warn!("{:?}", e);
135 break;
136 }
137 };
138 info!("rxd {}", core::str::from_utf8(&buf[..n]).unwrap());
139
140 if let Err(e) = socket.write_all(&buf[..n]).await {
141 warn!("write error: {:?}", e);
142 break;
143 }
144 }
145 }
146}
147
148async fn wait_for_config(stack: Stack<'static>) -> embassy_net::StaticConfigV4 {
149 loop {
150 if let Some(config) = stack.config_v4() {
151 return config.clone();
152 }
153 yield_now().await;
154 }
155}