aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorkalkyl <[email protected]>2023-05-09 01:51:08 +0200
committerkalkyl <[email protected]>2023-05-09 01:51:08 +0200
commit72b0379125b87bcd274bdb81127dd5f0ab29d661 (patch)
treeb620d67bc9ea930051668d63190dd6de62485b0a /src
:rainbow:
Diffstat (limited to 'src')
-rw-r--r--src/device.rs161
-rw-r--r--src/lib.rs114
-rw-r--r--src/socket.rs114
-rw-r--r--src/spi.rs37
4 files changed, 426 insertions, 0 deletions
diff --git a/src/device.rs b/src/device.rs
new file mode 100644
index 000000000..3875fde0e
--- /dev/null
+++ b/src/device.rs
@@ -0,0 +1,161 @@
1use crate::socket;
2use crate::spi::SpiInterface;
3use embedded_hal_async::spi::SpiDevice;
4
5pub const MODE: u16 = 0x00;
6pub const MAC: u16 = 0x09;
7pub const SOCKET_INTR: u16 = 0x18;
8pub const PHY_CFG: u16 = 0x2E;
9
10#[repr(u8)]
11pub enum RegisterBlock {
12 Common = 0x00,
13 Socket0 = 0x01,
14 TxBuf = 0x02,
15 RxBuf = 0x03,
16}
17
18/// W5500 in MACRAW mode
19#[derive(Debug)]
20#[cfg_attr(feature = "defmt", derive(defmt::Format))]
21pub struct W5500<SPI> {
22 bus: SpiInterface<SPI>,
23}
24
25impl<SPI: SpiDevice> W5500<SPI> {
26 /// Create and initialize the W5500 driver
27 pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<W5500<SPI>, SPI::Error> {
28 let mut bus = SpiInterface(spi);
29 // Reset device
30 bus.write_frame(RegisterBlock::Common, MODE, &[0x80])
31 .await?;
32
33 // Enable interrupt pin
34 bus.write_frame(RegisterBlock::Common, SOCKET_INTR, &[0x01])
35 .await?;
36 // Enable receive interrupt
37 bus.write_frame(
38 RegisterBlock::Socket0,
39 socket::SOCKET_INTR_MASK,
40 &[socket::Interrupt::Receive as u8],
41 )
42 .await?;
43
44 // Set MAC address
45 bus.write_frame(RegisterBlock::Common, MAC, &mac_addr)
46 .await?;
47
48 // Set the raw socket RX/TX buffer sizes to 16KB
49 bus.write_frame(RegisterBlock::Socket0, socket::TXBUF_SIZE, &[16])
50 .await?;
51 bus.write_frame(RegisterBlock::Socket0, socket::RXBUF_SIZE, &[16])
52 .await?;
53
54 // MACRAW mode with MAC filtering.
55 let mode: u8 = (1 << 2) | (1 << 7);
56 bus.write_frame(RegisterBlock::Socket0, socket::MODE, &[mode])
57 .await?;
58 socket::command(&mut bus, socket::Command::Open).await?;
59
60 Ok(Self { bus })
61 }
62
63 /// Read bytes from the RX buffer. Returns the number of bytes read.
64 async fn read_bytes(&mut self, buffer: &mut [u8], offset: u16) -> Result<usize, SPI::Error> {
65 let rx_size = socket::get_rx_size(&mut self.bus).await? as usize;
66
67 let read_buffer = if rx_size > buffer.len() + offset as usize {
68 buffer
69 } else {
70 &mut buffer[..rx_size - offset as usize]
71 };
72
73 let read_ptr = socket::get_rx_read_ptr(&mut self.bus)
74 .await?
75 .wrapping_add(offset);
76 self.bus
77 .read_frame(RegisterBlock::RxBuf, read_ptr, read_buffer)
78 .await?;
79 socket::set_rx_read_ptr(
80 &mut self.bus,
81 read_ptr.wrapping_add(read_buffer.len() as u16),
82 )
83 .await?;
84
85 Ok(read_buffer.len())
86 }
87
88 /// Read an ethernet frame from the device. Returns the number of bytes read.
89 pub async fn read_frame(&mut self, frame: &mut [u8]) -> Result<usize, SPI::Error> {
90 let rx_size = socket::get_rx_size(&mut self.bus).await? as usize;
91 if rx_size == 0 {
92 return Ok(0);
93 }
94
95 socket::reset_interrupt(&mut self.bus, socket::Interrupt::Receive).await?;
96
97 // First two bytes gives the size of the received ethernet frame
98 let expected_frame_size: usize = {
99 let mut frame_bytes = [0u8; 2];
100 assert!(self.read_bytes(&mut frame_bytes[..], 0).await? == 2);
101 u16::from_be_bytes(frame_bytes) as usize - 2
102 };
103
104 // Read the ethernet frame
105 let read_buffer = if frame.len() > expected_frame_size {
106 &mut frame[..expected_frame_size]
107 } else {
108 frame
109 };
110
111 let recvd_frame_size = self.read_bytes(read_buffer, 2).await?;
112
113 // Register RX as completed
114 socket::command(&mut self.bus, socket::Command::Receive).await?;
115
116 // If the whole frame wasn't read, drop it
117 if recvd_frame_size < expected_frame_size {
118 Ok(0)
119 } else {
120 Ok(recvd_frame_size)
121 }
122 }
123
124 /// Write an ethernet frame to the device. Returns number of bytes written
125 pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> {
126 let max_size = socket::get_tx_free_size(&mut self.bus).await? as usize;
127
128 let write_data = if frame.len() < max_size {
129 frame
130 } else {
131 &frame[..max_size]
132 };
133
134 let write_ptr = socket::get_tx_write_ptr(&mut self.bus).await?;
135 self.bus
136 .write_frame(RegisterBlock::TxBuf, write_ptr, write_data)
137 .await?;
138 socket::set_tx_write_ptr(
139 &mut self.bus,
140 write_ptr.wrapping_add(write_data.len() as u16),
141 )
142 .await?;
143
144 socket::reset_interrupt(&mut self.bus, socket::Interrupt::SendOk).await?;
145 socket::command(&mut self.bus, socket::Command::Send).await?;
146 // Wait for TX to complete
147 while !socket::is_interrupt(&mut self.bus, socket::Interrupt::SendOk).await? {}
148 socket::reset_interrupt(&mut self.bus, socket::Interrupt::SendOk).await?;
149
150 Ok(write_data.len())
151 }
152
153 pub async fn is_link_up(&mut self) -> bool {
154 let mut link = [0];
155 self.bus
156 .read_frame(RegisterBlock::Common, PHY_CFG, &mut link)
157 .await
158 .ok();
159 link[0] & 1 == 1
160 }
161}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 000000000..bf14b05b4
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,114 @@
1#![no_std]
2/// [`embassy-net`](crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip.
3mod device;
4mod socket;
5mod spi;
6
7use crate::device::W5500;
8use embassy_futures::select::{select, Either};
9use embassy_net_driver_channel as ch;
10use embassy_net_driver_channel::driver::LinkState;
11use embassy_time::{Duration, Timer};
12use embedded_hal::digital::OutputPin;
13use embedded_hal_async::digital::Wait;
14use embedded_hal_async::spi::SpiDevice;
15const MTU: usize = 1514;
16
17/// Type alias for the embassy-net driver for W5500
18pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>;
19
20/// Internal state for the embassy-net integration.
21pub struct State<const N_RX: usize, const N_TX: usize> {
22 ch_state: ch::State<MTU, N_RX, N_TX>,
23}
24
25impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> {
26 /// Create a new `State`.
27 pub const fn new() -> Self {
28 Self {
29 ch_state: ch::State::new(),
30 }
31 }
32}
33
34/// Background runner for the W5500.
35///
36/// You must call `.run()` in a background task for the W5500 to operate.
37pub struct Runner<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> {
38 mac: W5500<SPI>,
39 ch: ch::Runner<'d, MTU>,
40 int: INT,
41 _reset: RST,
42}
43
44/// You must call this in a background task for the W5500 to operate.
45impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> {
46 pub async fn run(mut self) -> ! {
47 let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split();
48 loop {
49 if self.mac.is_link_up().await {
50 state_chan.set_link_state(LinkState::Up);
51 loop {
52 match select(
53 async {
54 self.int.wait_for_low().await.ok();
55 rx_chan.rx_buf().await
56 },
57 tx_chan.tx_buf(),
58 )
59 .await
60 {
61 Either::First(p) => {
62 if let Ok(n) = self.mac.read_frame(p).await {
63 rx_chan.rx_done(n);
64 }
65 }
66 Either::Second(p) => {
67 self.mac.write_frame(p).await.ok();
68 tx_chan.tx_done();
69 }
70 }
71 }
72 } else {
73 state_chan.set_link_state(LinkState::Down);
74 }
75 }
76 }
77}
78
79/// Obtain a driver for using the W5500 with [`embassy-net`](crates.io/crates/embassy-net).
80pub async fn new<
81 'a,
82 const N_RX: usize,
83 const N_TX: usize,
84 SPI: SpiDevice,
85 INT: Wait,
86 RST: OutputPin,
87>(
88 mac_addr: [u8; 6],
89 state: &'a mut State<N_RX, N_TX>,
90 spi_dev: SPI,
91 int: INT,
92 mut reset: RST,
93) -> (Device<'a>, Runner<'a, SPI, INT, RST>) {
94 // Reset the W5500.
95 reset.set_low().ok();
96 // Ensure the reset is registered.
97 Timer::after(Duration::from_millis(1)).await;
98 reset.set_high().ok();
99 // Wait for the W5500 to achieve PLL lock.
100 Timer::after(Duration::from_millis(2)).await;
101
102 let mac = W5500::new(spi_dev, mac_addr).await.unwrap();
103
104 let (runner, device) = ch::new(&mut state.ch_state, mac_addr);
105 (
106 device,
107 Runner {
108 ch: runner,
109 mac,
110 int,
111 _reset: reset,
112 },
113 )
114}
diff --git a/src/socket.rs b/src/socket.rs
new file mode 100644
index 000000000..0d3d1aeb2
--- /dev/null
+++ b/src/socket.rs
@@ -0,0 +1,114 @@
1use crate::device::RegisterBlock;
2use crate::spi::SpiInterface;
3use embedded_hal_async::spi::SpiDevice;
4
5pub const MODE: u16 = 0x00;
6pub const COMMAND: u16 = 0x01;
7pub const RXBUF_SIZE: u16 = 0x1E;
8pub const TXBUF_SIZE: u16 = 0x1F;
9pub const TX_FREE_SIZE: u16 = 0x20;
10pub const TX_DATA_WRITE_PTR: u16 = 0x24;
11pub const RECVD_SIZE: u16 = 0x26;
12pub const RX_DATA_READ_PTR: u16 = 0x28;
13pub const SOCKET_INTR_MASK: u16 = 0x2C;
14
15#[repr(u8)]
16pub enum Command {
17 Open = 0x01,
18 Send = 0x20,
19 Receive = 0x40,
20}
21
22pub const INTR: u16 = 0x02;
23#[repr(u8)]
24pub enum Interrupt {
25 SendOk = 0b010000_u8,
26 Receive = 0b00100_u8,
27}
28
29pub async fn reset_interrupt<SPI: SpiDevice>(
30 bus: &mut SpiInterface<SPI>,
31 code: Interrupt,
32) -> Result<(), SPI::Error> {
33 let data = [code as u8];
34 bus.write_frame(RegisterBlock::Socket0, INTR, &data).await
35}
36
37pub async fn is_interrupt<SPI: SpiDevice>(
38 bus: &mut SpiInterface<SPI>,
39 code: Interrupt,
40) -> Result<bool, SPI::Error> {
41 let mut data = [0u8];
42 bus.read_frame(RegisterBlock::Socket0, INTR, &mut data)
43 .await?;
44 Ok(data[0] & code as u8 != 0)
45}
46
47pub async fn get_tx_write_ptr<SPI: SpiDevice>(
48 bus: &mut SpiInterface<SPI>,
49) -> Result<u16, SPI::Error> {
50 let mut data = [0u8; 2];
51 bus.read_frame(RegisterBlock::Socket0, TX_DATA_WRITE_PTR, &mut data)
52 .await?;
53 Ok(u16::from_be_bytes(data))
54}
55
56pub async fn set_tx_write_ptr<SPI: SpiDevice>(
57 bus: &mut SpiInterface<SPI>,
58 ptr: u16,
59) -> Result<(), SPI::Error> {
60 let data = ptr.to_be_bytes();
61 bus.write_frame(RegisterBlock::Socket0, TX_DATA_WRITE_PTR, &data)
62 .await
63}
64
65pub async fn get_rx_read_ptr<SPI: SpiDevice>(
66 bus: &mut SpiInterface<SPI>,
67) -> Result<u16, SPI::Error> {
68 let mut data = [0u8; 2];
69 bus.read_frame(RegisterBlock::Socket0, RX_DATA_READ_PTR, &mut data)
70 .await?;
71 Ok(u16::from_be_bytes(data))
72}
73
74pub async fn set_rx_read_ptr<SPI: SpiDevice>(
75 bus: &mut SpiInterface<SPI>,
76 ptr: u16,
77) -> Result<(), SPI::Error> {
78 let data = ptr.to_be_bytes();
79 bus.write_frame(RegisterBlock::Socket0, RX_DATA_READ_PTR, &data)
80 .await
81}
82
83pub async fn command<SPI: SpiDevice>(
84 bus: &mut SpiInterface<SPI>,
85 command: Command,
86) -> Result<(), SPI::Error> {
87 let data = [command as u8];
88 bus.write_frame(RegisterBlock::Socket0, COMMAND, &data)
89 .await
90}
91
92pub async fn get_rx_size<SPI: SpiDevice>(bus: &mut SpiInterface<SPI>) -> Result<u16, SPI::Error> {
93 loop {
94 // Wait until two sequential reads are equal
95 let mut res0 = [0u8; 2];
96 bus.read_frame(RegisterBlock::Socket0, RECVD_SIZE, &mut res0)
97 .await?;
98 let mut res1 = [0u8; 2];
99 bus.read_frame(RegisterBlock::Socket0, RECVD_SIZE, &mut res1)
100 .await?;
101 if res0 == res1 {
102 break Ok(u16::from_be_bytes(res0));
103 }
104 }
105}
106
107pub async fn get_tx_free_size<SPI: SpiDevice>(
108 bus: &mut SpiInterface<SPI>,
109) -> Result<u16, SPI::Error> {
110 let mut data = [0; 2];
111 bus.read_frame(RegisterBlock::Socket0, TX_FREE_SIZE, &mut data)
112 .await?;
113 Ok(u16::from_be_bytes(data))
114}
diff --git a/src/spi.rs b/src/spi.rs
new file mode 100644
index 000000000..55d311888
--- /dev/null
+++ b/src/spi.rs
@@ -0,0 +1,37 @@
1use crate::device::RegisterBlock;
2use embedded_hal_async::spi::{Operation, SpiDevice};
3
4#[derive(Debug)]
5#[cfg_attr(feature = "defmt", derive(defmt::Format))]
6pub struct SpiInterface<SPI>(pub SPI);
7
8impl<SPI: SpiDevice> SpiInterface<SPI> {
9 pub async fn read_frame(
10 &mut self,
11 block: RegisterBlock,
12 address: u16,
13 data: &mut [u8],
14 ) -> Result<(), SPI::Error> {
15 let address_phase = address.to_be_bytes();
16 let control_phase = [(block as u8) << 3];
17 let operations = &mut [
18 Operation::Write(&address_phase),
19 Operation::Write(&control_phase),
20 Operation::TransferInPlace(data),
21 ];
22 self.0.transaction(operations).await
23 }
24
25 pub async fn write_frame(
26 &mut self,
27 block: RegisterBlock,
28 address: u16,
29 data: &[u8],
30 ) -> Result<(), SPI::Error> {
31 let address_phase = address.to_be_bytes();
32 let control_phase = [(block as u8) << 3 | 0b0000_0100];
33 let data_phase = data;
34 let operations = &[&address_phase[..], &control_phase, &data_phase];
35 self.0.write_transaction(operations).await
36 }
37}