aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-07-15 21:18:03 +0000
committerGitHub <[email protected]>2023-07-15 21:18:03 +0000
commit25197308e3cd9694c37284b49ce1b482e22855ce (patch)
tree31acc092dd9da366eedb4409775c17848009c42f
parentcf278ea1b6ce29b7908a9f93de4cbdfd7d0dea37 (diff)
parent17d5e1c47046ea69ef7ac6041ae3cf3be587221b (diff)
Merge pull request #1653 from xoviat/eth
stm32/eth: solve busy-loop polling
-rw-r--r--embassy-stm32/src/eth/generic_smi.rs45
-rw-r--r--embassy-stm32/src/eth/mod.rs10
-rw-r--r--embassy-stm32/src/eth/v1/mod.rs27
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs27
-rw-r--r--examples/stm32f4/src/bin/eth.rs111
-rw-r--r--examples/stm32f7/src/bin/eth.rs2
-rw-r--r--examples/stm32h5/src/bin/eth.rs2
-rw-r--r--examples/stm32h7/src/bin/eth.rs2
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs2
9 files changed, 194 insertions, 34 deletions
diff --git a/embassy-stm32/src/eth/generic_smi.rs b/embassy-stm32/src/eth/generic_smi.rs
index 968256046..90631b175 100644
--- a/embassy-stm32/src/eth/generic_smi.rs
+++ b/embassy-stm32/src/eth/generic_smi.rs
@@ -1,5 +1,11 @@
1//! Generic SMI Ethernet PHY 1//! Generic SMI Ethernet PHY
2 2
3#[cfg(feature = "time")]
4use embassy_time::{Duration, Timer};
5use futures::task::Context;
6#[cfg(feature = "time")]
7use futures::FutureExt;
8
3use super::{StationManagement, PHY}; 9use super::{StationManagement, PHY};
4 10
5#[allow(dead_code)] 11#[allow(dead_code)]
@@ -36,25 +42,48 @@ mod phy_consts {
36use self::phy_consts::*; 42use self::phy_consts::*;
37 43
38/// Generic SMI Ethernet PHY 44/// Generic SMI Ethernet PHY
39pub struct GenericSMI; 45pub struct GenericSMI {
46 #[cfg(feature = "time")]
47 poll_interval: Duration,
48}
49
50impl GenericSMI {
51 #[cfg(feature = "time")]
52 pub fn new() -> Self {
53 Self {
54 poll_interval: Duration::from_millis(500),
55 }
56 }
57
58 #[cfg(not(feature = "time"))]
59 pub fn new() -> Self {
60 Self {}
61 }
62}
40 63
41unsafe impl PHY for GenericSMI { 64unsafe impl PHY for GenericSMI {
42 /// Reset PHY and wait for it to come out of reset. 65 /// Reset PHY and wait for it to come out of reset.
43 fn phy_reset<S: StationManagement>(sm: &mut S) { 66 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
44 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET); 67 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_RESET);
45 while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {} 68 while sm.smi_read(PHY_REG_BCR) & PHY_REG_BCR_RESET == PHY_REG_BCR_RESET {}
46 } 69 }
47 70
48 /// PHY initialisation. 71 /// PHY initialisation.
49 fn phy_init<S: StationManagement>(sm: &mut S) { 72 fn phy_init<S: StationManagement>(&mut self, sm: &mut S) {
50 // Clear WU CSR 73 // Clear WU CSR
51 Self::smi_write_ext(sm, PHY_REG_WUCSR, 0); 74 self.smi_write_ext(sm, PHY_REG_WUCSR, 0);
52 75
53 // Enable auto-negotiation 76 // Enable auto-negotiation
54 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M); 77 sm.smi_write(PHY_REG_BCR, PHY_REG_BCR_AN | PHY_REG_BCR_ANRST | PHY_REG_BCR_100M);
55 } 78 }
56 79
57 fn poll_link<S: StationManagement>(sm: &mut S) -> bool { 80 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool {
81 #[cfg(not(feature = "time"))]
82 cx.waker().wake_by_ref();
83
84 #[cfg(feature = "time")]
85 let _ = Timer::after(self.poll_interval).poll_unpin(cx);
86
58 let bsr = sm.smi_read(PHY_REG_BSR); 87 let bsr = sm.smi_read(PHY_REG_BSR);
59 88
60 // No link without autonegotiate 89 // No link without autonegotiate
@@ -73,8 +102,12 @@ unsafe impl PHY for GenericSMI {
73 102
74/// Public functions for the PHY 103/// Public functions for the PHY
75impl GenericSMI { 104impl GenericSMI {
105 pub fn set_poll_interval(&mut self, poll_interval: Duration) {
106 self.poll_interval = poll_interval
107 }
108
76 // Writes a value to an extended PHY register in MMD address space 109 // Writes a value to an extended PHY register in MMD address space
77 fn smi_write_ext<S: StationManagement>(sm: &mut S, reg_addr: u16, reg_data: u16) { 110 fn smi_write_ext<S: StationManagement>(&mut self, sm: &mut S, reg_addr: u16, reg_data: u16) {
78 sm.smi_write(PHY_REG_CTL, 0x0003); // set address 111 sm.smi_write(PHY_REG_CTL, 0x0003); // set address
79 sm.smi_write(PHY_REG_ADDAR, reg_addr); 112 sm.smi_write(PHY_REG_ADDAR, reg_addr);
80 sm.smi_write(PHY_REG_CTL, 0x4003); // set data 113 sm.smi_write(PHY_REG_CTL, 0x4003); // set data
diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs
index 4989e17c7..1687cb319 100644
--- a/embassy-stm32/src/eth/mod.rs
+++ b/embassy-stm32/src/eth/mod.rs
@@ -81,9 +81,7 @@ impl<'d, T: Instance, P: PHY> embassy_net_driver::Driver for Ethernet<'d, T, P>
81 } 81 }
82 82
83 fn link_state(&mut self, cx: &mut Context) -> LinkState { 83 fn link_state(&mut self, cx: &mut Context) -> LinkState {
84 // TODO: wake cx.waker on link state change 84 if self.phy.poll_link(&mut self.station_management, cx) {
85 cx.waker().wake_by_ref();
86 if P::poll_link(self) {
87 LinkState::Up 85 LinkState::Up
88 } else { 86 } else {
89 LinkState::Down 87 LinkState::Down
@@ -148,11 +146,11 @@ pub unsafe trait StationManagement {
148/// The methods cannot move S 146/// The methods cannot move S
149pub unsafe trait PHY { 147pub unsafe trait PHY {
150 /// Reset PHY and wait for it to come out of reset. 148 /// Reset PHY and wait for it to come out of reset.
151 fn phy_reset<S: StationManagement>(sm: &mut S); 149 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S);
152 /// PHY initialisation. 150 /// PHY initialisation.
153 fn phy_init<S: StationManagement>(sm: &mut S); 151 fn phy_init<S: StationManagement>(&mut self, sm: &mut S);
154 /// Poll link to see if it is up and FD with 100Mbps 152 /// Poll link to see if it is up and FD with 100Mbps
155 fn poll_link<S: StationManagement>(sm: &mut S) -> bool; 153 fn poll_link<S: StationManagement>(&mut self, sm: &mut S, cx: &mut Context) -> bool;
156} 154}
157 155
158pub(crate) mod sealed { 156pub(crate) mod sealed {
diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs
index b53c2d0fa..2a6ea35ff 100644
--- a/embassy-stm32/src/eth/v1/mod.rs
+++ b/embassy-stm32/src/eth/v1/mod.rs
@@ -3,6 +3,7 @@
3mod rx_desc; 3mod rx_desc;
4mod tx_desc; 4mod tx_desc;
5 5
6use core::marker::PhantomData;
6use core::sync::atomic::{fence, Ordering}; 7use core::sync::atomic::{fence, Ordering};
7 8
8use embassy_hal_common::{into_ref, PeripheralRef}; 9use embassy_hal_common::{into_ref, PeripheralRef};
@@ -48,9 +49,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
48 pub(crate) rx: RDesRing<'d>, 49 pub(crate) rx: RDesRing<'d>,
49 50
50 pins: [PeripheralRef<'d, AnyPin>; 9], 51 pins: [PeripheralRef<'d, AnyPin>; 9],
51 _phy: P, 52 pub(crate) phy: P,
52 clock_range: Cr, 53 pub(crate) station_management: EthernetStationManagement<T>,
53 phy_addr: u8,
54 pub(crate) mac_addr: [u8; 6], 54 pub(crate) mac_addr: [u8; 6],
55} 55}
56 56
@@ -224,9 +224,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
224 let mut this = Self { 224 let mut this = Self {
225 _peri: peri, 225 _peri: peri,
226 pins, 226 pins,
227 _phy: phy, 227 phy: phy,
228 clock_range, 228 station_management: EthernetStationManagement {
229 phy_addr, 229 peri: PhantomData,
230 clock_range: clock_range,
231 phy_addr: phy_addr,
232 },
230 mac_addr, 233 mac_addr,
231 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 234 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
232 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 235 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
@@ -256,8 +259,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
256 w.set_tie(true); 259 w.set_tie(true);
257 }); 260 });
258 261
259 P::phy_reset(&mut this); 262 this.phy.phy_reset(&mut this.station_management);
260 P::phy_init(&mut this); 263 this.phy.phy_init(&mut this.station_management);
261 264
262 interrupt::ETH.unpend(); 265 interrupt::ETH.unpend();
263 unsafe { interrupt::ETH.enable() }; 266 unsafe { interrupt::ETH.enable() };
@@ -266,7 +269,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
266 } 269 }
267} 270}
268 271
269unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 272pub struct EthernetStationManagement<T: Instance> {
273 peri: PhantomData<T>,
274 clock_range: Cr,
275 phy_addr: u8,
276}
277
278unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
270 fn smi_read(&mut self, reg: u8) -> u16 { 279 fn smi_read(&mut self, reg: u8) -> u16 {
271 let mac = ETH.ethernet_mac(); 280 let mac = ETH.ethernet_mac();
272 281
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 600e1d3bc..bb681c42b 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,5 +1,6 @@
1mod descriptors; 1mod descriptors;
2 2
3use core::marker::PhantomData;
3use core::sync::atomic::{fence, Ordering}; 4use core::sync::atomic::{fence, Ordering};
4 5
5use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
@@ -40,9 +41,8 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
40 pub(crate) tx: TDesRing<'d>, 41 pub(crate) tx: TDesRing<'d>,
41 pub(crate) rx: RDesRing<'d>, 42 pub(crate) rx: RDesRing<'d>,
42 pins: [PeripheralRef<'d, AnyPin>; 9], 43 pins: [PeripheralRef<'d, AnyPin>; 9],
43 _phy: P, 44 pub(crate) phy: P,
44 clock_range: u8, 45 pub(crate) station_management: EthernetStationManagement<T>,
45 phy_addr: u8,
46 pub(crate) mac_addr: [u8; 6], 46 pub(crate) mac_addr: [u8; 6],
47} 47}
48 48
@@ -201,9 +201,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
201 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), 201 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
202 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), 202 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
203 pins, 203 pins,
204 _phy: phy, 204 phy: phy,
205 clock_range, 205 station_management: EthernetStationManagement {
206 phy_addr, 206 peri: PhantomData,
207 clock_range: clock_range,
208 phy_addr: phy_addr,
209 },
207 mac_addr, 210 mac_addr,
208 }; 211 };
209 212
@@ -229,8 +232,8 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
229 w.set_tie(true); 232 w.set_tie(true);
230 }); 233 });
231 234
232 P::phy_reset(&mut this); 235 this.phy.phy_reset(&mut this.station_management);
233 P::phy_init(&mut this); 236 this.phy.phy_init(&mut this.station_management);
234 237
235 interrupt::ETH.unpend(); 238 interrupt::ETH.unpend();
236 unsafe { interrupt::ETH.enable() }; 239 unsafe { interrupt::ETH.enable() };
@@ -239,7 +242,13 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
239 } 242 }
240} 243}
241 244
242unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> { 245pub struct EthernetStationManagement<T: Instance> {
246 peri: PhantomData<T>,
247 clock_range: u8,
248 phy_addr: u8,
249}
250
251unsafe impl<T: Instance> StationManagement for EthernetStationManagement<T> {
243 fn smi_read(&mut self, reg: u8) -> u16 { 252 fn smi_read(&mut self, reg: u8) -> u16 {
244 let mac = ETH.ethernet_mac(); 253 let mac = ETH.ethernet_mac();
245 254
diff --git a/examples/stm32f4/src/bin/eth.rs b/examples/stm32f4/src/bin/eth.rs
new file mode 100644
index 000000000..d0b164393
--- /dev/null
+++ b/examples/stm32f4/src/bin/eth.rs
@@ -0,0 +1,111 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use defmt::*;
6use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz;
14use embassy_stm32::{bind_interrupts, eth, Config};
15use embassy_time::{Duration, Timer};
16use embedded_io::asynch::Write;
17use static_cell::make_static;
18use {defmt_rtt as _, panic_probe as _};
19bind_interrupts!(struct Irqs {
20 ETH => eth::InterruptHandler;
21});
22
23type Device = Ethernet<'static, ETH, GenericSMI>;
24
25#[embassy_executor::task]
26async fn net_task(stack: &'static Stack<Device>) -> ! {
27 stack.run().await
28}
29
30#[embassy_executor::main]
31async fn main(spawner: Spawner) -> ! {
32 let mut config = Config::default();
33 config.rcc.sys_ck = Some(mhz(200));
34 let p = embassy_stm32::init(config);
35
36 info!("Hello World!");
37
38 // Generate random seed.
39 let mut rng = Rng::new(p.RNG);
40 let mut seed = [0; 8];
41 let _ = rng.async_fill_bytes(&mut seed).await;
42 let seed = u64::from_le_bytes(seed);
43
44 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
45
46 let device = Ethernet::new(
47 make_static!(PacketQueue::<16, 16>::new()),
48 p.ETH,
49 Irqs,
50 p.PA1,
51 p.PA2,
52 p.PC1,
53 p.PA7,
54 p.PC4,
55 p.PC5,
56 p.PG13,
57 p.PB13,
58 p.PG11,
59 GenericSMI::new(),
60 mac_addr,
61 0,
62 );
63
64 let config = embassy_net::Config::dhcpv4(Default::default());
65 //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
66 // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
67 // dns_servers: Vec::new(),
68 // gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
69 //});
70
71 // Init network stack
72 let stack = &*make_static!(Stack::new(
73 device,
74 config,
75 make_static!(StackResources::<2>::new()),
76 seed
77 ));
78
79 // Launch network task
80 unwrap!(spawner.spawn(net_task(&stack)));
81
82 info!("Network task initialized");
83
84 // Then we can use it!
85 let mut rx_buffer = [0; 4096];
86 let mut tx_buffer = [0; 4096];
87
88 loop {
89 let mut socket = TcpSocket::new(&stack, &mut rx_buffer, &mut tx_buffer);
90
91 socket.set_timeout(Some(embassy_time::Duration::from_secs(10)));
92
93 let remote_endpoint = (Ipv4Address::new(10, 42, 0, 1), 8000);
94 info!("connecting...");
95 let r = socket.connect(remote_endpoint).await;
96 if let Err(e) = r {
97 info!("connect error: {:?}", e);
98 continue;
99 }
100 info!("connected!");
101 let buf = [0; 1024];
102 loop {
103 let r = socket.write_all(&buf).await;
104 if let Err(e) = r {
105 info!("write error: {:?}", e);
106 continue;
107 }
108 Timer::after(Duration::from_secs(1)).await;
109 }
110 }
111}
diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs
index fde6a7576..c6b2ba45c 100644
--- a/examples/stm32f7/src/bin/eth.rs
+++ b/examples/stm32f7/src/bin/eth.rs
@@ -57,7 +57,7 @@ async fn main(spawner: Spawner) -> ! {
57 p.PG13, 57 p.PG13,
58 p.PB13, 58 p.PB13,
59 p.PG11, 59 p.PG11,
60 GenericSMI, 60 GenericSMI::new(),
61 mac_addr, 61 mac_addr,
62 0, 62 0,
63 ); 63 );
diff --git a/examples/stm32h5/src/bin/eth.rs b/examples/stm32h5/src/bin/eth.rs
index 78c8282a6..0bff85ed8 100644
--- a/examples/stm32h5/src/bin/eth.rs
+++ b/examples/stm32h5/src/bin/eth.rs
@@ -76,7 +76,7 @@ async fn main(spawner: Spawner) -> ! {
76 p.PG13, 76 p.PG13,
77 p.PB15, 77 p.PB15,
78 p.PG11, 78 p.PG11,
79 GenericSMI, 79 GenericSMI::new(),
80 mac_addr, 80 mac_addr,
81 0, 81 0,
82 ); 82 );
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 12d37f7a4..cfafcaed1 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -58,7 +58,7 @@ async fn main(spawner: Spawner) -> ! {
58 p.PG13, 58 p.PG13,
59 p.PB13, 59 p.PB13,
60 p.PG11, 60 p.PG11,
61 GenericSMI, 61 GenericSMI::new(),
62 mac_addr, 62 mac_addr,
63 0, 63 0,
64 ); 64 );
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 6078fc3fe..4ed737578 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -59,7 +59,7 @@ async fn main(spawner: Spawner) -> ! {
59 p.PG13, 59 p.PG13,
60 p.PB13, 60 p.PB13,
61 p.PG11, 61 p.PG11,
62 GenericSMI, 62 GenericSMI::new(),
63 mac_addr, 63 mac_addr,
64 0, 64 0,
65 ); 65 );