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