diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-08-15 18:19:03 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-08-15 22:53:22 +0200 |
| commit | 1d4b941d52a7e257b0305935034e999facb537bd (patch) | |
| tree | 20e6776b6503dcbb15f4f6afb5c476ba433f94be | |
| parent | 76276c326aaa4fd64a73253a480e2ea22f5ff740 (diff) | |
net-w5500: add w5100s support.
| -rw-r--r-- | embassy-net-w5500/Cargo.toml | 3 | ||||
| -rw-r--r-- | embassy-net-w5500/src/chip/mod.rs | 7 | ||||
| -rw-r--r-- | embassy-net-w5500/src/chip/w5100s.rs | 61 | ||||
| -rw-r--r-- | embassy-net-w5500/src/chip/w5500.rs | 5 | ||||
| -rw-r--r-- | embassy-net-w5500/src/device.rs | 41 | ||||
| -rw-r--r-- | embassy-net-w5500/src/lib.rs | 24 |
6 files changed, 123 insertions, 18 deletions
diff --git a/embassy-net-w5500/Cargo.toml b/embassy-net-w5500/Cargo.toml index 8972b814a..c45598684 100644 --- a/embassy-net-w5500/Cargo.toml +++ b/embassy-net-w5500/Cargo.toml | |||
| @@ -18,4 +18,5 @@ defmt = { version = "0.3", optional = true } | |||
| 18 | [package.metadata.embassy_docs] | 18 | [package.metadata.embassy_docs] |
| 19 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/src/" | 19 | src_base = "https://github.com/embassy-rs/embassy/blob/embassy-net-w5500-v$VERSION/embassy-net-w5500/src/" |
| 20 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-w5500/src/" | 20 | src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-net-w5500/src/" |
| 21 | target = "thumbv7em-none-eabi" \ No newline at end of file | 21 | target = "thumbv7em-none-eabi" |
| 22 | features = ["defmt"] \ No newline at end of file | ||
diff --git a/embassy-net-w5500/src/chip/mod.rs b/embassy-net-w5500/src/chip/mod.rs index b7d550e26..562db515a 100644 --- a/embassy-net-w5500/src/chip/mod.rs +++ b/embassy-net-w5500/src/chip/mod.rs | |||
| @@ -1,5 +1,7 @@ | |||
| 1 | mod w5500; | 1 | mod w5500; |
| 2 | pub use w5500::W5500; | 2 | pub use w5500::W5500; |
| 3 | mod w5100s; | ||
| 4 | pub use w5100s::W5100S; | ||
| 3 | 5 | ||
| 4 | pub(crate) mod sealed { | 6 | pub(crate) mod sealed { |
| 5 | use embedded_hal_async::spi::SpiDevice; | 7 | use embedded_hal_async::spi::SpiDevice; |
| @@ -22,6 +24,11 @@ pub(crate) mod sealed { | |||
| 22 | const SOCKET_INTR_MASK: Self::Address; | 24 | const SOCKET_INTR_MASK: Self::Address; |
| 23 | const SOCKET_INTR: Self::Address; | 25 | const SOCKET_INTR: Self::Address; |
| 24 | 26 | ||
| 27 | const SOCKET_MODE_VALUE: u8; | ||
| 28 | |||
| 29 | const BUF_SIZE: u16; | ||
| 30 | const AUTO_WRAP: bool; | ||
| 31 | |||
| 25 | fn rx_addr(addr: u16) -> Self::Address; | 32 | fn rx_addr(addr: u16) -> Self::Address; |
| 26 | fn tx_addr(addr: u16) -> Self::Address; | 33 | fn tx_addr(addr: u16) -> Self::Address; |
| 27 | 34 | ||
diff --git a/embassy-net-w5500/src/chip/w5100s.rs b/embassy-net-w5500/src/chip/w5100s.rs new file mode 100644 index 000000000..07a840370 --- /dev/null +++ b/embassy-net-w5500/src/chip/w5100s.rs | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | use embedded_hal_async::spi::{Operation, SpiDevice}; | ||
| 2 | |||
| 3 | const SOCKET_BASE: u16 = 0x400; | ||
| 4 | const TX_BASE: u16 = 0x4000; | ||
| 5 | const RX_BASE: u16 = 0x6000; | ||
| 6 | |||
| 7 | pub enum W5100S {} | ||
| 8 | |||
| 9 | impl super::Chip for W5100S {} | ||
| 10 | impl super::sealed::Chip for W5100S { | ||
| 11 | type Address = u16; | ||
| 12 | |||
| 13 | const COMMON_MODE: Self::Address = 0x00; | ||
| 14 | const COMMON_MAC: Self::Address = 0x09; | ||
| 15 | const COMMON_SOCKET_INTR: Self::Address = 0x16; | ||
| 16 | const COMMON_PHY_CFG: Self::Address = 0x3c; | ||
| 17 | |||
| 18 | const SOCKET_MODE: Self::Address = SOCKET_BASE + 0x00; | ||
| 19 | const SOCKET_COMMAND: Self::Address = SOCKET_BASE + 0x01; | ||
| 20 | const SOCKET_RXBUF_SIZE: Self::Address = SOCKET_BASE + 0x1E; | ||
| 21 | const SOCKET_TXBUF_SIZE: Self::Address = SOCKET_BASE + 0x1F; | ||
| 22 | const SOCKET_TX_FREE_SIZE: Self::Address = SOCKET_BASE + 0x20; | ||
| 23 | const SOCKET_TX_DATA_WRITE_PTR: Self::Address = SOCKET_BASE + 0x24; | ||
| 24 | const SOCKET_RECVD_SIZE: Self::Address = SOCKET_BASE + 0x26; | ||
| 25 | const SOCKET_RX_DATA_READ_PTR: Self::Address = SOCKET_BASE + 0x28; | ||
| 26 | const SOCKET_INTR_MASK: Self::Address = SOCKET_BASE + 0x2C; | ||
| 27 | const SOCKET_INTR: Self::Address = SOCKET_BASE + 0x02; | ||
| 28 | |||
| 29 | const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 6); | ||
| 30 | |||
| 31 | const BUF_SIZE: u16 = 0x2000; | ||
| 32 | const AUTO_WRAP: bool = false; | ||
| 33 | |||
| 34 | fn rx_addr(addr: u16) -> Self::Address { | ||
| 35 | RX_BASE + addr | ||
| 36 | } | ||
| 37 | |||
| 38 | fn tx_addr(addr: u16) -> Self::Address { | ||
| 39 | TX_BASE + addr | ||
| 40 | } | ||
| 41 | |||
| 42 | async fn bus_read<SPI: SpiDevice>( | ||
| 43 | spi: &mut SPI, | ||
| 44 | address: Self::Address, | ||
| 45 | data: &mut [u8], | ||
| 46 | ) -> Result<(), SPI::Error> { | ||
| 47 | spi.transaction(&mut [ | ||
| 48 | Operation::Write(&[0x0F, (address >> 8) as u8, address as u8]), | ||
| 49 | Operation::Read(data), | ||
| 50 | ]) | ||
| 51 | .await | ||
| 52 | } | ||
| 53 | |||
| 54 | async fn bus_write<SPI: SpiDevice>(spi: &mut SPI, address: Self::Address, data: &[u8]) -> Result<(), SPI::Error> { | ||
| 55 | spi.transaction(&mut [ | ||
| 56 | Operation::Write(&[0xF0, (address >> 8) as u8, address as u8]), | ||
| 57 | Operation::Write(data), | ||
| 58 | ]) | ||
| 59 | .await | ||
| 60 | } | ||
| 61 | } | ||
diff --git a/embassy-net-w5500/src/chip/w5500.rs b/embassy-net-w5500/src/chip/w5500.rs index f514e12a7..61e512946 100644 --- a/embassy-net-w5500/src/chip/w5500.rs +++ b/embassy-net-w5500/src/chip/w5500.rs | |||
| @@ -30,6 +30,11 @@ impl super::sealed::Chip for W5500 { | |||
| 30 | const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C); | 30 | const SOCKET_INTR_MASK: Self::Address = (RegisterBlock::Socket0, 0x2C); |
| 31 | const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02); | 31 | const SOCKET_INTR: Self::Address = (RegisterBlock::Socket0, 0x02); |
| 32 | 32 | ||
| 33 | const SOCKET_MODE_VALUE: u8 = (1 << 2) | (1 << 7); | ||
| 34 | |||
| 35 | const BUF_SIZE: u16 = 0x4000; | ||
| 36 | const AUTO_WRAP: bool = true; | ||
| 37 | |||
| 33 | fn rx_addr(addr: u16) -> Self::Address { | 38 | fn rx_addr(addr: u16) -> Self::Address { |
| 34 | (RegisterBlock::RxBuf, addr) | 39 | (RegisterBlock::RxBuf, addr) |
| 35 | } | 40 | } |
diff --git a/embassy-net-w5500/src/device.rs b/embassy-net-w5500/src/device.rs index a6ee8f8f7..f367bc3eb 100644 --- a/embassy-net-w5500/src/device.rs +++ b/embassy-net-w5500/src/device.rs | |||
| @@ -43,13 +43,13 @@ impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> { | |||
| 43 | // Set MAC address | 43 | // Set MAC address |
| 44 | this.bus_write(C::COMMON_MAC, &mac_addr).await?; | 44 | this.bus_write(C::COMMON_MAC, &mac_addr).await?; |
| 45 | 45 | ||
| 46 | // Set the raw socket RX/TX buffer sizes to 16KB | 46 | // Set the raw socket RX/TX buffer sizes. |
| 47 | this.bus_write(C::SOCKET_TXBUF_SIZE, &[16]).await?; | 47 | let buf_kbs = (C::BUF_SIZE / 1024) as u8; |
| 48 | this.bus_write(C::SOCKET_RXBUF_SIZE, &[16]).await?; | 48 | this.bus_write(C::SOCKET_TXBUF_SIZE, &[buf_kbs]).await?; |
| 49 | this.bus_write(C::SOCKET_RXBUF_SIZE, &[buf_kbs]).await?; | ||
| 49 | 50 | ||
| 50 | // MACRAW mode with MAC filtering. | 51 | // MACRAW mode with MAC filtering. |
| 51 | let mode: u8 = (1 << 2) | (1 << 7); | 52 | this.bus_write(C::SOCKET_MODE, &[C::SOCKET_MODE_VALUE]).await?; |
| 52 | this.bus_write(C::SOCKET_MODE, &[mode]).await?; | ||
| 53 | this.command(Command::Open).await?; | 53 | this.command(Command::Open).await?; |
| 54 | 54 | ||
| 55 | Ok(this) | 55 | Ok(this) |
| @@ -114,9 +114,21 @@ impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> { | |||
| 114 | Ok(u16::from_be_bytes(data)) | 114 | Ok(u16::from_be_bytes(data)) |
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | /// Read bytes from the RX buffer. Returns the number of bytes read. | 117 | /// Read bytes from the RX buffer. |
| 118 | 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> { |
| 119 | self.bus_read(C::rx_addr(*read_ptr), buffer).await?; | 119 | if C::AUTO_WRAP { |
| 120 | self.bus_read(C::rx_addr(*read_ptr), buffer).await?; | ||
| 121 | } else { | ||
| 122 | let addr = *read_ptr % C::BUF_SIZE; | ||
| 123 | if addr as usize + buffer.len() <= C::BUF_SIZE as usize { | ||
| 124 | self.bus_read(C::rx_addr(addr), buffer).await?; | ||
| 125 | } else { | ||
| 126 | let n = C::BUF_SIZE - addr; | ||
| 127 | self.bus_read(C::rx_addr(addr), &mut buffer[..n as usize]).await?; | ||
| 128 | self.bus_read(C::rx_addr(0), &mut buffer[n as usize..]).await?; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 120 | *read_ptr = (*read_ptr).wrapping_add(buffer.len() as u16); | 132 | *read_ptr = (*read_ptr).wrapping_add(buffer.len() as u16); |
| 121 | 133 | ||
| 122 | Ok(()) | 134 | Ok(()) |
| @@ -155,7 +167,20 @@ impl<C: Chip, SPI: SpiDevice> WiznetDevice<C, SPI> { | |||
| 155 | pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> { | 167 | pub async fn write_frame(&mut self, frame: &[u8]) -> Result<usize, SPI::Error> { |
| 156 | while self.get_tx_free_size().await? < frame.len() as u16 {} | 168 | while self.get_tx_free_size().await? < frame.len() as u16 {} |
| 157 | let write_ptr = self.get_tx_write_ptr().await?; | 169 | let write_ptr = self.get_tx_write_ptr().await?; |
| 158 | self.bus_write(C::tx_addr(write_ptr), frame).await?; | 170 | |
| 171 | if C::AUTO_WRAP { | ||
| 172 | self.bus_write(C::tx_addr(write_ptr), frame).await?; | ||
| 173 | } else { | ||
| 174 | let addr = write_ptr % C::BUF_SIZE; | ||
| 175 | if addr as usize + frame.len() <= C::BUF_SIZE as usize { | ||
| 176 | self.bus_write(C::tx_addr(addr), frame).await?; | ||
| 177 | } else { | ||
| 178 | let n = C::BUF_SIZE - addr; | ||
| 179 | self.bus_write(C::tx_addr(addr), &frame[..n as usize]).await?; | ||
| 180 | self.bus_write(C::tx_addr(0), &frame[n as usize..]).await?; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 159 | self.set_tx_write_ptr(write_ptr.wrapping_add(frame.len() as u16)) | 184 | self.set_tx_write_ptr(write_ptr.wrapping_add(frame.len() as u16)) |
| 160 | .await?; | 185 | .await?; |
| 161 | self.command(Command::Send).await?; | 186 | self.command(Command::Send).await?; |
diff --git a/embassy-net-w5500/src/lib.rs b/embassy-net-w5500/src/lib.rs index 9b53e9618..3030dfb90 100644 --- a/embassy-net-w5500/src/lib.rs +++ b/embassy-net-w5500/src/lib.rs | |||
| @@ -1,4 +1,4 @@ | |||
| 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 WIZnet ethernet chips. |
| 2 | #![no_std] | 2 | #![no_std] |
| 3 | #![feature(async_fn_in_trait)] | 3 | #![feature(async_fn_in_trait)] |
| 4 | 4 | ||
| @@ -18,7 +18,7 @@ use crate::device::WiznetDevice; | |||
| 18 | 18 | ||
| 19 | const MTU: usize = 1514; | 19 | const MTU: usize = 1514; |
| 20 | 20 | ||
| 21 | /// Type alias for the embassy-net driver for W5500 | 21 | /// Type alias for the embassy-net driver. |
| 22 | pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; | 22 | pub type Device<'d> = embassy_net_driver_channel::Device<'d, MTU>; |
| 23 | 23 | ||
| 24 | /// Internal state for the embassy-net integration. | 24 | /// Internal state for the embassy-net integration. |
| @@ -35,9 +35,9 @@ impl<const N_RX: usize, const N_TX: usize> State<N_RX, N_TX> { | |||
| 35 | } | 35 | } |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | /// Background runner for the W5500. | 38 | /// Background runner for the driver. |
| 39 | /// | 39 | /// |
| 40 | /// You must call `.run()` in a background task for the W5500 to operate. | 40 | /// You must call `.run()` in a background task for the driver to operate. |
| 41 | pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> { | 41 | pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> { |
| 42 | mac: WiznetDevice<C, SPI>, | 42 | mac: WiznetDevice<C, SPI>, |
| 43 | ch: ch::Runner<'d, MTU>, | 43 | ch: ch::Runner<'d, MTU>, |
| @@ -45,7 +45,7 @@ pub struct Runner<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> { | |||
| 45 | _reset: RST, | 45 | _reset: RST, |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | /// You must call this in a background task for the W5500 to operate. | 48 | /// You must call this in a background task for the driver to operate. |
| 49 | impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { | 49 | impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, INT, RST> { |
| 50 | pub async fn run(mut self) -> ! { | 50 | pub async fn run(mut self) -> ! { |
| 51 | 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(); |
| @@ -80,7 +80,11 @@ impl<'d, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin> Runner<'d, C, SPI, | |||
| 80 | } | 80 | } |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | /// Obtain a driver for using the W5500 with [`embassy-net`](https://crates.io/crates/embassy-net). | 83 | /// Create a Wiznet ethernet chip driver for [`embassy-net`](https://crates.io/crates/embassy-net). |
| 84 | /// | ||
| 85 | /// This returns two structs: | ||
| 86 | /// - a `Device` that you must pass to the `embassy-net` stack. | ||
| 87 | /// - a `Runner`. You must call `.run()` on it in a background task. | ||
| 84 | pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>( | 88 | pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevice, INT: Wait, RST: OutputPin>( |
| 85 | mac_addr: [u8; 6], | 89 | mac_addr: [u8; 6], |
| 86 | state: &'a mut State<N_RX, N_TX>, | 90 | state: &'a mut State<N_RX, N_TX>, |
| @@ -88,13 +92,15 @@ pub async fn new<'a, const N_RX: usize, const N_TX: usize, C: Chip, SPI: SpiDevi | |||
| 88 | int: INT, | 92 | int: INT, |
| 89 | mut reset: RST, | 93 | mut reset: RST, |
| 90 | ) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) { | 94 | ) -> (Device<'a>, Runner<'a, C, SPI, INT, RST>) { |
| 91 | // Reset the W5500. | 95 | // Reset the chip. |
| 92 | reset.set_low().ok(); | 96 | reset.set_low().ok(); |
| 93 | // Ensure the reset is registered. | 97 | // Ensure the reset is registered. |
| 94 | Timer::after(Duration::from_millis(1)).await; | 98 | Timer::after(Duration::from_millis(1)).await; |
| 95 | reset.set_high().ok(); | 99 | reset.set_high().ok(); |
| 96 | // Wait for the W5500 to achieve PLL lock. | 100 | |
| 97 | Timer::after(Duration::from_millis(2)).await; | 101 | // Wait for PLL lock. Some chips are slower than others. |
| 102 | // Slowest is w5100s which is 100ms, so let's just wait that. | ||
| 103 | Timer::after(Duration::from_millis(100)).await; | ||
| 98 | 104 | ||
| 99 | let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap(); | 105 | let mac = WiznetDevice::new(spi_dev, mac_addr).await.unwrap(); |
| 100 | 106 | ||
