diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-12-09 03:18:45 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-12-13 16:43:25 +0100 |
| commit | 8f3065210927b6e92f6d727741189155b2eab91e (patch) | |
| tree | 57bbff95079fd43cb01f0728f8a8b5836e0b5343 | |
| parent | e9219405ca04e23b6543fb841fd97df54cf72f94 (diff) | |
stm32/eth_v1: update to new embassy-net trait, remove PeripheralMutex.
| -rw-r--r-- | embassy-stm32/src/eth/mod.rs | 121 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v1/descriptors.rs | 21 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v1/mod.rs | 395 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v1/rx_desc.rs | 208 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v1/tx_desc.rs | 153 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/eth.rs | 50 |
6 files changed, 423 insertions, 525 deletions
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 76a3dfab4..fd1b48530 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs | |||
| @@ -1,14 +1,131 @@ | |||
| 1 | #![macro_use] | 1 | #![macro_use] |
| 2 | #![cfg_attr(not(feature = "embassy-net"), allow(unused))] | ||
| 2 | 3 | ||
| 3 | #[cfg(feature = "net")] | ||
| 4 | #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] | 4 | #[cfg_attr(any(eth_v1a, eth_v1b, eth_v1c), path = "v1/mod.rs")] |
| 5 | #[cfg_attr(eth_v2, path = "v2/mod.rs")] | 5 | #[cfg_attr(eth_v2, path = "v2/mod.rs")] |
| 6 | mod _version; | 6 | mod _version; |
| 7 | pub mod generic_smi; | 7 | pub mod generic_smi; |
| 8 | 8 | ||
| 9 | #[cfg(feature = "net")] | ||
| 10 | pub use _version::*; | 9 | pub use _version::*; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 11 | 11 | ||
| 12 | #[allow(unused)] | ||
| 13 | const MTU: usize = 1514; | ||
| 14 | const TX_BUFFER_SIZE: usize = 1514; | ||
| 15 | const RX_BUFFER_SIZE: usize = 1536; | ||
| 16 | |||
| 17 | #[repr(C, align(8))] | ||
| 18 | #[derive(Copy, Clone)] | ||
| 19 | pub(crate) struct Packet<const N: usize>([u8; N]); | ||
| 20 | |||
| 21 | pub struct PacketQueue<const TX: usize, const RX: usize> { | ||
| 22 | tx_desc: [TDes; TX], | ||
| 23 | rx_desc: [RDes; RX], | ||
| 24 | tx_buf: [Packet<TX_BUFFER_SIZE>; TX], | ||
| 25 | rx_buf: [Packet<RX_BUFFER_SIZE>; RX], | ||
| 26 | } | ||
| 27 | |||
| 28 | impl<const TX: usize, const RX: usize> PacketQueue<TX, RX> { | ||
| 29 | pub const fn new() -> Self { | ||
| 30 | const NEW_TDES: TDes = TDes::new(); | ||
| 31 | const NEW_RDES: RDes = RDes::new(); | ||
| 32 | Self { | ||
| 33 | tx_desc: [NEW_TDES; TX], | ||
| 34 | rx_desc: [NEW_RDES; RX], | ||
| 35 | tx_buf: [Packet([0; TX_BUFFER_SIZE]); TX], | ||
| 36 | rx_buf: [Packet([0; RX_BUFFER_SIZE]); RX], | ||
| 37 | } | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
| 42 | |||
| 43 | #[cfg(feature = "embassy-net")] | ||
| 44 | mod embassy_net_impl { | ||
| 45 | use core::task::Context; | ||
| 46 | |||
| 47 | use embassy_net::device::{Device, DeviceCapabilities, LinkState}; | ||
| 48 | |||
| 49 | use super::*; | ||
| 50 | |||
| 51 | impl<'d, T: Instance, P: PHY> Device for Ethernet<'d, T, P> { | ||
| 52 | type RxToken<'a> = RxToken<'a, 'd> where Self: 'a; | ||
| 53 | type TxToken<'a> = TxToken<'a, 'd> where Self: 'a; | ||
| 54 | |||
| 55 | fn receive(&mut self, cx: &mut Context) -> Option<(Self::RxToken<'_>, Self::TxToken<'_>)> { | ||
| 56 | WAKER.register(cx.waker()); | ||
| 57 | if self.rx.available().is_some() && self.tx.available().is_some() { | ||
| 58 | Some((RxToken { rx: &mut self.rx }, TxToken { tx: &mut self.tx })) | ||
| 59 | } else { | ||
| 60 | None | ||
| 61 | } | ||
| 62 | } | ||
| 63 | |||
| 64 | fn transmit(&mut self, cx: &mut Context) -> Option<Self::TxToken<'_>> { | ||
| 65 | WAKER.register(cx.waker()); | ||
| 66 | if self.tx.available().is_some() { | ||
| 67 | Some(TxToken { tx: &mut self.tx }) | ||
| 68 | } else { | ||
| 69 | None | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | fn capabilities(&self) -> DeviceCapabilities { | ||
| 74 | let mut caps = DeviceCapabilities::default(); | ||
| 75 | caps.max_transmission_unit = MTU; | ||
| 76 | caps.max_burst_size = Some(self.tx.len()); | ||
| 77 | caps | ||
| 78 | } | ||
| 79 | |||
| 80 | fn link_state(&mut self, cx: &mut Context) -> LinkState { | ||
| 81 | // TODO: wake cx.waker on link state change | ||
| 82 | cx.waker().wake_by_ref(); | ||
| 83 | if P::poll_link(self) { | ||
| 84 | LinkState::Up | ||
| 85 | } else { | ||
| 86 | LinkState::Down | ||
| 87 | } | ||
| 88 | } | ||
| 89 | |||
| 90 | fn ethernet_address(&self) -> [u8; 6] { | ||
| 91 | self.mac_addr | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | pub struct RxToken<'a, 'd> { | ||
| 96 | rx: &'a mut RDesRing<'d>, | ||
| 97 | } | ||
| 98 | |||
| 99 | impl<'a, 'd> embassy_net::device::RxToken for RxToken<'a, 'd> { | ||
| 100 | fn consume<R, F>(self, f: F) -> R | ||
| 101 | where | ||
| 102 | F: FnOnce(&mut [u8]) -> R, | ||
| 103 | { | ||
| 104 | // NOTE(unwrap): we checked the queue wasn't full when creating the token. | ||
| 105 | let pkt = unwrap!(self.rx.available()); | ||
| 106 | let r = f(pkt); | ||
| 107 | self.rx.pop_packet(); | ||
| 108 | r | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | pub struct TxToken<'a, 'd> { | ||
| 113 | tx: &'a mut TDesRing<'d>, | ||
| 114 | } | ||
| 115 | |||
| 116 | impl<'a, 'd> embassy_net::device::TxToken for TxToken<'a, 'd> { | ||
| 117 | fn consume<R, F>(self, len: usize, f: F) -> R | ||
| 118 | where | ||
| 119 | F: FnOnce(&mut [u8]) -> R, | ||
| 120 | { | ||
| 121 | // NOTE(unwrap): we checked the queue wasn't full when creating the token. | ||
| 122 | let pkt = unwrap!(self.tx.available()); | ||
| 123 | let r = f(&mut pkt[..len]); | ||
| 124 | self.tx.transmit(len); | ||
| 125 | r | ||
| 126 | } | ||
| 127 | } | ||
| 128 | } | ||
| 12 | /// Station Management Interface (SMI) on an ethernet PHY | 129 | /// Station Management Interface (SMI) on an ethernet PHY |
| 13 | /// | 130 | /// |
| 14 | /// # Safety | 131 | /// # Safety |
diff --git a/embassy-stm32/src/eth/v1/descriptors.rs b/embassy-stm32/src/eth/v1/descriptors.rs deleted file mode 100644 index 25f21ce19..000000000 --- a/embassy-stm32/src/eth/v1/descriptors.rs +++ /dev/null | |||
| @@ -1,21 +0,0 @@ | |||
| 1 | use crate::eth::_version::rx_desc::RDesRing; | ||
| 2 | use crate::eth::_version::tx_desc::TDesRing; | ||
| 3 | |||
| 4 | pub struct DescriptorRing<const T: usize, const R: usize> { | ||
| 5 | pub(crate) tx: TDesRing<T>, | ||
| 6 | pub(crate) rx: RDesRing<R>, | ||
| 7 | } | ||
| 8 | |||
| 9 | impl<const T: usize, const R: usize> DescriptorRing<T, R> { | ||
| 10 | pub const fn new() -> Self { | ||
| 11 | Self { | ||
| 12 | tx: TDesRing::new(), | ||
| 13 | rx: RDesRing::new(), | ||
| 14 | } | ||
| 15 | } | ||
| 16 | |||
| 17 | pub fn init(&mut self) { | ||
| 18 | self.tx.init(); | ||
| 19 | self.rx.init(); | ||
| 20 | } | ||
| 21 | } | ||
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 38629a932..de36d3da1 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs | |||
| @@ -1,14 +1,17 @@ | |||
| 1 | // The v1c ethernet driver was ported to embassy from the awesome stm32-eth project (https://github.com/stm32-rs/stm32-eth). | 1 | // The v1c ethernet driver was ported to embassy from the awesome stm32-eth project (https://github.com/stm32-rs/stm32-eth). |
| 2 | 2 | ||
| 3 | use core::marker::PhantomData; | 3 | mod rx_desc; |
| 4 | mod tx_desc; | ||
| 5 | |||
| 4 | use core::sync::atomic::{fence, Ordering}; | 6 | use core::sync::atomic::{fence, Ordering}; |
| 5 | use core::task::Waker; | ||
| 6 | 7 | ||
| 7 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | 8 | use embassy_cortex_m::interrupt::InterruptExt; |
| 8 | use embassy_hal_common::{into_ref, PeripheralRef}; | 9 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 9 | use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU}; | 10 | use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; |
| 10 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 11 | 11 | ||
| 12 | pub(crate) use self::rx_desc::{RDes, RDesRing}; | ||
| 13 | pub(crate) use self::tx_desc::{TDes, TDesRing}; | ||
| 14 | use super::*; | ||
| 12 | use crate::gpio::sealed::{AFType, Pin as __GpioPin}; | 15 | use crate::gpio::sealed::{AFType, Pin as __GpioPin}; |
| 13 | use crate::gpio::{AnyPin, Speed}; | 16 | use crate::gpio::{AnyPin, Speed}; |
| 14 | #[cfg(eth_v1a)] | 17 | #[cfg(eth_v1a)] |
| @@ -18,29 +21,16 @@ use crate::pac::SYSCFG; | |||
| 18 | use crate::pac::{ETH, RCC}; | 21 | use crate::pac::{ETH, RCC}; |
| 19 | use crate::Peripheral; | 22 | use crate::Peripheral; |
| 20 | 23 | ||
| 21 | mod descriptors; | 24 | pub struct Ethernet<'d, T: Instance, P: PHY> { |
| 22 | mod rx_desc; | 25 | _peri: PeripheralRef<'d, T>, |
| 23 | mod tx_desc; | 26 | pub(crate) tx: TDesRing<'d>, |
| 27 | pub(crate) rx: RDesRing<'d>, | ||
| 24 | 28 | ||
| 25 | use descriptors::DescriptorRing; | ||
| 26 | use stm32_metapac::eth::vals::{Apcs, Cr, Dm, DmaomrSr, Fes, Ftf, Ifg, MbProgress, Mw, Pbl, Rsf, St, Tsf}; | ||
| 27 | |||
| 28 | use super::*; | ||
| 29 | |||
| 30 | pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>); | ||
| 31 | impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> { | ||
| 32 | pub const fn new() -> Self { | ||
| 33 | Self(StateStorage::new()) | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | pub struct Ethernet<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> { | ||
| 38 | state: PeripheralMutex<'d, Inner<'d, T, TX, RX>>, | ||
| 39 | pins: [PeripheralRef<'d, AnyPin>; 9], | 29 | pins: [PeripheralRef<'d, AnyPin>; 9], |
| 40 | _phy: P, | 30 | _phy: P, |
| 41 | clock_range: Cr, | 31 | clock_range: Cr, |
| 42 | phy_addr: u8, | 32 | phy_addr: u8, |
| 43 | mac_addr: [u8; 6], | 33 | pub(crate) mac_addr: [u8; 6], |
| 44 | } | 34 | } |
| 45 | 35 | ||
| 46 | #[cfg(eth_v1a)] | 36 | #[cfg(eth_v1a)] |
| @@ -82,10 +72,10 @@ macro_rules! config_pins { | |||
| 82 | }; | 72 | }; |
| 83 | } | 73 | } |
| 84 | 74 | ||
| 85 | impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, P, TX, RX> { | 75 | impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { |
| 86 | /// safety: the returned instance is not leak-safe | 76 | /// safety: the returned instance is not leak-safe |
| 87 | pub unsafe fn new( | 77 | pub fn new<const TX: usize, const RX: usize>( |
| 88 | state: &'d mut State<'d, T, TX, RX>, | 78 | queue: &'d mut PacketQueue<TX, RX>, |
| 89 | peri: impl Peripheral<P = T> + 'd, | 79 | peri: impl Peripheral<P = T> + 'd, |
| 90 | interrupt: impl Peripheral<P = crate::interrupt::ETH> + 'd, | 80 | interrupt: impl Peripheral<P = crate::interrupt::ETH> + 'd, |
| 91 | ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, | 81 | ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, |
| @@ -101,134 +91,131 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, | |||
| 101 | mac_addr: [u8; 6], | 91 | mac_addr: [u8; 6], |
| 102 | phy_addr: u8, | 92 | phy_addr: u8, |
| 103 | ) -> Self { | 93 | ) -> Self { |
| 104 | into_ref!(interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 94 | into_ref!(peri, interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); |
| 105 | 95 | ||
| 106 | // Enable the necessary Clocks | 96 | unsafe { |
| 107 | // NOTE(unsafe) We have exclusive access to the registers | 97 | // Enable the necessary Clocks |
| 108 | #[cfg(eth_v1a)] | 98 | // NOTE(unsafe) We have exclusive access to the registers |
| 109 | critical_section::with(|_| { | 99 | #[cfg(eth_v1a)] |
| 110 | RCC.apb2enr().modify(|w| w.set_afioen(true)); | 100 | critical_section::with(|_| { |
| 101 | RCC.apb2enr().modify(|w| w.set_afioen(true)); | ||
| 102 | |||
| 103 | // Select RMII (Reduced Media Independent Interface) | ||
| 104 | // Must be done prior to enabling peripheral clock | ||
| 105 | AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); | ||
| 106 | |||
| 107 | RCC.ahbenr().modify(|w| { | ||
| 108 | w.set_ethen(true); | ||
| 109 | w.set_ethtxen(true); | ||
| 110 | w.set_ethrxen(true); | ||
| 111 | }); | ||
| 112 | }); | ||
| 113 | |||
| 114 | #[cfg(any(eth_v1b, eth_v1c))] | ||
| 115 | critical_section::with(|_| { | ||
| 116 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | ||
| 117 | RCC.ahb1enr().modify(|w| { | ||
| 118 | w.set_ethen(true); | ||
| 119 | w.set_ethtxen(true); | ||
| 120 | w.set_ethrxen(true); | ||
| 121 | }); | ||
| 122 | |||
| 123 | // RMII (Reduced Media Independent Interface) | ||
| 124 | SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); | ||
| 125 | }); | ||
| 126 | |||
| 127 | #[cfg(eth_v1a)] | ||
| 128 | { | ||
| 129 | config_in_pins!(ref_clk, rx_d0, rx_d1); | ||
| 130 | config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); | ||
| 131 | } | ||
| 132 | |||
| 133 | #[cfg(any(eth_v1b, eth_v1c))] | ||
| 134 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | ||
| 135 | |||
| 136 | // NOTE(unsafe) We have exclusive access to the registers | ||
| 137 | let dma = ETH.ethernet_dma(); | ||
| 138 | let mac = ETH.ethernet_mac(); | ||
| 111 | 139 | ||
| 112 | // Select RMII (Reduced Media Independent Interface) | 140 | // Reset and wait |
| 113 | // Must be done prior to enabling peripheral clock | 141 | dma.dmabmr().modify(|w| w.set_sr(true)); |
| 114 | AFIO.mapr().modify(|w| w.set_mii_rmii_sel(true)); | 142 | while dma.dmabmr().read().sr() {} |
| 115 | 143 | ||
| 116 | RCC.ahbenr().modify(|w| { | 144 | mac.maccr().modify(|w| { |
| 117 | w.set_ethen(true); | 145 | w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times |
| 118 | w.set_ethtxen(true); | 146 | w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping |
| 119 | w.set_ethrxen(true); | 147 | w.set_fes(Fes::FES100); // fast ethernet speed |
| 148 | w.set_dm(Dm::FULLDUPLEX); // full duplex | ||
| 149 | // TODO: Carrier sense ? ECRSFD | ||
| 120 | }); | 150 | }); |
| 121 | }); | ||
| 122 | 151 | ||
| 123 | #[cfg(any(eth_v1b, eth_v1c))] | 152 | // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, |
| 124 | critical_section::with(|_| { | 153 | // so the LR write must happen after the HR write. |
| 125 | RCC.apb2enr().modify(|w| w.set_syscfgen(true)); | 154 | mac.maca0hr() |
| 126 | RCC.ahb1enr().modify(|w| { | 155 | .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); |
| 127 | w.set_ethen(true); | 156 | mac.maca0lr().write(|w| { |
| 128 | w.set_ethtxen(true); | 157 | w.set_maca0l( |
| 129 | w.set_ethrxen(true); | 158 | u32::from(mac_addr[0]) |
| 159 | | (u32::from(mac_addr[1]) << 8) | ||
| 160 | | (u32::from(mac_addr[2]) << 16) | ||
| 161 | | (u32::from(mac_addr[3]) << 24), | ||
| 162 | ) | ||
| 130 | }); | 163 | }); |
| 131 | 164 | ||
| 132 | // RMII (Reduced Media Independent Interface) | 165 | // pause time |
| 133 | SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(true)); | 166 | mac.macfcr().modify(|w| w.set_pt(0x100)); |
| 134 | }); | ||
| 135 | 167 | ||
| 136 | #[cfg(eth_v1a)] | 168 | // Transfer and Forward, Receive and Forward |
| 137 | { | 169 | dma.dmaomr().modify(|w| { |
| 138 | config_in_pins!(ref_clk, rx_d0, rx_d1); | 170 | w.set_tsf(Tsf::STOREFORWARD); |
| 139 | config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_en); | 171 | w.set_rsf(Rsf::STOREFORWARD); |
| 140 | } | 172 | }); |
| 141 | 173 | ||
| 142 | #[cfg(any(eth_v1b, eth_v1c))] | 174 | dma.dmabmr().modify(|w| { |
| 143 | config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); | 175 | w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? |
| 144 | 176 | }); | |
| 145 | // NOTE(unsafe) We are ourselves not leak-safe. | 177 | |
| 146 | let state = PeripheralMutex::new(interrupt, &mut state.0, || Inner::new(peri)); | 178 | // TODO MTU size setting not found for v1 ethernet, check if correct |
| 147 | 179 | ||
| 148 | // NOTE(unsafe) We have exclusive access to the registers | 180 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called |
| 149 | let dma = ETH.ethernet_dma(); | 181 | let hclk = crate::rcc::get_freqs().ahb1; |
| 150 | let mac = ETH.ethernet_mac(); | 182 | let hclk_mhz = hclk.0 / 1_000_000; |
| 151 | 183 | ||
| 152 | // Reset and wait | 184 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz |
| 153 | dma.dmabmr().modify(|w| w.set_sr(true)); | 185 | let clock_range = match hclk_mhz { |
| 154 | while dma.dmabmr().read().sr() {} | 186 | 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), |
| 155 | 187 | 25..=34 => Cr::CR_20_35, // Divide by 16 | |
| 156 | mac.maccr().modify(|w| { | 188 | 35..=59 => Cr::CR_35_60, // Divide by 26 |
| 157 | w.set_ifg(Ifg::IFG96); // inter frame gap 96 bit times | 189 | 60..=99 => Cr::CR_60_100, // Divide by 42 |
| 158 | w.set_apcs(Apcs::STRIP); // automatic padding and crc stripping | 190 | 100..=149 => Cr::CR_100_150, // Divide by 62 |
| 159 | w.set_fes(Fes::FES100); // fast ethernet speed | 191 | 150..=216 => Cr::CR_150_168, // Divide by 102 |
| 160 | w.set_dm(Dm::FULLDUPLEX); // full duplex | 192 | _ => { |
| 161 | // TODO: Carrier sense ? ECRSFD | 193 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") |
| 162 | }); | 194 | } |
| 163 | 195 | }; | |
| 164 | // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, | 196 | |
| 165 | // so the LR write must happen after the HR write. | 197 | let pins = [ |
| 166 | mac.maca0hr() | 198 | ref_clk.map_into(), |
| 167 | .modify(|w| w.set_maca0h(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); | 199 | mdio.map_into(), |
| 168 | mac.maca0lr().write(|w| { | 200 | mdc.map_into(), |
| 169 | w.set_maca0l( | 201 | crs.map_into(), |
| 170 | u32::from(mac_addr[0]) | 202 | rx_d0.map_into(), |
| 171 | | (u32::from(mac_addr[1]) << 8) | 203 | rx_d1.map_into(), |
| 172 | | (u32::from(mac_addr[2]) << 16) | 204 | tx_d0.map_into(), |
| 173 | | (u32::from(mac_addr[3]) << 24), | 205 | tx_d1.map_into(), |
| 174 | ) | 206 | tx_en.map_into(), |
| 175 | }); | 207 | ]; |
| 176 | 208 | ||
| 177 | // pause time | 209 | let mut this = Self { |
| 178 | mac.macfcr().modify(|w| w.set_pt(0x100)); | 210 | _peri: peri, |
| 179 | 211 | pins, | |
| 180 | // Transfer and Forward, Receive and Forward | 212 | _phy: phy, |
| 181 | dma.dmaomr().modify(|w| { | 213 | clock_range, |
| 182 | w.set_tsf(Tsf::STOREFORWARD); | 214 | phy_addr, |
| 183 | w.set_rsf(Rsf::STOREFORWARD); | 215 | mac_addr, |
| 184 | }); | 216 | tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), |
| 185 | 217 | rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), | |
| 186 | dma.dmabmr().modify(|w| { | 218 | }; |
| 187 | w.set_pbl(Pbl::PBL32) // programmable burst length - 32 ? | ||
| 188 | }); | ||
| 189 | |||
| 190 | // TODO MTU size setting not found for v1 ethernet, check if correct | ||
| 191 | |||
| 192 | // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called | ||
| 193 | let hclk = crate::rcc::get_freqs().ahb1; | ||
| 194 | let hclk_mhz = hclk.0 / 1_000_000; | ||
| 195 | |||
| 196 | // Set the MDC clock frequency in the range 1MHz - 2.5MHz | ||
| 197 | let clock_range = match hclk_mhz { | ||
| 198 | 0..=24 => panic!("Invalid HCLK frequency - should be at least 25 MHz."), | ||
| 199 | 25..=34 => Cr::CR_20_35, // Divide by 16 | ||
| 200 | 35..=59 => Cr::CR_35_60, // Divide by 26 | ||
| 201 | 60..=99 => Cr::CR_60_100, // Divide by 42 | ||
| 202 | 100..=149 => Cr::CR_100_150, // Divide by 62 | ||
| 203 | 150..=216 => Cr::CR_150_168, // Divide by 102 | ||
| 204 | _ => { | ||
| 205 | panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") | ||
| 206 | } | ||
| 207 | }; | ||
| 208 | |||
| 209 | let pins = [ | ||
| 210 | ref_clk.map_into(), | ||
| 211 | mdio.map_into(), | ||
| 212 | mdc.map_into(), | ||
| 213 | crs.map_into(), | ||
| 214 | rx_d0.map_into(), | ||
| 215 | rx_d1.map_into(), | ||
| 216 | tx_d0.map_into(), | ||
| 217 | tx_d1.map_into(), | ||
| 218 | tx_en.map_into(), | ||
| 219 | ]; | ||
| 220 | |||
| 221 | let mut this = Self { | ||
| 222 | state, | ||
| 223 | pins, | ||
| 224 | _phy: phy, | ||
| 225 | clock_range, | ||
| 226 | phy_addr, | ||
| 227 | mac_addr, | ||
| 228 | }; | ||
| 229 | |||
| 230 | this.state.with(|s| { | ||
| 231 | s.desc_ring.init(); | ||
| 232 | 219 | ||
| 233 | fence(Ordering::SeqCst); | 220 | fence(Ordering::SeqCst); |
| 234 | 221 | ||
| @@ -245,23 +232,45 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, | |||
| 245 | w.set_sr(DmaomrSr::STARTED); // start receiving channel | 232 | w.set_sr(DmaomrSr::STARTED); // start receiving channel |
| 246 | }); | 233 | }); |
| 247 | 234 | ||
| 235 | this.rx.demand_poll(); | ||
| 236 | |||
| 248 | // Enable interrupts | 237 | // Enable interrupts |
| 249 | dma.dmaier().modify(|w| { | 238 | dma.dmaier().modify(|w| { |
| 250 | w.set_nise(true); | 239 | w.set_nise(true); |
| 251 | w.set_rie(true); | 240 | w.set_rie(true); |
| 252 | w.set_tie(true); | 241 | w.set_tie(true); |
| 253 | }); | 242 | }); |
| 254 | }); | ||
| 255 | P::phy_reset(&mut this); | ||
| 256 | P::phy_init(&mut this); | ||
| 257 | 243 | ||
| 258 | this | 244 | P::phy_reset(&mut this); |
| 245 | P::phy_init(&mut this); | ||
| 246 | |||
| 247 | interrupt.set_handler(Self::on_interrupt); | ||
| 248 | interrupt.enable(); | ||
| 249 | |||
| 250 | this | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | fn on_interrupt(_cx: *mut ()) { | ||
| 255 | WAKER.wake(); | ||
| 256 | |||
| 257 | // TODO: Check and clear more flags | ||
| 258 | unsafe { | ||
| 259 | let dma = ETH.ethernet_dma(); | ||
| 260 | |||
| 261 | dma.dmasr().modify(|w| { | ||
| 262 | w.set_ts(true); | ||
| 263 | w.set_rs(true); | ||
| 264 | w.set_nis(true); | ||
| 265 | }); | ||
| 266 | // Delay two peripheral's clock | ||
| 267 | dma.dmasr().read(); | ||
| 268 | dma.dmasr().read(); | ||
| 269 | } | ||
| 259 | } | 270 | } |
| 260 | } | 271 | } |
| 261 | 272 | ||
| 262 | unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationManagement | 273 | unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { |
| 263 | for Ethernet<'d, T, P, TX, RX> | ||
| 264 | { | ||
| 265 | fn smi_read(&mut self, reg: u8) -> u16 { | 274 | fn smi_read(&mut self, reg: u8) -> u16 { |
| 266 | // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` | 275 | // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` |
| 267 | unsafe { | 276 | unsafe { |
| @@ -297,44 +306,7 @@ unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationMa | |||
| 297 | } | 306 | } |
| 298 | } | 307 | } |
| 299 | 308 | ||
| 300 | impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Device for Ethernet<'d, T, P, TX, RX> { | 309 | impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { |
| 301 | fn is_transmit_ready(&mut self) -> bool { | ||
| 302 | self.state.with(|s| s.desc_ring.tx.available()) | ||
| 303 | } | ||
| 304 | |||
| 305 | fn transmit(&mut self, pkt: PacketBuf) { | ||
| 306 | self.state.with(|s| unwrap!(s.desc_ring.tx.transmit(pkt))); | ||
| 307 | } | ||
| 308 | |||
| 309 | fn receive(&mut self) -> Option<PacketBuf> { | ||
| 310 | self.state.with(|s| s.desc_ring.rx.pop_packet()) | ||
| 311 | } | ||
| 312 | |||
| 313 | fn register_waker(&mut self, waker: &Waker) { | ||
| 314 | WAKER.register(waker); | ||
| 315 | } | ||
| 316 | |||
| 317 | fn capabilities(&self) -> DeviceCapabilities { | ||
| 318 | let mut caps = DeviceCapabilities::default(); | ||
| 319 | caps.max_transmission_unit = MTU; | ||
| 320 | caps.max_burst_size = Some(TX.min(RX)); | ||
| 321 | caps | ||
| 322 | } | ||
| 323 | |||
| 324 | fn link_state(&mut self) -> LinkState { | ||
| 325 | if P::poll_link(self) { | ||
| 326 | LinkState::Up | ||
| 327 | } else { | ||
| 328 | LinkState::Down | ||
| 329 | } | ||
| 330 | } | ||
| 331 | |||
| 332 | fn ethernet_address(&self) -> [u8; 6] { | ||
| 333 | self.mac_addr | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Ethernet<'d, T, P, TX, RX> { | ||
| 338 | fn drop(&mut self) { | 310 | fn drop(&mut self) { |
| 339 | // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers | 311 | // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers |
| 340 | unsafe { | 312 | unsafe { |
| @@ -361,46 +333,3 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Etherne | |||
| 361 | }) | 333 | }) |
| 362 | } | 334 | } |
| 363 | } | 335 | } |
| 364 | |||
| 365 | //---------------------------------------------------------------------- | ||
| 366 | |||
| 367 | struct Inner<'d, T: Instance, const TX: usize, const RX: usize> { | ||
| 368 | _peri: PhantomData<&'d mut T>, | ||
| 369 | desc_ring: DescriptorRing<TX, RX>, | ||
| 370 | } | ||
| 371 | |||
| 372 | impl<'d, T: Instance, const TX: usize, const RX: usize> Inner<'d, T, TX, RX> { | ||
| 373 | pub fn new(_peri: impl Peripheral<P = T> + 'd) -> Self { | ||
| 374 | Self { | ||
| 375 | _peri: PhantomData, | ||
| 376 | desc_ring: DescriptorRing::new(), | ||
| 377 | } | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | impl<'d, T: Instance, const TX: usize, const RX: usize> PeripheralState for Inner<'d, T, TX, RX> { | ||
| 382 | type Interrupt = crate::interrupt::ETH; | ||
| 383 | |||
| 384 | fn on_interrupt(&mut self) { | ||
| 385 | unwrap!(self.desc_ring.tx.on_interrupt()); | ||
| 386 | self.desc_ring.rx.on_interrupt(); | ||
| 387 | |||
| 388 | WAKER.wake(); | ||
| 389 | |||
| 390 | // TODO: Check and clear more flags | ||
| 391 | unsafe { | ||
| 392 | let dma = ETH.ethernet_dma(); | ||
| 393 | |||
| 394 | dma.dmasr().modify(|w| { | ||
| 395 | w.set_ts(true); | ||
| 396 | w.set_rs(true); | ||
| 397 | w.set_nis(true); | ||
| 398 | }); | ||
| 399 | // Delay two peripheral's clock | ||
| 400 | dma.dmasr().read(); | ||
| 401 | dma.dmasr().read(); | ||
| 402 | } | ||
| 403 | } | ||
| 404 | } | ||
| 405 | |||
| 406 | static WAKER: AtomicWaker = AtomicWaker::new(); | ||
diff --git a/embassy-stm32/src/eth/v1/rx_desc.rs b/embassy-stm32/src/eth/v1/rx_desc.rs index d482590a1..8b8566d92 100644 --- a/embassy-stm32/src/eth/v1/rx_desc.rs +++ b/embassy-stm32/src/eth/v1/rx_desc.rs | |||
| @@ -1,9 +1,9 @@ | |||
| 1 | use core::sync::atomic::{compiler_fence, fence, Ordering}; | 1 | use core::sync::atomic::{compiler_fence, fence, Ordering}; |
| 2 | 2 | ||
| 3 | use embassy_net::{Packet, PacketBox, PacketBoxExt, PacketBuf}; | 3 | use stm32_metapac::eth::vals::{Rpd, Rps}; |
| 4 | use stm32_metapac::eth::vals::{DmaomrSr, Rpd, Rps}; | ||
| 5 | use vcell::VolatileCell; | 4 | use vcell::VolatileCell; |
| 6 | 5 | ||
| 6 | use crate::eth::RX_BUFFER_SIZE; | ||
| 7 | use crate::pac::ETH; | 7 | use crate::pac::ETH; |
| 8 | 8 | ||
| 9 | mod rx_consts { | 9 | mod rx_consts { |
| @@ -28,6 +28,8 @@ mod rx_consts { | |||
| 28 | 28 | ||
| 29 | use rx_consts::*; | 29 | use rx_consts::*; |
| 30 | 30 | ||
| 31 | use super::Packet; | ||
| 32 | |||
| 31 | /// Receive Descriptor representation | 33 | /// Receive Descriptor representation |
| 32 | /// | 34 | /// |
| 33 | /// * rdes0: OWN and Status | 35 | /// * rdes0: OWN and Status |
| @@ -35,7 +37,7 @@ use rx_consts::*; | |||
| 35 | /// * rdes2: data buffer address | 37 | /// * rdes2: data buffer address |
| 36 | /// * rdes3: next descriptor address | 38 | /// * rdes3: next descriptor address |
| 37 | #[repr(C)] | 39 | #[repr(C)] |
| 38 | struct RDes { | 40 | pub(crate) struct RDes { |
| 39 | rdes0: VolatileCell<u32>, | 41 | rdes0: VolatileCell<u32>, |
| 40 | rdes1: VolatileCell<u32>, | 42 | rdes1: VolatileCell<u32>, |
| 41 | rdes2: VolatileCell<u32>, | 43 | rdes2: VolatileCell<u32>, |
| @@ -54,7 +56,7 @@ impl RDes { | |||
| 54 | 56 | ||
| 55 | /// Return true if this RDes is acceptable to us | 57 | /// Return true if this RDes is acceptable to us |
| 56 | #[inline(always)] | 58 | #[inline(always)] |
| 57 | pub fn valid(&self) -> bool { | 59 | fn valid(&self) -> bool { |
| 58 | // Write-back descriptor is valid if: | 60 | // Write-back descriptor is valid if: |
| 59 | // | 61 | // |
| 60 | // Contains first buffer of packet AND contains last buf of | 62 | // Contains first buffer of packet AND contains last buf of |
| @@ -64,15 +66,16 @@ impl RDes { | |||
| 64 | 66 | ||
| 65 | /// Return true if this RDes is not currently owned by the DMA | 67 | /// Return true if this RDes is not currently owned by the DMA |
| 66 | #[inline(always)] | 68 | #[inline(always)] |
| 67 | pub fn available(&self) -> bool { | 69 | fn available(&self) -> bool { |
| 68 | self.rdes0.get() & RXDESC_0_OWN == 0 // Owned by us | 70 | self.rdes0.get() & RXDESC_0_OWN == 0 // Owned by us |
| 69 | } | 71 | } |
| 70 | 72 | ||
| 71 | /// Configures the reception buffer address and length and passed descriptor ownership to the DMA | 73 | /// Configures the reception buffer address and length and passed descriptor ownership to the DMA |
| 72 | #[inline(always)] | 74 | #[inline(always)] |
| 73 | pub fn set_ready(&mut self, buf_addr: u32, buf_len: usize) { | 75 | fn set_ready(&self, buf: *mut u8) { |
| 74 | self.rdes1.set(self.rdes1.get() | (buf_len as u32) & RXDESC_1_RBS_MASK); | 76 | self.rdes1 |
| 75 | self.rdes2.set(buf_addr); | 77 | .set(self.rdes1.get() | (RX_BUFFER_SIZE as u32) & RXDESC_1_RBS_MASK); |
| 78 | self.rdes2.set(buf as u32); | ||
| 76 | 79 | ||
| 77 | // "Preceding reads and writes cannot be moved past subsequent writes." | 80 | // "Preceding reads and writes cannot be moved past subsequent writes." |
| 78 | fence(Ordering::Release); | 81 | fence(Ordering::Release); |
| @@ -88,12 +91,12 @@ impl RDes { | |||
| 88 | 91 | ||
| 89 | // points to next descriptor (RCH) | 92 | // points to next descriptor (RCH) |
| 90 | #[inline(always)] | 93 | #[inline(always)] |
| 91 | fn set_buffer2(&mut self, buffer: *const u8) { | 94 | fn set_buffer2(&self, buffer: *const u8) { |
| 92 | self.rdes3.set(buffer as u32); | 95 | self.rdes3.set(buffer as u32); |
| 93 | } | 96 | } |
| 94 | 97 | ||
| 95 | #[inline(always)] | 98 | #[inline(always)] |
| 96 | fn set_end_of_ring(&mut self) { | 99 | fn set_end_of_ring(&self) { |
| 97 | self.rdes1.set(self.rdes1.get() | RXDESC_1_RER); | 100 | self.rdes1.set(self.rdes1.get() | RXDESC_1_RER); |
| 98 | } | 101 | } |
| 99 | 102 | ||
| @@ -102,7 +105,7 @@ impl RDes { | |||
| 102 | ((self.rdes0.get() >> RXDESC_0_FL_SHIFT) & RXDESC_0_FL_MASK) as usize | 105 | ((self.rdes0.get() >> RXDESC_0_FL_SHIFT) & RXDESC_0_FL_MASK) as usize |
| 103 | } | 106 | } |
| 104 | 107 | ||
| 105 | pub fn setup(&mut self, next: Option<&Self>) { | 108 | fn setup(&self, next: Option<&Self>, buf: *mut u8) { |
| 106 | // Defer this initialization to this function, so we can have `RingEntry` on bss. | 109 | // Defer this initialization to this function, so we can have `RingEntry` on bss. |
| 107 | self.rdes1.set(self.rdes1.get() | RXDESC_1_RCH); | 110 | self.rdes1.set(self.rdes1.get() | RXDESC_1_RCH); |
| 108 | 111 | ||
| @@ -113,8 +116,11 @@ impl RDes { | |||
| 113 | self.set_end_of_ring(); | 116 | self.set_end_of_ring(); |
| 114 | } | 117 | } |
| 115 | } | 118 | } |
| 119 | |||
| 120 | self.set_ready(buf); | ||
| 116 | } | 121 | } |
| 117 | } | 122 | } |
| 123 | |||
| 118 | /// Running state of the `RxRing` | 124 | /// Running state of the `RxRing` |
| 119 | #[derive(PartialEq, Eq, Debug)] | 125 | #[derive(PartialEq, Eq, Debug)] |
| 120 | pub enum RunningState { | 126 | pub enum RunningState { |
| @@ -123,116 +129,42 @@ pub enum RunningState { | |||
| 123 | Running, | 129 | Running, |
| 124 | } | 130 | } |
| 125 | 131 | ||
| 126 | impl RunningState { | ||
| 127 | /// whether self equals to `RunningState::Running` | ||
| 128 | pub fn is_running(&self) -> bool { | ||
| 129 | *self == RunningState::Running | ||
| 130 | } | ||
| 131 | } | ||
| 132 | |||
| 133 | /// Rx ring of descriptors and packets | 132 | /// Rx ring of descriptors and packets |
| 134 | /// | 133 | pub(crate) struct RDesRing<'a> { |
| 135 | /// This ring has three major locations that work in lock-step. The DMA will never write to the tail | 134 | descriptors: &'a mut [RDes], |
| 136 | /// index, so the `read_index` must never pass the tail index. The `next_tail_index` is always 1 | 135 | buffers: &'a mut [Packet<RX_BUFFER_SIZE>], |
| 137 | /// slot ahead of the real tail index, and it must never pass the `read_index` or it could overwrite | 136 | index: usize, |
| 138 | /// a packet still to be passed to the application. | ||
| 139 | /// | ||
| 140 | /// nt can't pass r (no alloc) | ||
| 141 | /// +---+---+---+---+ Read ok +---+---+---+---+ No Read +---+---+---+---+ | ||
| 142 | /// | | | | | ------------> | | | | | ------------> | | | | | | ||
| 143 | /// +---+---+---+---+ Allocation ok +---+---+---+---+ +---+---+---+---+ | ||
| 144 | /// ^ ^t ^t ^ ^t ^ | ||
| 145 | /// |r |r |r | ||
| 146 | /// |nt |nt |nt | ||
| 147 | /// | ||
| 148 | /// | ||
| 149 | /// +---+---+---+---+ Read ok +---+---+---+---+ Can't read +---+---+---+---+ | ||
| 150 | /// | | | | | ------------> | | | | | ------------> | | | | | | ||
| 151 | /// +---+---+---+---+ Allocation fail +---+---+---+---+ Allocation ok +---+---+---+---+ | ||
| 152 | /// ^ ^t ^ ^t ^ ^ ^ ^t | ||
| 153 | /// |r | |r | | |r | ||
| 154 | /// |nt |nt |nt | ||
| 155 | /// | ||
| 156 | pub(crate) struct RDesRing<const N: usize> { | ||
| 157 | descriptors: [RDes; N], | ||
| 158 | buffers: [Option<PacketBox>; N], | ||
| 159 | read_index: usize, | ||
| 160 | next_tail_index: usize, | ||
| 161 | } | 137 | } |
| 162 | 138 | ||
| 163 | impl<const N: usize> RDesRing<N> { | 139 | impl<'a> RDesRing<'a> { |
| 164 | pub const fn new() -> Self { | 140 | pub(crate) fn new(descriptors: &'a mut [RDes], buffers: &'a mut [Packet<RX_BUFFER_SIZE>]) -> Self { |
| 165 | const RDES: RDes = RDes::new(); | 141 | assert!(descriptors.len() > 1); |
| 166 | const BUFFERS: Option<PacketBox> = None; | 142 | assert!(descriptors.len() == buffers.len()); |
| 167 | |||
| 168 | Self { | ||
| 169 | descriptors: [RDES; N], | ||
| 170 | buffers: [BUFFERS; N], | ||
| 171 | read_index: 0, | ||
| 172 | next_tail_index: 0, | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | pub(crate) fn init(&mut self) { | ||
| 177 | assert!(N > 1); | ||
| 178 | let mut last_index = 0; | ||
| 179 | for (index, buf) in self.buffers.iter_mut().enumerate() { | ||
| 180 | let pkt = match PacketBox::new(Packet::new()) { | ||
| 181 | Some(p) => p, | ||
| 182 | None => { | ||
| 183 | if index == 0 { | ||
| 184 | panic!("Could not allocate at least one buffer for Ethernet receiving"); | ||
| 185 | } else { | ||
| 186 | break; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | }; | ||
| 190 | self.descriptors[index].set_ready(pkt.as_ptr() as u32, pkt.len()); | ||
| 191 | *buf = Some(pkt); | ||
| 192 | last_index = index; | ||
| 193 | } | ||
| 194 | self.next_tail_index = (last_index + 1) % N; | ||
| 195 | |||
| 196 | // not sure if this is supposed to span all of the descriptor or just those that contain buffers | ||
| 197 | { | ||
| 198 | let mut previous: Option<&mut RDes> = None; | ||
| 199 | for entry in self.descriptors.iter_mut() { | ||
| 200 | if let Some(prev) = &mut previous { | ||
| 201 | prev.setup(Some(entry)); | ||
| 202 | } | ||
| 203 | previous = Some(entry); | ||
| 204 | } | ||
| 205 | 143 | ||
| 206 | if let Some(entry) = &mut previous { | 144 | for (i, entry) in descriptors.iter().enumerate() { |
| 207 | entry.setup(None); | 145 | entry.setup(descriptors.get(i + 1), buffers[i].0.as_mut_ptr()); |
| 208 | } | ||
| 209 | } | 146 | } |
| 210 | 147 | ||
| 211 | // Register txdescriptor start | 148 | // Register rx descriptor start |
| 212 | // NOTE (unsafe) Used for atomic writes | 149 | // NOTE (unsafe) Used for atomic writes |
| 213 | unsafe { | 150 | unsafe { |
| 214 | ETH.ethernet_dma() | 151 | ETH.ethernet_dma() |
| 215 | .dmardlar() | 152 | .dmardlar() |
| 216 | .write(|w| w.0 = &self.descriptors as *const _ as u32); | 153 | .write(|w| w.0 = descriptors.as_ptr() as u32); |
| 217 | }; | 154 | }; |
| 218 | // We already have fences in `set_owned`, which is called in `setup` | 155 | // We already have fences in `set_owned`, which is called in `setup` |
| 219 | 156 | ||
| 220 | // Start receive | 157 | Self { |
| 221 | unsafe { ETH.ethernet_dma().dmaomr().modify(|w| w.set_sr(DmaomrSr::STARTED)) }; | 158 | descriptors, |
| 222 | 159 | buffers, | |
| 223 | self.demand_poll(); | 160 | index: 0, |
| 161 | } | ||
| 224 | } | 162 | } |
| 225 | 163 | ||
| 226 | fn demand_poll(&self) { | 164 | pub(crate) fn demand_poll(&self) { |
| 227 | unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) }; | 165 | unsafe { ETH.ethernet_dma().dmarpdr().write(|w| w.set_rpd(Rpd::POLL)) }; |
| 228 | } | 166 | } |
| 229 | 167 | ||
| 230 | pub(crate) fn on_interrupt(&mut self) { | ||
| 231 | // XXX: Do we need to do anything here ? Maybe we should try to advance the tail ptr, but it | ||
| 232 | // would soon hit the read ptr anyway, and we will wake smoltcp's stack on the interrupt | ||
| 233 | // which should try to pop a packet... | ||
| 234 | } | ||
| 235 | |||
| 236 | /// Get current `RunningState` | 168 | /// Get current `RunningState` |
| 237 | fn running_state(&self) -> RunningState { | 169 | fn running_state(&self) -> RunningState { |
| 238 | match unsafe { ETH.ethernet_dma().dmasr().read().rps() } { | 170 | match unsafe { ETH.ethernet_dma().dmasr().read().rps() } { |
| @@ -252,52 +184,52 @@ impl<const N: usize> RDesRing<N> { | |||
| 252 | } | 184 | } |
| 253 | } | 185 | } |
| 254 | 186 | ||
| 255 | pub(crate) fn pop_packet(&mut self) -> Option<PacketBuf> { | 187 | /// Get a received packet if any, or None. |
| 256 | if !self.running_state().is_running() { | 188 | pub(crate) fn available(&mut self) -> Option<&mut [u8]> { |
| 189 | if self.running_state() != RunningState::Running { | ||
| 257 | self.demand_poll(); | 190 | self.demand_poll(); |
| 258 | } | 191 | } |
| 192 | |||
| 259 | // Not sure if the contents of the write buffer on the M7 can affects reads, so we are using | 193 | // Not sure if the contents of the write buffer on the M7 can affects reads, so we are using |
| 260 | // a DMB here just in case, it also serves as a hint to the compiler that we're syncing the | 194 | // a DMB here just in case, it also serves as a hint to the compiler that we're syncing the |
| 261 | // buffer (I think .-.) | 195 | // buffer (I think .-.) |
| 262 | fence(Ordering::SeqCst); | 196 | fence(Ordering::SeqCst); |
| 263 | 197 | ||
| 264 | let read_available = self.descriptors[self.read_index].available(); | 198 | // We might have to process many packets, in case some have been rx'd but are invalid. |
| 265 | let tail_index = (self.next_tail_index + N - 1) % N; | 199 | loop { |
| 200 | let descriptor = &mut self.descriptors[self.index]; | ||
| 201 | if !descriptor.available() { | ||
| 202 | return None; | ||
| 203 | } | ||
| 266 | 204 | ||
| 267 | let pkt = if read_available && self.read_index != tail_index { | 205 | // If packet is invalid, pop it and try again. |
| 268 | let pkt = self.buffers[self.read_index].take(); | 206 | if !descriptor.valid() { |
| 269 | let len = self.descriptors[self.read_index].packet_len(); | 207 | warn!("invalid packet: {:08x}", descriptor.rdes0.get()); |
| 208 | self.pop_packet(); | ||
| 209 | continue; | ||
| 210 | } | ||
| 270 | 211 | ||
| 271 | assert!(pkt.is_some()); | 212 | break; |
| 272 | let valid = self.descriptors[self.read_index].valid(); | 213 | } |
| 273 | 214 | ||
| 274 | self.read_index = (self.read_index + 1) % N; | 215 | let descriptor = &mut self.descriptors[self.index]; |
| 275 | if valid { | 216 | let len = descriptor.packet_len(); |
| 276 | pkt.map(|p| p.slice(0..len)) | 217 | return Some(&mut self.buffers[self.index].0[..len]); |
| 277 | } else { | 218 | } |
| 278 | None | ||
| 279 | } | ||
| 280 | } else { | ||
| 281 | None | ||
| 282 | }; | ||
| 283 | 219 | ||
| 284 | // Try to advance the tail_index | 220 | /// Pop the packet previously returned by `available`. |
| 285 | if self.next_tail_index != self.read_index { | 221 | pub(crate) fn pop_packet(&mut self) { |
| 286 | match PacketBox::new(Packet::new()) { | 222 | let descriptor = &mut self.descriptors[self.index]; |
| 287 | Some(b) => { | 223 | assert!(descriptor.available()); |
| 288 | let addr = b.as_ptr() as u32; | 224 | |
| 289 | let buffer_len = b.len(); | 225 | self.descriptors[self.index].set_ready(self.buffers[self.index].0.as_mut_ptr()); |
| 290 | self.buffers[self.next_tail_index].replace(b); | 226 | |
| 291 | self.descriptors[self.next_tail_index].set_ready(addr, buffer_len); | 227 | self.demand_poll(); |
| 292 | 228 | ||
| 293 | // "Preceding reads and writes cannot be moved past subsequent writes." | 229 | // Increment index. |
| 294 | fence(Ordering::Release); | 230 | self.index += 1; |
| 295 | 231 | if self.index == self.descriptors.len() { | |
| 296 | self.next_tail_index = (self.next_tail_index + 1) % N; | 232 | self.index = 0 |
| 297 | } | ||
| 298 | None => {} | ||
| 299 | } | ||
| 300 | } | 233 | } |
| 301 | pkt | ||
| 302 | } | 234 | } |
| 303 | } | 235 | } |
diff --git a/embassy-stm32/src/eth/v1/tx_desc.rs b/embassy-stm32/src/eth/v1/tx_desc.rs index f2889b550..0e63c5443 100644 --- a/embassy-stm32/src/eth/v1/tx_desc.rs +++ b/embassy-stm32/src/eth/v1/tx_desc.rs | |||
| @@ -1,20 +1,10 @@ | |||
| 1 | use core::sync::atomic::{compiler_fence, fence, Ordering}; | 1 | use core::sync::atomic::{compiler_fence, fence, Ordering}; |
| 2 | 2 | ||
| 3 | use embassy_net::PacketBuf; | ||
| 4 | use stm32_metapac::eth::vals::St; | ||
| 5 | use vcell::VolatileCell; | 3 | use vcell::VolatileCell; |
| 6 | 4 | ||
| 5 | use crate::eth::TX_BUFFER_SIZE; | ||
| 7 | use crate::pac::ETH; | 6 | use crate::pac::ETH; |
| 8 | 7 | ||
| 9 | #[non_exhaustive] | ||
| 10 | #[derive(Debug, Copy, Clone)] | ||
| 11 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 12 | pub enum Error { | ||
| 13 | NoBufferAvailable, | ||
| 14 | // TODO: Break down this error into several others | ||
| 15 | TransmissionError, | ||
| 16 | } | ||
| 17 | |||
| 18 | /// Transmit and Receive Descriptor fields | 8 | /// Transmit and Receive Descriptor fields |
| 19 | #[allow(dead_code)] | 9 | #[allow(dead_code)] |
| 20 | mod tx_consts { | 10 | mod tx_consts { |
| @@ -37,6 +27,8 @@ mod tx_consts { | |||
| 37 | } | 27 | } |
| 38 | use tx_consts::*; | 28 | use tx_consts::*; |
| 39 | 29 | ||
| 30 | use super::Packet; | ||
| 31 | |||
| 40 | /// Transmit Descriptor representation | 32 | /// Transmit Descriptor representation |
| 41 | /// | 33 | /// |
| 42 | /// * tdes0: control | 34 | /// * tdes0: control |
| @@ -44,7 +36,7 @@ use tx_consts::*; | |||
| 44 | /// * tdes2: data buffer address | 36 | /// * tdes2: data buffer address |
| 45 | /// * tdes3: next descriptor address | 37 | /// * tdes3: next descriptor address |
| 46 | #[repr(C)] | 38 | #[repr(C)] |
| 47 | struct TDes { | 39 | pub(crate) struct TDes { |
| 48 | tdes0: VolatileCell<u32>, | 40 | tdes0: VolatileCell<u32>, |
| 49 | tdes1: VolatileCell<u32>, | 41 | tdes1: VolatileCell<u32>, |
| 50 | tdes2: VolatileCell<u32>, | 42 | tdes2: VolatileCell<u32>, |
| @@ -62,7 +54,7 @@ impl TDes { | |||
| 62 | } | 54 | } |
| 63 | 55 | ||
| 64 | /// Return true if this TDes is not currently owned by the DMA | 56 | /// Return true if this TDes is not currently owned by the DMA |
| 65 | pub fn available(&self) -> bool { | 57 | fn available(&self) -> bool { |
| 66 | (self.tdes0.get() & TXDESC_0_OWN) == 0 | 58 | (self.tdes0.get() & TXDESC_0_OWN) == 0 |
| 67 | } | 59 | } |
| 68 | 60 | ||
| @@ -79,26 +71,26 @@ impl TDes { | |||
| 79 | fence(Ordering::SeqCst); | 71 | fence(Ordering::SeqCst); |
| 80 | } | 72 | } |
| 81 | 73 | ||
| 82 | fn set_buffer1(&mut self, buffer: *const u8) { | 74 | fn set_buffer1(&self, buffer: *const u8) { |
| 83 | self.tdes2.set(buffer as u32); | 75 | self.tdes2.set(buffer as u32); |
| 84 | } | 76 | } |
| 85 | 77 | ||
| 86 | fn set_buffer1_len(&mut self, len: usize) { | 78 | fn set_buffer1_len(&self, len: usize) { |
| 87 | self.tdes1 | 79 | self.tdes1 |
| 88 | .set((self.tdes1.get() & !TXDESC_1_TBS_MASK) | ((len as u32) << TXDESC_1_TBS_SHIFT)); | 80 | .set((self.tdes1.get() & !TXDESC_1_TBS_MASK) | ((len as u32) << TXDESC_1_TBS_SHIFT)); |
| 89 | } | 81 | } |
| 90 | 82 | ||
| 91 | // points to next descriptor (RCH) | 83 | // points to next descriptor (RCH) |
| 92 | fn set_buffer2(&mut self, buffer: *const u8) { | 84 | fn set_buffer2(&self, buffer: *const u8) { |
| 93 | self.tdes3.set(buffer as u32); | 85 | self.tdes3.set(buffer as u32); |
| 94 | } | 86 | } |
| 95 | 87 | ||
| 96 | fn set_end_of_ring(&mut self) { | 88 | fn set_end_of_ring(&self) { |
| 97 | self.tdes0.set(self.tdes0.get() | TXDESC_0_TER); | 89 | self.tdes0.set(self.tdes0.get() | TXDESC_0_TER); |
| 98 | } | 90 | } |
| 99 | 91 | ||
| 100 | // set up as a part fo the ring buffer - configures the tdes | 92 | // set up as a part fo the ring buffer - configures the tdes |
| 101 | pub fn setup(&mut self, next: Option<&Self>) { | 93 | fn setup(&self, next: Option<&Self>) { |
| 102 | // Defer this initialization to this function, so we can have `RingEntry` on bss. | 94 | // Defer this initialization to this function, so we can have `RingEntry` on bss. |
| 103 | self.tdes0.set(TXDESC_0_TCH | TXDESC_0_IOC | TXDESC_0_FS | TXDESC_0_LS); | 95 | self.tdes0.set(TXDESC_0_TCH | TXDESC_0_IOC | TXDESC_0_FS | TXDESC_0_LS); |
| 104 | match next { | 96 | match next { |
| @@ -111,85 +103,58 @@ impl TDes { | |||
| 111 | } | 103 | } |
| 112 | } | 104 | } |
| 113 | 105 | ||
| 114 | pub(crate) struct TDesRing<const N: usize> { | 106 | pub(crate) struct TDesRing<'a> { |
| 115 | descriptors: [TDes; N], | 107 | descriptors: &'a mut [TDes], |
| 116 | buffers: [Option<PacketBuf>; N], | 108 | buffers: &'a mut [Packet<TX_BUFFER_SIZE>], |
| 117 | next_entry: usize, | 109 | index: usize, |
| 118 | } | 110 | } |
| 119 | 111 | ||
| 120 | impl<const N: usize> TDesRing<N> { | 112 | impl<'a> TDesRing<'a> { |
| 121 | pub const fn new() -> Self { | ||
| 122 | const TDES: TDes = TDes::new(); | ||
| 123 | const BUFFERS: Option<PacketBuf> = None; | ||
| 124 | |||
| 125 | Self { | ||
| 126 | descriptors: [TDES; N], | ||
| 127 | buffers: [BUFFERS; N], | ||
| 128 | next_entry: 0, | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | /// Initialise this TDesRing. Assume TDesRing is corrupt | 113 | /// Initialise this TDesRing. Assume TDesRing is corrupt |
| 133 | /// | 114 | pub(crate) fn new(descriptors: &'a mut [TDes], buffers: &'a mut [Packet<TX_BUFFER_SIZE>]) -> Self { |
| 134 | /// The current memory address of the buffers inside this TDesRing | 115 | assert!(descriptors.len() > 0); |
| 135 | /// will be stored in the descriptors, so ensure the TDesRing is | 116 | assert!(descriptors.len() == buffers.len()); |
| 136 | /// not moved after initialisation. | ||
| 137 | pub(crate) fn init(&mut self) { | ||
| 138 | assert!(N > 0); | ||
| 139 | |||
| 140 | { | ||
| 141 | let mut previous: Option<&mut TDes> = None; | ||
| 142 | for entry in self.descriptors.iter_mut() { | ||
| 143 | if let Some(prev) = &mut previous { | ||
| 144 | prev.setup(Some(entry)); | ||
| 145 | } | ||
| 146 | previous = Some(entry); | ||
| 147 | } | ||
| 148 | 117 | ||
| 149 | if let Some(entry) = &mut previous { | 118 | for (i, entry) in descriptors.iter().enumerate() { |
| 150 | entry.setup(None); | 119 | entry.setup(descriptors.get(i + 1)); |
| 151 | } | ||
| 152 | } | 120 | } |
| 153 | self.next_entry = 0; | ||
| 154 | 121 | ||
| 155 | // Register txdescriptor start | 122 | // Register txdescriptor start |
| 156 | // NOTE (unsafe) Used for atomic writes | 123 | // NOTE (unsafe) Used for atomic writes |
| 157 | unsafe { | 124 | unsafe { |
| 158 | ETH.ethernet_dma() | 125 | ETH.ethernet_dma() |
| 159 | .dmatdlar() | 126 | .dmatdlar() |
| 160 | .write(|w| w.0 = &self.descriptors as *const _ as u32); | 127 | .write(|w| w.0 = descriptors.as_ptr() as u32); |
| 161 | } | 128 | } |
| 162 | 129 | ||
| 163 | // "Preceding reads and writes cannot be moved past subsequent writes." | 130 | Self { |
| 164 | #[cfg(feature = "fence")] | 131 | descriptors, |
| 165 | fence(Ordering::Release); | 132 | buffers, |
| 166 | 133 | index: 0, | |
| 167 | // We don't need a compiler fence here because all interactions with `Descriptor` are | 134 | } |
| 168 | // volatiles | ||
| 169 | |||
| 170 | // Start transmission | ||
| 171 | unsafe { ETH.ethernet_dma().dmaomr().modify(|w| w.set_st(St::STARTED)) }; | ||
| 172 | } | 135 | } |
| 173 | 136 | ||
| 174 | /// Return true if a TDes is available for use | 137 | pub(crate) fn len(&self) -> usize { |
| 175 | pub(crate) fn available(&self) -> bool { | 138 | self.descriptors.len() |
| 176 | self.descriptors[self.next_entry].available() | ||
| 177 | } | 139 | } |
| 178 | 140 | ||
| 179 | pub(crate) fn transmit(&mut self, pkt: PacketBuf) -> Result<(), Error> { | 141 | /// Return the next available packet buffer for transmitting, or None |
| 180 | if !self.available() { | 142 | pub(crate) fn available(&mut self) -> Option<&mut [u8]> { |
| 181 | return Err(Error::NoBufferAvailable); | 143 | let descriptor = &mut self.descriptors[self.index]; |
| 144 | if descriptor.available() { | ||
| 145 | Some(&mut self.buffers[self.index].0) | ||
| 146 | } else { | ||
| 147 | None | ||
| 182 | } | 148 | } |
| 149 | } | ||
| 183 | 150 | ||
| 184 | let descriptor = &mut self.descriptors[self.next_entry]; | 151 | /// Transmit the packet written in a buffer returned by `available`. |
| 185 | 152 | pub(crate) fn transmit(&mut self, len: usize) { | |
| 186 | let pkt_len = pkt.len(); | 153 | let descriptor = &mut self.descriptors[self.index]; |
| 187 | let address = pkt.as_ptr() as *const u8; | 154 | assert!(descriptor.available()); |
| 188 | |||
| 189 | descriptor.set_buffer1(address); | ||
| 190 | descriptor.set_buffer1_len(pkt_len); | ||
| 191 | 155 | ||
| 192 | self.buffers[self.next_entry].replace(pkt); | 156 | descriptor.set_buffer1(self.buffers[self.index].0.as_ptr()); |
| 157 | descriptor.set_buffer1_len(len); | ||
| 193 | 158 | ||
| 194 | descriptor.set_owned(); | 159 | descriptor.set_owned(); |
| 195 | 160 | ||
| @@ -198,36 +163,12 @@ impl<const N: usize> TDesRing<N> { | |||
| 198 | // "Preceding reads and writes cannot be moved past subsequent writes." | 163 | // "Preceding reads and writes cannot be moved past subsequent writes." |
| 199 | fence(Ordering::Release); | 164 | fence(Ordering::Release); |
| 200 | 165 | ||
| 201 | // Move the tail pointer (TPR) to the next descriptor | 166 | // Move the index to the next descriptor |
| 202 | self.next_entry = (self.next_entry + 1) % N; | 167 | self.index += 1; |
| 203 | 168 | if self.index == self.descriptors.len() { | |
| 169 | self.index = 0 | ||
| 170 | } | ||
| 204 | // Request the DMA engine to poll the latest tx descriptor | 171 | // Request the DMA engine to poll the latest tx descriptor |
| 205 | unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) } | 172 | unsafe { ETH.ethernet_dma().dmatpdr().modify(|w| w.0 = 1) } |
| 206 | Ok(()) | ||
| 207 | } | ||
| 208 | |||
| 209 | pub(crate) fn on_interrupt(&mut self) -> Result<(), Error> { | ||
| 210 | let previous = (self.next_entry + N - 1) % N; | ||
| 211 | let td = &self.descriptors[previous]; | ||
| 212 | |||
| 213 | // DMB to ensure that we are reading an updated value, probably not needed at the hardware | ||
| 214 | // level, but this is also a hint to the compiler that we're syncing on the buffer. | ||
| 215 | fence(Ordering::SeqCst); | ||
| 216 | |||
| 217 | let tdes0 = td.tdes0.get(); | ||
| 218 | |||
| 219 | if tdes0 & TXDESC_0_OWN != 0 { | ||
| 220 | // Transmission isn't done yet, probably a receive interrupt that fired this | ||
| 221 | return Ok(()); | ||
| 222 | } | ||
| 223 | |||
| 224 | // Release the buffer | ||
| 225 | self.buffers[previous].take(); | ||
| 226 | |||
| 227 | if tdes0 & TXDESC_0_ES != 0 { | ||
| 228 | Err(Error::TransmissionError) | ||
| 229 | } else { | ||
| 230 | Ok(()) | ||
| 231 | } | ||
| 232 | } | 173 | } |
| 233 | } | 174 | } |
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 5202edf62..224cc202b 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs | |||
| @@ -7,7 +7,7 @@ use embassy_executor::Spawner; | |||
| 7 | use embassy_net::tcp::TcpSocket; | 7 | use embassy_net::tcp::TcpSocket; |
| 8 | use embassy_net::{Ipv4Address, Stack, StackResources}; | 8 | use embassy_net::{Ipv4Address, Stack, StackResources}; |
| 9 | use embassy_stm32::eth::generic_smi::GenericSMI; | 9 | use embassy_stm32::eth::generic_smi::GenericSMI; |
| 10 | use embassy_stm32::eth::{Ethernet, State}; | 10 | use embassy_stm32::eth::{Ethernet, PacketQueue}; |
| 11 | use embassy_stm32::peripherals::ETH; | 11 | use embassy_stm32::peripherals::ETH; |
| 12 | use embassy_stm32::rng::Rng; | 12 | use embassy_stm32::rng::Rng; |
| 13 | use embassy_stm32::time::mhz; | 13 | use embassy_stm32::time::mhz; |
| @@ -22,11 +22,12 @@ macro_rules! singleton { | |||
| 22 | ($val:expr) => {{ | 22 | ($val:expr) => {{ |
| 23 | type T = impl Sized; | 23 | type T = impl Sized; |
| 24 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); | 24 | static STATIC_CELL: StaticCell<T> = StaticCell::new(); |
| 25 | STATIC_CELL.init_with(move || $val) | 25 | let (x,) = STATIC_CELL.init(($val,)); |
| 26 | x | ||
| 26 | }}; | 27 | }}; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; | 30 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 30 | 31 | ||
| 31 | #[embassy_executor::task] | 32 | #[embassy_executor::task] |
| 32 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 33 | async fn net_task(stack: &'static Stack<Device>) -> ! { |
| @@ -50,25 +51,23 @@ async fn main(spawner: Spawner) -> ! { | |||
| 50 | let eth_int = interrupt::take!(ETH); | 51 | let eth_int = interrupt::take!(ETH); |
| 51 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; | 52 | let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; |
| 52 | 53 | ||
| 53 | let device = unsafe { | 54 | let device = Ethernet::new( |
| 54 | Ethernet::new( | 55 | singleton!(PacketQueue::<16, 16>::new()), |
| 55 | singleton!(State::new()), | 56 | p.ETH, |
| 56 | p.ETH, | 57 | eth_int, |
| 57 | eth_int, | 58 | p.PA1, |
| 58 | p.PA1, | 59 | p.PA2, |
| 59 | p.PA2, | 60 | p.PC1, |
| 60 | p.PC1, | 61 | p.PA7, |
| 61 | p.PA7, | 62 | p.PC4, |
| 62 | p.PC4, | 63 | p.PC5, |
| 63 | p.PC5, | 64 | p.PG13, |
| 64 | p.PG13, | 65 | p.PB13, |
| 65 | p.PB13, | 66 | p.PG11, |
| 66 | p.PG11, | 67 | GenericSMI, |
| 67 | GenericSMI, | 68 | mac_addr, |
| 68 | mac_addr, | 69 | 0, |
| 69 | 0, | 70 | ); |
| 70 | ) | ||
| 71 | }; | ||
| 72 | 71 | ||
| 73 | let config = embassy_net::ConfigStrategy::Dhcp; | 72 | let config = embassy_net::ConfigStrategy::Dhcp; |
| 74 | //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { | 73 | //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { |
| @@ -91,8 +90,8 @@ async fn main(spawner: Spawner) -> ! { | |||
| 91 | info!("Network task initialized"); | 90 | info!("Network task initialized"); |
| 92 | 91 | ||
| 93 | // Then we can use it! | 92 | // Then we can use it! |
| 94 | let mut rx_buffer = [0; 1024]; | 93 | let mut rx_buffer = [0; 4096]; |
| 95 | let mut tx_buffer = [0; 1024]; | 94 | let mut tx_buffer = [0; 4096]; |
| 96 | 95 | ||
| 97 | loop { | 96 | loop { |
| 98 | let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); | 97 | let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer); |
| @@ -107,8 +106,9 @@ async fn main(spawner: Spawner) -> ! { | |||
| 107 | continue; | 106 | continue; |
| 108 | } | 107 | } |
| 109 | info!("connected!"); | 108 | info!("connected!"); |
| 109 | let buf = [0; 1024]; | ||
| 110 | loop { | 110 | loop { |
| 111 | let r = socket.write_all(b"Hello\n").await; | 111 | let r = socket.write_all(&buf).await; |
| 112 | if let Err(e) = r { | 112 | if let Err(e) = r { |
| 113 | info!("write error: {:?}", e); | 113 | info!("write error: {:?}", e); |
| 114 | return; | 114 | return; |
