diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-08-15 17:50:56 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-08-15 22:52:37 +0200 |
| commit | 76276c326aaa4fd64a73253a480e2ea22f5ff740 (patch) | |
| tree | 33a257710366497f68bf2669dacd3ad78516c3d5 | |
| parent | a436bd068f6059fa073a9f1f246a77e1ce38dd31 (diff) | |
net-w5500: extract chip-specific stuff to a trait.
| -rw-r--r-- | embassy-net-w5500/src/chip/mod.rs | 41 | ||||
| -rw-r--r-- | embassy-net-w5500/src/chip/w5500.rs | 67 | ||||
| -rw-r--r-- | embassy-net-w5500/src/device.rs | 94 | ||||
| -rw-r--r-- | embassy-net-w5500/src/lib.rs | 19 | ||||
| -rw-r--r-- | embassy-net-w5500/src/spi.rs | 34 | ||||
| -rw-r--r-- | examples/rp/src/bin/ethernet_w5500_multisocket.rs | 2 | ||||
| -rw-r--r-- | examples/rp/src/bin/ethernet_w5500_tcp_client.rs | 2 | ||||
| -rw-r--r-- | examples/rp/src/bin/ethernet_w5500_tcp_server.rs | 2 | ||||
| -rw-r--r-- | examples/rp/src/bin/ethernet_w5500_udp.rs | 2 |
9 files changed, 169 insertions, 94 deletions
diff --git a/embassy-net-w5500/src/chip/mod.rs b/embassy-net-w5500/src/chip/mod.rs new file mode 100644 index 000000000..b7d550e26 --- /dev/null +++ b/embassy-net-w5500/src/chip/mod.rs | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | mod w5500; | ||
| 2 | pub use w5500::W5500; | ||
| 3 | |||
| 4 | pub(crate) mod sealed { | ||
| 5 | use embedded_hal_async::spi::SpiDevice; | ||
| 6 | |||
| 7 | pub trait Chip { | ||
| 8 | type Address; | ||
| 9 | |||
| 10 | const COMMON_MODE: Self::Address; | ||
| 11 | const COMMON_MAC: Self::Address; | ||
| 12 | const COMMON_SOCKET_INTR: Self::Address; | ||
| 13 | const COMMON_PHY_CFG: Self::Address; | ||
| 14 | const SOCKET_MODE: Self::Address; | ||
| 15 | const SOCKET_COMMAND: Self::Address; | ||
| 16 | const SOCKET_RXBUF_SIZE: Self::Address; | ||
| 17 | const SOCKET_TXBUF_SIZE: Self::Address; | ||
| 18 | const SOCKET_TX_FREE_SIZE: Self::Address; | ||
| 19 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address; | ||
| 20 | const SOCKET_RECVD_SIZE: Self::Address; | ||
| 21 | const SOCKET_RX_DATA_READ_PTR: Self::Address; | ||
| 22 | const SOCKET_INTR_MASK: Self::Address; | ||
| 23 | const SOCKET_INTR: Self::Address; | ||
| 24 | |||
| 25 | fn rx_addr(addr: u16) -> Self::Address; | ||
| 26 | fn tx_addr(addr: u16) -> Self::Address; | ||
| 27 | |||
| 28 | async fn bus_read<SPI: SpiDevice>( | ||
| 29 | spi: &mut SPI, | ||
| 30 | address: Self::Address, | ||
| 31 | data: &mut [u8], | ||
| 32 | ) -> Result<(), SPI::Error>; | ||
| 33 | async fn bus_write<SPI: SpiDevice>( | ||
| 34 | spi: &mut SPI, | ||
| 35 | address: Self::Address, | ||
| 36 | data: &[u8], | ||
| 37 | ) -> Result<(), SPI::Error>; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | pub trait Chip: sealed::Chip {} | ||
diff --git a/embassy-net-w5500/src/chip/w5500.rs b/embassy-net-w5500/src/chip/w5500.rs new file mode 100644 index 000000000..f514e12a7 --- /dev/null +++ b/embassy-net-w5500/src/chip/w5500.rs | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | use embedded_hal_async::spi::{Operation, SpiDevice}; | ||
| 2 | |||
| 3 | #[repr(u8)] | ||
| 4 | pub enum RegisterBlock { | ||
| 5 | Common = 0x00, | ||
| 6 | Socket0 = 0x01, | ||
| 7 | TxBuf = 0x02, | ||
| 8 | RxBuf = 0x03, | ||
| 9 | } | ||
| 10 | |||
| 11 | pub enum W5500 {} | ||
| 12 | |||
| 13 | impl super::Chip for W5500 {} | ||
| 14 | impl super::sealed::Chip for W5500 { | ||
| 15 | type Address = (RegisterBlock, u16); | ||
| 16 | |||
| 17 | const COMMON_MODE: Self::Address = (RegisterBlock::Common, 0x00); | ||
| 18 | const COMMON_MAC: Self::Address = (RegisterBlock::Common, 0x09); | ||
| 19 | const COMMON_SOCKET_INTR: Self::Address = (RegisterBlock::Common, 0x18); | ||
| 20 | const COMMON_PHY_CFG: Self::Address = (RegisterBlock::Common, 0x2E); | ||
| 21 | |||
| 22 | const SOCKET_MODE: Self::Address = (RegisterBlock::Socket0, 0x00); | ||
| 23 | const SOCKET_COMMAND: Self::Address = (RegisterBlock::Socket0, 0x01); | ||
| 24 | const SOCKET_RXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x1E); | ||
| 25 | const SOCKET_TXBUF_SIZE: Self::Address = (RegisterBlock::Socket0, 0x1F); | ||
| 26 | const SOCKET_TX_FREE_SIZE: Self::Address = (RegisterBlock::Socket0, 0x20); | ||
| 27 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address = (RegisterBlock::Socket0, 0x24); | ||
| 28 | const SOCKET_RECVD_SIZE: Self::Address = (RegisterBlock::Socket0, 0x26); | ||
| 29 | const SOCKET_RX_DATA_READ_PTR: Self::Address = (RegisterBlock::Socket0, 0x28); | ||
| 30 | const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C); | ||
| 31 | const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02); | ||
| 32 | |||
| 33 | fn rx_addr(addr: u16) -> Self::Address { | ||
| 34 | (RegisterBlock::RxBuf, addr) | ||
| 35 | } | ||
| 36 | |||
| 37 | fn tx_addr(addr: u16) -> Self::Address { | ||
| 38 | (RegisterBlock::TxBuf, addr) | ||
| 39 | } | ||
| 40 | |||
| 41 | async fn bus_read<SPI: SpiDevice>( | ||
| 42 | spi: &mut SPI, | ||
| 43 | address: Self::Address, | ||
| 44 | data: &mut [u8], | ||
| 45 | ) -> Result<(), SPI::Error> { | ||
| 46 | let address_phase = address.1.to_be_bytes(); | ||
| 47 | let control_phase = [(address.0 as u8) << 3]; | ||
| 48 | let operations = &mut [ | ||
| 49 | Operation::Write(&address_phase), | ||
| 50 | Operation::Write(&control_phase), | ||
| 51 | Operation::TransferInPlace(data), | ||
| 52 | ]; | ||
| 53 | spi.transaction(operations).await | ||
| 54 | } | ||
| 55 | |||
| 56 | async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 57 | let address_phase = address.1.to_be_bytes(); | ||
| 58 | let control_phase = [(address.0 as u8) << 3 | 0b0000_0100]; | ||
| 59 | let data_phase = data; | ||
| 60 | let operations = &mut [ | ||
| 61 | Operation::Write(&address_phase[..]), | ||
| 62 | Operation::Write(&control_phase), | ||
| 63 | Operation::Write(&data_phase), | ||
| 64 | ]; | ||
| 65 | spi.transaction(operations).await | ||
| 66 | } | ||
| 67 | } | ||
diff --git a/embassy-net-w5500/src/device.rs b/embassy-net-w5500/src/device.rs index cf451b334..a6ee8f8f7 100644 --- a/embassy-net-w5500/src/device.rs +++ b/embassy-net-w5500/src/device.rs | |||
| @@ -1,117 +1,107 @@ | |||
| 1 | use embedded_hal_async::spi::SpiDevice; | 1 | use core::marker::PhantomData; |
| 2 | |||
| 3 | use crate::spi::{Address, SpiInterface}; | ||
| 4 | 2 | ||
| 5 | pub const COMMON_MODE: Address = (RegisterBlock::Common, 0x00); | 3 | use embedded_hal_async::spi::SpiDevice; |
| 6 | pub const COMMON_MAC: Address = (RegisterBlock::Common, 0x09); | ||
| 7 | pub const COMMON_SOCKET_INTR: Address = (RegisterBlock::Common, 0x18); | ||
| 8 | pub const COMMON_PHY_CFG: Address = (RegisterBlock::Common, 0x2E); | ||
| 9 | 4 | ||
| 10 | pub const SOCKET_MODE: Address = (RegisterBlock::Socket0, 0x00); | 5 | use crate::chip::Chip; |
| 11 | pub const SOCKET_COMMAND: Address = (RegisterBlock::Socket0, 0x01); | ||
| 12 | pub const SOCKET_RXBUF_SIZE: Address = (RegisterBlock::Socket0, 0x1E); | ||
| 13 | pub const SOCKET_TXBUF_SIZE: Address = (RegisterBlock::Socket0, 0x1F); | ||
| 14 | pub const SOCKET_TX_FREE_SIZE: Address = (RegisterBlock::Socket0, 0x20); | ||
| 15 | pub const SOCKET_TX_DATA_WRITE_PTR: Address = (RegisterBlock::Socket0, 0x24); | ||
| 16 | pub const SOCKET_RECVD_SIZE: Address = (RegisterBlock::Socket0, 0x26); | ||
| 17 | pub const SOCKET_RX_DATA_READ_PTR: Address = (RegisterBlock::Socket0, 0x28); | ||
| 18 | pub const SOCKET_INTR_MASK: Address = (RegisterBlock::Socket0, 0x2C); | ||
| 19 | pub const SOCKET_INTR: Address = (RegisterBlock::Socket0, 0x02); | ||
| 20 | 6 | ||
| 21 | #[repr(u8)] | 7 | #[repr(u8)] |
| 22 | pub enum Command { | 8 | enum Command { |
| 23 | Open = 0x01, | 9 | Open = 0x01, |
| 24 | Send = 0x20, | 10 | Send = 0x20, |
| 25 | Receive = 0x40, | 11 | Receive = 0x40, |
| 26 | } | 12 | } |
| 27 | 13 | ||
| 28 | #[repr(u8)] | 14 | #[repr(u8)] |
| 29 | pub enum Interrupt { | 15 | enum Interrupt { |
| 30 | Receive = 0b00100_u8, | 16 | Receive = 0b00100_u8, |
| 31 | } | 17 | } |
| 32 | 18 | ||
| 33 | #[repr(u8)] | ||
| 34 | pub enum RegisterBlock { | ||
| 35 | Common = 0x00, | ||
| 36 | Socket0 = 0x01, | ||
| 37 | TxBuf = 0x02, | ||
| 38 | RxBuf = 0x03, | ||
| 39 | } | ||
| 40 | |||
| 41 | /// W5500 in MACRAW mode | 19 | /// W5500 in MACRAW mode |
| 42 | #[derive(Debug)] | 20 | #[derive(Debug)] |
| 43 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 21 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 44 | pub struct W5500<SPI> { | 22 | pub(crate) struct WiznetDevice<C, SPI> { |
| 45 | bus: SpiInterface<SPI>, | 23 | spi: SPI, |
| 24 | _phantom: PhantomData<C>, | ||
| 46 | } | 25 | } |
| 47 | 26 | ||
| 48 | impl<SPI: SpiDevice> W5500<SPI> { | 27 | impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> { |
| 49 | /// Create and initialize the W5500 driver | 28 | /// Create and initialize the W5500 driver |
| 50 | pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<W5500<SPI>, SPI::Error> { | 29 | pub async fn new(spi: SPI, mac_addr: [u8; 6]) -> Result<Self, SPI::Error> { |
| 51 | let mut bus = SpiInterface(spi); | 30 | let mut this = Self { |
| 31 | spi, | ||
| 32 | _phantom: PhantomData, | ||
| 33 | }; | ||
| 34 | |||
| 52 | // Reset device | 35 | // Reset device |
| 53 | bus.write_frame(COMMON_MODE, &[0x80]).await?; | 36 | this.bus_write(C::COMMON_MODE, &[0x80]).await?; |
| 54 | 37 | ||
| 55 | // Enable interrupt pin | 38 | // Enable interrupt pin |
| 56 | bus.write_frame(COMMON_SOCKET_INTR, &[0x01]).await?; | 39 | this.bus_write(C::COMMON_SOCKET_INTR, &[0x01]).await?; |
| 57 | // Enable receive interrupt | 40 | // Enable receive interrupt |
| 58 | bus.write_frame(SOCKET_INTR_MASK, &[Interrupt::Receive as u8]).await?; | 41 | this.bus_write(C::SOCKET_INTR_MASK, &[Interrupt::Receive as u8]).await?; |
| 59 | 42 | ||
| 60 | // Set MAC address | 43 | // Set MAC address |
| 61 | bus.write_frame(COMMON_MAC, &mac_addr).await?; | 44 | this.bus_write(C::COMMON_MAC, &mac_addr).await?; |
| 62 | 45 | ||
| 63 | // Set the raw socket RX/TX buffer sizes to 16KB | 46 | // Set the raw socket RX/TX buffer sizes to 16KB |
| 64 | bus.write_frame(SOCKET_TXBUF_SIZE, &[16]).await?; | 47 | this.bus_write(C::SOCKET_TXBUF_SIZE, &[16]).await?; |
| 65 | bus.write_frame(SOCKET_RXBUF_SIZE, &[16]).await?; | 48 | this.bus_write(C::SOCKET_RXBUF_SIZE, &[16]).await?; |
| 66 | 49 | ||
| 67 | // MACRAW mode with MAC filtering. | 50 | // MACRAW mode with MAC filtering. |
| 68 | let mode: u8 = (1 << 2) | (1 << 7); | 51 | let mode: u8 = (1 << 2) | (1 << 7); |
| 69 | bus.write_frame(SOCKET_MODE, &[mode]).await?; | 52 | this.bus_write(C::SOCKET_MODE, &[mode]).await?; |
| 70 | let mut this = Self { bus }; | ||
| 71 | this.command(Command::Open).await?; | 53 | this.command(Command::Open).await?; |
| 72 | 54 | ||
| 73 | Ok(this) | 55 | Ok(this) |
| 74 | } | 56 | } |
| 75 | 57 | ||
| 58 | async fn bus_read(&mut self, address: C::Address, data: &mut [u8]) -> Result<(), SPI::Error> { | ||
| 59 | C::bus_read(&mut self.spi, address, data).await | ||
| 60 | } | ||
| 61 | |||
| 62 | async fn bus_write(&mut self, address: C::Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 63 | C::bus_write(&mut self.spi, address, data).await | ||
| 64 | } | ||
| 65 | |||
| 76 | async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> { | 66 | async fn reset_interrupt(&mut self, code: Interrupt) -> Result<(), SPI::Error> { |
| 77 | let data = [code as u8]; | 67 | let data = [code as u8]; |
| 78 | self.bus.write_frame(SOCKET_INTR, &data).await | 68 | self.bus_write(C::SOCKET_INTR, &data).await |
| 79 | } | 69 | } |
| 80 | 70 | ||
| 81 | async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> { | 71 | async fn get_tx_write_ptr(&mut self) -> Result<u16, SPI::Error> { |
| 82 | let mut data = [0u8; 2]; | 72 | let mut data = [0u8; 2]; |
| 83 | self.bus.read_frame(SOCKET_TX_DATA_WRITE_PTR, &mut data).await?; | 73 | self.bus_read(C::SOCKET_TX_DATA_WRITE_PTR, &mut data).await?; |
| 84 | Ok(u16::from_be_bytes(data)) | 74 | Ok(u16::from_be_bytes(data)) |
| 85 | } | 75 | } |
| 86 | 76 | ||
| 87 | async fn set_tx_write_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> { | 77 | async fn set_tx_write_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> { |
| 88 | let data = ptr.to_be_bytes(); | 78 | let data = ptr.to_be_bytes(); |
| 89 | self.bus.write_frame(SOCKET_TX_DATA_WRITE_PTR, &data).await | 79 | self.bus_write(C::SOCKET_TX_DATA_WRITE_PTR, &data).await |
| 90 | } | 80 | } |
| 91 | 81 | ||
| 92 | async fn get_rx_read_ptr(&mut self) -> Result<u16, SPI::Error> { | 82 | async fn get_rx_read_ptr(&mut self) -> Result<u16, SPI::Error> { |
| 93 | let mut data = [0u8; 2]; | 83 | let mut data = [0u8; 2]; |
| 94 | self.bus.read_frame(SOCKET_RX_DATA_READ_PTR, &mut data).await?; | 84 | self.bus_read(C::SOCKET_RX_DATA_READ_PTR, &mut data).await?; |
| 95 | Ok(u16::from_be_bytes(data)) | 85 | Ok(u16::from_be_bytes(data)) |
| 96 | } | 86 | } |
| 97 | 87 | ||
| 98 | async fn set_rx_read_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> { | 88 | async fn set_rx_read_ptr(&mut self, ptr: u16) -> Result<(), SPI::Error> { |
| 99 | let data = ptr.to_be_bytes(); | 89 | let data = ptr.to_be_bytes(); |
| 100 | self.bus.write_frame(SOCKET_RX_DATA_READ_PTR, &data).await | 90 | self.bus_write(C::SOCKET_RX_DATA_READ_PTR, &data).await |
| 101 | } | 91 | } |
| 102 | 92 | ||
| 103 | async fn command(&mut self, command: Command) -> Result<(), SPI::Error> { | 93 | async fn command(&mut self, command: Command) -> Result<(), SPI::Error> { |
| 104 | let data = [command as u8]; | 94 | let data = [command as u8]; |
| 105 | self.bus.write_frame(SOCKET_COMMAND, &data).await | 95 | self.bus_write(C::SOCKET_COMMAND, &data).await |
| 106 | } | 96 | } |
| 107 | 97 | ||
| 108 | async fn get_rx_size(&mut self) -> Result<u16, SPI::Error> { | 98 | async fn get_rx_size(&mut self) -> Result<u16, SPI::Error> { |
| 109 | loop { | 99 | loop { |
| 110 | // Wait until two sequential reads are equal | 100 | // Wait until two sequential reads are equal |
| 111 | let mut res0 = [0u8; 2]; | 101 | let mut res0 = [0u8; 2]; |
| 112 | self.bus.read_frame(SOCKET_RECVD_SIZE, &mut res0).await?; | 102 | self.bus_read(C::SOCKET_RECVD_SIZE, &mut res0).await?; |
| 113 | let mut res1 = [0u8; 2]; | 103 | let mut res1 = [0u8; 2]; |
| 114 | self.bus.read_frame(SOCKET_RECVD_SIZE, &mut res1).await?; | 104 | self.bus_read(C::SOCKET_RECVD_SIZE, &mut res1).await?; |
| 115 | if res0 == res1 { | 105 | if res0 == res1 { |
| 116 | break Ok(u16::from_be_bytes(res0)); | 106 | break Ok(u16::from_be_bytes(res0)); |
| 117 | } | 107 | } |
| @@ -120,13 +110,13 @@ impl<SPI: SpiDevice> W5500<SPI> { | |||
| 120 | 110 | ||
| 121 | async fn get_tx_free_size(&mut self) -> Result<u16, SPI::Error> { | 111 | async fn get_tx_free_size(&mut self) -> Result<u16, SPI::Error> { |
| 122 | let mut data = [0; 2]; | 112 | let mut data = [0; 2]; |
| 123 | self.bus.read_frame(SOCKET_TX_FREE_SIZE, &mut data).await?; | 113 | self.bus_read(C::SOCKET_TX_FREE_SIZE, &mut data).await?; |
| 124 | Ok(u16::from_be_bytes(data)) | 114 | Ok(u16::from_be_bytes(data)) |
| 125 | } | 115 | } |
| 126 | 116 | ||
| 127 | /// Read bytes from the RX buffer. Returns the number of bytes read. | 117 | /// Read bytes from the RX buffer. Returns the number of bytes read. |
| 128 | async fn read_bytes(&mut self, read_ptr: &mut u16, buffer: &mut [u8]) -> Result<(), SPI::Error> { | 118 | async fn read_bytes(&mut self, read_ptr: &mut u16, buffer: &mut [u8]) -> Result<(), SPI::Error> { |
| 129 | self.bus.read_frame((RegisterBlock::RxBuf, *read_ptr), buffer).await?; | 119 | self.bus_read(C::rx_addr(*read_ptr), buffer).await?; |
| 130 | *read_ptr = (*read_ptr).wrapping_add(buffer.len() as u16); | 120 | *read_ptr = (*read_ptr).wrapping_add(buffer.len() as u16); |
| 131 | 121 | ||
| 132 | Ok(()) | 122 | Ok(()) |
| @@ -165,7 +155,7 @@ impl<SPI: SpiDevice> W5500<SPI> { | |||
| 165 | pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> { | 155 | pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> { |
| 166 | while self.get_tx_free_size().await? < frame.len() as u16 {} | 156 | while self.get_tx_free_size().await? < frame.len() as u16 {} |
| 167 | let write_ptr = self.get_tx_write_ptr().await?; | 157 | let write_ptr = self.get_tx_write_ptr().await?; |
| 168 | self.bus.write_frame((RegisterBlock::TxBuf, write_ptr), frame).await?; | 158 | self.bus_write(C::tx_addr(write_ptr), frame).await?; |
| 169 | self.set_tx_write_ptr(write_ptr.wrapping_add(frame.len() as u16)) | 159 | self.set_tx_write_ptr(write_ptr.wrapping_add(frame.len() as u16)) |
| 170 | .await?; | 160 | .await?; |
| 171 | self.command(Command::Send).await?; | 161 | self.command(Command::Send).await?; |
| @@ -174,7 +164,7 @@ impl<SPI: SpiDevice> W5500<SPI> { | |||
| 174 | 164 | ||
| 175 | pub async fn is_link_up(&mut self) -> bool { | 165 | pub async fn is_link_up(&mut self) -> bool { |
| 176 | let mut link = [0]; | 166 | let mut link = [0]; |
| 177 | self.bus.read_frame(COMMON_PHY_CFG, &mut link).await.ok(); | 167 | self.bus_read(C::COMMON_PHY_CFG, &mut link).await.ok(); |
| 178 | link[0] & 1 == 1 | 168 | link[0] & 1 == 1 |
| 179 | } | 169 | } |
| 180 | } | 170 | } |
diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-w5500/src/lib.rs index 3c54777d8..9b53e9618 100644 --- a/embassy-net-w5500/src/lib.rs +++ b/embassy-net-w5500/src/lib.rs | |||
| @@ -1,8 +1,9 @@ | |||
| 1 | //! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. | 1 | //! [`embassy-net`](https://crates.io/crates/embassy-net) driver for the WIZnet W5500 ethernet chip. |
| 2 | #![no_std] | 2 | #![no_std] |
| 3 | #![feature(async_fn_in_trait)] | ||
| 3 | 4 | ||
| 5 | pub mod chip; | ||
| 4 | mod device; | 6 | mod device; |
| 5 | mod spi; | ||
| 6 | 7 | ||
| 7 | use embassy_futures::select::{select, Either}; | 8 | use embassy_futures::select::{select, Either}; |
| 8 | use embassy_net_driver_channel as ch; | 9 | use embassy_net_driver_channel as ch; |
| @@ -12,7 +13,9 @@ use embedded_hal::digital::OutputPin; | |||
| 12 | use embedded_hal_async::digital::Wait; | 13 | use embedded_hal_async::digital::Wait; |
| 13 | use embedded_hal_async::spi::SpiDevice; | 14 | use embedded_hal_async::spi::SpiDevice; |
| 14 | 15 | ||
| 15 | use crate::device::W5500; | 16 | use crate::chip::Chip; |
| 17 | use crate::device::WiznetDevice; | ||
| 18 | |||
| 16 | const MTU: usize = 1514; | 19 | const MTU: usize = 1514; |
| 17 | 20 | ||
| 18 | /// Type alias for the embassy-net driver for W5500 | 21 | /// Type alias for the embassy-net driver for W5500 |
| @@ -35,15 +38,15 @@ impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> { | |||
| 35 | /// Background runner for the W5500. | 38 | /// Background runner for the W5500. |
| 36 | /// | 39 | /// |
| 37 | /// You must call `.run()` in a background task for the W5500 to operate. | 40 | /// You must call `.run()` in a background task for the W5500 to operate. |
| 38 | pub struct Runner<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> { | 41 | pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> { |
| 39 | mac: W5500<SPI>, | 42 | mac: WiznetDevice<C, SPI>, |
| 40 | ch: ch::Runner<'d, MTU>, | 43 | ch: ch::Runner<'d, MTU>, |
| 41 | int: INT, | 44 | int: INT, |
| 42 | _reset: RST, | 45 | _reset: RST, |
| 43 | } | 46 | } |
| 44 | 47 | ||
| 45 | /// You must call this in a background task for the W5500 to operate. | 48 | /// You must call this in a background task for the W5500 to operate. |
| 46 | impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { | 49 | impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { |
| 47 | pub async fn run(mut self) -> ! { | 50 | pub async fn run(mut self) -> ! { |
| 48 | let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); | 51 | let (state_chan, mut rx_chan, mut tx_chan) = self.ch.split(); |
| 49 | loop { | 52 | loop { |
| @@ -78,13 +81,13 @@ impl<'d, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, SPI, INT, RST> { | |||
| 78 | } | 81 | } |
| 79 | 82 | ||
| 80 | /// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). | 83 | /// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). |
| 81 | pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: Wait, RST: OutputPin>( | 84 | pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>( |
| 82 | mac_addr: [u8; 6], | 85 | mac_addr: [u8; 6], |
| 83 | state: &'a mut State<N_RX, N_TX>, | 86 | state: &'a mut State<N_RX, N_TX>, |
| 84 | spi_dev: SPI, | 87 | spi_dev: SPI, |
| 85 | int: INT, | 88 | int: INT, |
| 86 | mut reset: RST, | 89 | mut reset: RST, |
| 87 | ) -> (Device<'a>, Runner<'a, SPI, INT, RST>) { | 90 | ) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) { |
| 88 | // Reset the W5500. | 91 | // Reset the W5500. |
| 89 | reset.set_low().ok(); | 92 | reset.set_low().ok(); |
| 90 | // Ensure the reset is registered. | 93 | // Ensure the reset is registered. |
| @@ -93,7 +96,7 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, SPI: SpiDevice, INT: | |||
| 93 | // Wait for the W5500 to achieve PLL lock. | 96 | // Wait for the W5500 to achieve PLL lock. |
| 94 | Timer::after(Duration::from_millis(2)).await; | 97 | Timer::after(Duration::from_millis(2)).await; |
| 95 | 98 | ||
| 96 | let mac = W5500::new(spi_dev, mac_addr).await.unwrap(); | 99 | let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap(); |
| 97 | 100 | ||
| 98 | let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); | 101 | let (runner, device) = ch::new(&mut state.ch_state, ch::driver::HardwareAddress::Ethernet(mac_addr)); |
| 99 | ( | 102 | ( |
diff --git a/embassy-net-w5500/src/spi.rs b/embassy-net-w5500/src/spi.rs deleted file mode 100644 index 316c6521e..000000000 --- a/embassy-net-w5500/src/spi.rs +++ /dev/null | |||
| @@ -1,34 +0,0 @@ | |||
| 1 | use embedded_hal_async::spi::{Operation, SpiDevice}; | ||
| 2 | |||
| 3 | use crate::device::RegisterBlock; | ||
| 4 | |||
| 5 | pub type Address = (RegisterBlock, u16); | ||
| 6 | |||
| 7 | #[derive(Debug)] | ||
| 8 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 9 | pub struct SpiInterface<SPI>(pub SPI); | ||
| 10 | |||
| 11 | impl<SPI: SpiDevice> SpiInterface<SPI> { | ||
| 12 | pub async fn read_frame(&mut self, address: Address, data: &mut [u8]) -> Result<(), SPI::Error> { | ||
| 13 | let address_phase = address.1.to_be_bytes(); | ||
| 14 | let control_phase = [(address.0 as u8) << 3]; | ||
| 15 | let operations = &mut [ | ||
| 16 | Operation::Write(&address_phase), | ||
| 17 | Operation::Write(&control_phase), | ||
| 18 | Operation::TransferInPlace(data), | ||
| 19 | ]; | ||
| 20 | self.0.transaction(operations).await | ||
| 21 | } | ||
| 22 | |||
| 23 | pub async fn write_frame(&mut self, address: Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 24 | let address_phase = address.1.to_be_bytes(); | ||
| 25 | let control_phase = [(address.0 as u8) << 3 | 0b0000_0100]; | ||
| 26 | let data_phase = data; | ||
| 27 | let operations = &mut [ | ||
| 28 | Operation::Write(&address_phase[..]), | ||
| 29 | Operation::Write(&control_phase), | ||
| 30 | Operation::Write(&data_phase), | ||
| 31 | ]; | ||
| 32 | self.0.transaction(operations).await | ||
| 33 | } | ||
| 34 | } | ||
diff --git a/examples/rp/src/bin/ethernet_w5500_multisocket.rs b/examples/rp/src/bin/ethernet_w5500_multisocket.rs index 9f800d0d9..3677f3cd6 100644 --- a/examples/rp/src/bin/ethernet_w5500_multisocket.rs +++ b/examples/rp/src/bin/ethernet_w5500_multisocket.rs | |||
| @@ -10,6 +10,7 @@ use defmt::*; | |||
| 10 | use embassy_executor::Spawner; | 10 | use embassy_executor::Spawner; |
| 11 | use embassy_futures::yield_now; | 11 | use embassy_futures::yield_now; |
| 12 | use embassy_net::{Stack, StackResources}; | 12 | use embassy_net::{Stack, StackResources}; |
| 13 | use embassy_net_w5500::chip::W5500; | ||
| 13 | use embassy_net_w5500::*; | 14 | use embassy_net_w5500::*; |
| 14 | use embassy_rp::clocks::RoscRng; | 15 | use embassy_rp::clocks::RoscRng; |
| 15 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 16 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| @@ -26,6 +27,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 26 | async fn ethernet_task( | 27 | async fn ethernet_task( |
| 27 | runner: Runner< | 28 | runner: Runner< |
| 28 | 'static, | 29 | 'static, |
| 30 | W5500, | ||
| 29 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 31 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 30 | Input<'static, PIN_21>, | 32 | Input<'static, PIN_21>, |
| 31 | Output<'static, PIN_20>, | 33 | Output<'static, PIN_20>, |
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs index fee84b613..b78a09779 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_client.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_client.rs | |||
| @@ -12,6 +12,7 @@ use defmt::*; | |||
| 12 | use embassy_executor::Spawner; | 12 | use embassy_executor::Spawner; |
| 13 | use embassy_futures::yield_now; | 13 | use embassy_futures::yield_now; |
| 14 | use embassy_net::{Stack, StackResources}; | 14 | use embassy_net::{Stack, StackResources}; |
| 15 | use embassy_net_w5500::chip::W5500; | ||
| 15 | use embassy_net_w5500::*; | 16 | use embassy_net_w5500::*; |
| 16 | use embassy_rp::clocks::RoscRng; | 17 | use embassy_rp::clocks::RoscRng; |
| 17 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 18 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| @@ -28,6 +29,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 28 | async fn ethernet_task( | 29 | async fn ethernet_task( |
| 29 | runner: Runner< | 30 | runner: Runner< |
| 30 | 'static, | 31 | 'static, |
| 32 | W5500, | ||
| 31 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 33 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 32 | Input<'static, PIN_21>, | 34 | Input<'static, PIN_21>, |
| 33 | Output<'static, PIN_20>, | 35 | Output<'static, PIN_20>, |
diff --git a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs index 024574267..34f054d9a 100644 --- a/examples/rp/src/bin/ethernet_w5500_tcp_server.rs +++ b/examples/rp/src/bin/ethernet_w5500_tcp_server.rs | |||
| @@ -11,6 +11,7 @@ use defmt::*; | |||
| 11 | use embassy_executor::Spawner; | 11 | use embassy_executor::Spawner; |
| 12 | use embassy_futures::yield_now; | 12 | use embassy_futures::yield_now; |
| 13 | use embassy_net::{Stack, StackResources}; | 13 | use embassy_net::{Stack, StackResources}; |
| 14 | use embassy_net_w5500::chip::W5500; | ||
| 14 | use embassy_net_w5500::*; | 15 | use embassy_net_w5500::*; |
| 15 | use embassy_rp::clocks::RoscRng; | 16 | use embassy_rp::clocks::RoscRng; |
| 16 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 17 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| @@ -26,6 +27,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 26 | async fn ethernet_task( | 27 | async fn ethernet_task( |
| 27 | runner: Runner< | 28 | runner: Runner< |
| 28 | 'static, | 29 | 'static, |
| 30 | W5500, | ||
| 29 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 31 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 30 | Input<'static, PIN_21>, | 32 | Input<'static, PIN_21>, |
| 31 | Output<'static, PIN_20>, | 33 | Output<'static, PIN_20>, |
diff --git a/examples/rp/src/bin/ethernet_w5500_udp.rs b/examples/rp/src/bin/ethernet_w5500_udp.rs index 038432b17..8f38e453e 100644 --- a/examples/rp/src/bin/ethernet_w5500_udp.rs +++ b/examples/rp/src/bin/ethernet_w5500_udp.rs | |||
| @@ -11,6 +11,7 @@ use embassy_executor::Spawner; | |||
| 11 | use embassy_futures::yield_now; | 11 | use embassy_futures::yield_now; |
| 12 | use embassy_net::udp::{PacketMetadata, UdpSocket}; | 12 | use embassy_net::udp::{PacketMetadata, UdpSocket}; |
| 13 | use embassy_net::{Stack, StackResources}; | 13 | use embassy_net::{Stack, StackResources}; |
| 14 | use embassy_net_w5500::chip::W5500; | ||
| 14 | use embassy_net_w5500::*; | 15 | use embassy_net_w5500::*; |
| 15 | use embassy_rp::clocks::RoscRng; | 16 | use embassy_rp::clocks::RoscRng; |
| 16 | use embassy_rp::gpio::{Input, Level, Output, Pull}; | 17 | use embassy_rp::gpio::{Input, Level, Output, Pull}; |
| @@ -25,6 +26,7 @@ use {defmt_rtt as _, panic_probe as _}; | |||
| 25 | async fn ethernet_task( | 26 | async fn ethernet_task( |
| 26 | runner: Runner< | 27 | runner: Runner< |
| 27 | 'static, | 28 | 'static, |
| 29 | W5500, | ||
| 28 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, | 30 | ExclusiveDevice<Spi<'static, SPI0, Async>, Output<'static, PIN_17>, Delay>, |
| 29 | Input<'static, PIN_21>, | 31 | Input<'static, PIN_21>, |
| 30 | Output<'static, PIN_20>, | 32 | Output<'static, PIN_20>, |
