aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-12-12 02:04:33 +0100
committerDario Nieuwenhuis <[email protected]>2022-12-13 16:43:25 +0100
commit3005ee0178af46ef8a2b7f8b02f4aea69ed9202b (patch)
tree237592613fc66e1a2613feafc7c9ac8de40f67be
parent8f3065210927b6e92f6d727741189155b2eab91e (diff)
stm32/eth_v2: update to new embassy-net trait, remove PeripheralMutex.
-rw-r--r--embassy-stm32/src/eth/v2/descriptors.rs333
-rw-r--r--embassy-stm32/src/eth/v2/mod.rs383
-rw-r--r--examples/stm32h7/src/bin/eth.rs43
-rw-r--r--examples/stm32h7/src/bin/eth_client.rs43
4 files changed, 302 insertions, 500 deletions
diff --git a/embassy-stm32/src/eth/v2/descriptors.rs b/embassy-stm32/src/eth/v2/descriptors.rs
index c6c06a9ce..2426596fb 100644
--- a/embassy-stm32/src/eth/v2/descriptors.rs
+++ b/embassy-stm32/src/eth/v2/descriptors.rs
@@ -1,19 +1,10 @@
1use core::sync::atomic::{fence, Ordering}; 1use core::sync::atomic::{fence, Ordering};
2 2
3use embassy_net::{Packet, PacketBox, PacketBoxExt, PacketBuf};
4use vcell::VolatileCell; 3use vcell::VolatileCell;
5 4
5use crate::eth::{Packet, RX_BUFFER_SIZE, TX_BUFFER_SIZE};
6use crate::pac::ETH; 6use crate::pac::ETH;
7 7
8#[non_exhaustive]
9#[derive(Debug, Copy, Clone)]
10#[cfg_attr(feature = "defmt", derive(defmt::Format))]
11pub enum Error {
12 NoBufferAvailable,
13 // TODO: Break down this error into several others
14 TransmissionError,
15}
16
17/// Transmit and Receive Descriptor fields 8/// Transmit and Receive Descriptor fields
18#[allow(dead_code)] 9#[allow(dead_code)]
19mod emac_consts { 10mod emac_consts {
@@ -41,7 +32,7 @@ use emac_consts::*;
41/// * tdes2: buffer lengths 32/// * tdes2: buffer lengths
42/// * tdes3: control and payload/frame length 33/// * tdes3: control and payload/frame length
43#[repr(C)] 34#[repr(C)]
44struct TDes { 35pub(crate) struct TDes {
45 tdes0: VolatileCell<u32>, 36 tdes0: VolatileCell<u32>,
46 tdes1: VolatileCell<u32>, 37 tdes1: VolatileCell<u32>,
47 tdes2: VolatileCell<u32>, 38 tdes2: VolatileCell<u32>,
@@ -59,41 +50,26 @@ impl TDes {
59 } 50 }
60 51
61 /// Return true if this TDes is not currently owned by the DMA 52 /// Return true if this TDes is not currently owned by the DMA
62 pub fn available(&self) -> bool { 53 fn available(&self) -> bool {
63 self.tdes3.get() & EMAC_DES3_OWN == 0 54 self.tdes3.get() & EMAC_DES3_OWN == 0
64 } 55 }
65} 56}
66 57
67pub(crate) struct TDesRing<const N: usize> { 58pub(crate) struct TDesRing<'a> {
68 td: [TDes; N], 59 descriptors: &'a mut [TDes],
69 buffers: [Option<PacketBuf>; N], 60 buffers: &'a mut [Packet<TX_BUFFER_SIZE>],
70 tdidx: usize, 61 index: usize,
71} 62}
72 63
73impl<const N: usize> TDesRing<N> { 64impl<'a> TDesRing<'a> {
74 pub const fn new() -> Self { 65 /// Initialise this TDesRing. Assume TDesRing is corrupt.
75 const TDES: TDes = TDes::new(); 66 pub fn new(descriptors: &'a mut [TDes], buffers: &'a mut [Packet<TX_BUFFER_SIZE>]) -> Self {
76 const BUFFERS: Option<PacketBuf> = None; 67 assert!(descriptors.len() > 0);
68 assert!(descriptors.len() == buffers.len());
77 69
78 Self { 70 for td in descriptors.iter_mut() {
79 td: [TDES; N],
80 buffers: [BUFFERS; N],
81 tdidx: 0,
82 }
83 }
84
85 /// Initialise this TDesRing. Assume TDesRing is corrupt
86 ///
87 /// The current memory address of the buffers inside this TDesRing
88 /// will be stored in the descriptors, so ensure the TDesRing is
89 /// not moved after initialisation.
90 pub(crate) fn init(&mut self) {
91 assert!(N > 0);
92
93 for td in self.td.iter_mut() {
94 *td = TDes::new(); 71 *td = TDes::new();
95 } 72 }
96 self.tdidx = 0;
97 73
98 // Initialize the pointers in the DMA engine. (There will be a memory barrier later 74 // Initialize the pointers in the DMA engine. (There will be a memory barrier later
99 // before the DMA engine is enabled.) 75 // before the DMA engine is enabled.)
@@ -101,80 +77,60 @@ impl<const N: usize> TDesRing<N> {
101 unsafe { 77 unsafe {
102 let dma = ETH.ethernet_dma(); 78 let dma = ETH.ethernet_dma();
103 79
104 dma.dmactx_dlar().write(|w| w.0 = &self.td as *const _ as u32); 80 dma.dmactx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
105 dma.dmactx_rlr().write(|w| w.set_tdrl((N as u16) - 1)); 81 dma.dmactx_rlr().write(|w| w.set_tdrl((descriptors.len() as u16) - 1));
106 dma.dmactx_dtpr().write(|w| w.0 = &self.td[0] as *const _ as u32); 82 dma.dmactx_dtpr().write(|w| w.0 = 0);
83 }
84
85 Self {
86 descriptors,
87 buffers,
88 index: 0,
107 } 89 }
108 } 90 }
109 91
110 /// Return true if a TDes is available for use 92 pub(crate) fn len(&self) -> usize {
111 pub(crate) fn available(&self) -> bool { 93 self.descriptors.len()
112 self.td[self.tdidx].available()
113 } 94 }
114 95
115 pub(crate) fn transmit(&mut self, pkt: PacketBuf) -> Result<(), Error> { 96 /// Return the next available packet buffer for transmitting, or None
116 if !self.available() { 97 pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
117 return Err(Error::NoBufferAvailable); 98 let d = &mut self.descriptors[self.index];
99 if d.available() {
100 Some(&mut self.buffers[self.index].0)
101 } else {
102 None
118 } 103 }
119 let x = self.tdidx; 104 }
120 let td = &mut self.td[x];
121 105
122 let pkt_len = pkt.len(); 106 /// Transmit the packet written in a buffer returned by `available`.
123 assert!(pkt_len as u32 <= EMAC_TDES2_B1L); 107 pub(crate) fn transmit(&mut self, len: usize) {
124 let address = pkt.as_ptr() as u32; 108 let td = &mut self.descriptors[self.index];
109 assert!(td.available());
110 assert!(len as u32 <= EMAC_TDES2_B1L);
125 111
126 // Read format 112 // Read format
127 td.tdes0.set(address); 113 td.tdes0.set(self.buffers[self.index].0.as_ptr() as u32);
128 td.tdes2.set(pkt_len as u32 & EMAC_TDES2_B1L | EMAC_TDES2_IOC); 114 td.tdes2.set(len as u32 & EMAC_TDES2_B1L | EMAC_TDES2_IOC);
129 115
130 // FD: Contains first buffer of packet 116 // FD: Contains first buffer of packet
131 // LD: Contains last buffer of packet 117 // LD: Contains last buffer of packet
132 // Give the DMA engine ownership 118 // Give the DMA engine ownership
133 td.tdes3.set(EMAC_DES3_FD | EMAC_DES3_LD | EMAC_DES3_OWN); 119 td.tdes3.set(EMAC_DES3_FD | EMAC_DES3_LD | EMAC_DES3_OWN);
134 120
135 self.buffers[x].replace(pkt);
136
137 // Ensure changes to the descriptor are committed before DMA engine sees tail pointer store. 121 // Ensure changes to the descriptor are committed before DMA engine sees tail pointer store.
138 // This will generate an DMB instruction. 122 // This will generate an DMB instruction.
139 // "Preceding reads and writes cannot be moved past subsequent writes." 123 // "Preceding reads and writes cannot be moved past subsequent writes."
140 fence(Ordering::Release); 124 fence(Ordering::Release);
141 125
142 // Move the tail pointer (TPR) to the next descriptor 126 self.index = self.index + 1;
143 let x = (x + 1) % N; 127 if self.index == self.descriptors.len() {
144 // NOTE(unsafe) Atomic write 128 self.index = 0;
145 unsafe {
146 ETH.ethernet_dma()
147 .dmactx_dtpr()
148 .write(|w| w.0 = &self.td[x] as *const _ as u32);
149 } 129 }
150 self.tdidx = x;
151 Ok(())
152 }
153
154 pub(crate) fn on_interrupt(&mut self) -> Result<(), Error> {
155 let previous = (self.tdidx + N - 1) % N;
156 let td = &self.td[previous];
157
158 // DMB to ensure that we are reading an updated value, probably not needed at the hardware
159 // level, but this is also a hint to the compiler that we're syncing on the buffer.
160 fence(Ordering::SeqCst);
161
162 let tdes3 = td.tdes3.get();
163
164 if tdes3 & EMAC_DES3_OWN != 0 {
165 // Transmission isn't done yet, probably a receive interrupt that fired this
166 return Ok(());
167 }
168 assert!(tdes3 & EMAC_DES3_CTXT == 0);
169
170 // Release the buffer
171 self.buffers[previous].take();
172 130
173 if tdes3 & EMAC_DES3_ES != 0 { 131 // signal DMA it can try again.
174 Err(Error::TransmissionError) 132 // NOTE(unsafe) Atomic write
175 } else { 133 unsafe { ETH.ethernet_dma().dmactx_dtpr().write(|w| w.0 = 0) }
176 Ok(())
177 }
178 } 134 }
179} 135}
180 136
@@ -185,7 +141,7 @@ impl<const N: usize> TDesRing<N> {
185/// * rdes2: 141/// * rdes2:
186/// * rdes3: OWN and Status 142/// * rdes3: OWN and Status
187#[repr(C)] 143#[repr(C)]
188struct RDes { 144pub(crate) struct RDes {
189 rdes0: VolatileCell<u32>, 145 rdes0: VolatileCell<u32>,
190 rdes1: VolatileCell<u32>, 146 rdes1: VolatileCell<u32>,
191 rdes2: VolatileCell<u32>, 147 rdes2: VolatileCell<u32>,
@@ -204,7 +160,7 @@ impl RDes {
204 160
205 /// Return true if this RDes is acceptable to us 161 /// Return true if this RDes is acceptable to us
206 #[inline(always)] 162 #[inline(always)]
207 pub fn valid(&self) -> bool { 163 fn valid(&self) -> bool {
208 // Write-back descriptor is valid if: 164 // Write-back descriptor is valid if:
209 // 165 //
210 // Contains first buffer of packet AND contains last buf of 166 // Contains first buffer of packet AND contains last buf of
@@ -215,177 +171,96 @@ impl RDes {
215 171
216 /// Return true if this RDes is not currently owned by the DMA 172 /// Return true if this RDes is not currently owned by the DMA
217 #[inline(always)] 173 #[inline(always)]
218 pub fn available(&self) -> bool { 174 fn available(&self) -> bool {
219 self.rdes3.get() & EMAC_DES3_OWN == 0 // Owned by us 175 self.rdes3.get() & EMAC_DES3_OWN == 0 // Owned by us
220 } 176 }
221 177
222 #[inline(always)] 178 #[inline(always)]
223 pub fn set_ready(&mut self, buf_addr: u32) { 179 fn set_ready(&mut self, buf: *mut u8) {
224 self.rdes0.set(buf_addr); 180 self.rdes0.set(buf as u32);
225 self.rdes3.set(EMAC_RDES3_BUF1V | EMAC_RDES3_IOC | EMAC_DES3_OWN); 181 self.rdes3.set(EMAC_RDES3_BUF1V | EMAC_RDES3_IOC | EMAC_DES3_OWN);
226 } 182 }
227} 183}
228 184
229/// Rx ring of descriptors and packets 185/// Rx ring of descriptors and packets
230/// 186pub(crate) struct RDesRing<'a> {
231/// This ring has three major locations that work in lock-step. The DMA will never write to the tail 187 descriptors: &'a mut [RDes],
232/// index, so the `read_index` must never pass the tail index. The `next_tail_index` is always 1 188 buffers: &'a mut [Packet<RX_BUFFER_SIZE>],
233/// slot ahead of the real tail index, and it must never pass the `read_index` or it could overwrite 189 index: usize,
234/// a packet still to be passed to the application.
235///
236/// nt can't pass r (no alloc)
237/// +---+---+---+---+ Read ok +---+---+---+---+ No Read +---+---+---+---+
238/// | | | | | ------------> | | | | | ------------> | | | | |
239/// +---+---+---+---+ Allocation ok +---+---+---+---+ +---+---+---+---+
240/// ^ ^t ^t ^ ^t ^
241/// |r |r |r
242/// |nt |nt |nt
243///
244///
245/// +---+---+---+---+ Read ok +---+---+---+---+ Can't read +---+---+---+---+
246/// | | | | | ------------> | | | | | ------------> | | | | |
247/// +---+---+---+---+ Allocation fail +---+---+---+---+ Allocation ok +---+---+---+---+
248/// ^ ^t ^ ^t ^ ^ ^ ^t
249/// |r | |r | | |r
250/// |nt |nt |nt
251///
252pub(crate) struct RDesRing<const N: usize> {
253 rd: [RDes; N],
254 buffers: [Option<PacketBox>; N],
255 read_idx: usize,
256 next_tail_idx: usize,
257} 190}
258 191
259impl<const N: usize> RDesRing<N> { 192impl<'a> RDesRing<'a> {
260 pub const fn new() -> Self { 193 pub(crate) fn new(descriptors: &'a mut [RDes], buffers: &'a mut [Packet<RX_BUFFER_SIZE>]) -> Self {
261 const RDES: RDes = RDes::new(); 194 assert!(descriptors.len() > 1);
262 const BUFFERS: Option<PacketBox> = None; 195 assert!(descriptors.len() == buffers.len());
263
264 Self {
265 rd: [RDES; N],
266 buffers: [BUFFERS; N],
267 read_idx: 0,
268 next_tail_idx: 0,
269 }
270 }
271 196
272 pub(crate) fn init(&mut self) { 197 for (i, desc) in descriptors.iter_mut().enumerate() {
273 assert!(N > 1);
274
275 for desc in self.rd.iter_mut() {
276 *desc = RDes::new(); 198 *desc = RDes::new();
199 desc.set_ready(buffers[i].0.as_mut_ptr());
277 } 200 }
278 201
279 let mut last_index = 0;
280 for (index, buf) in self.buffers.iter_mut().enumerate() {
281 let pkt = match PacketBox::new(Packet::new()) {
282 Some(p) => p,
283 None => {
284 if index == 0 {
285 panic!("Could not allocate at least one buffer for Ethernet receiving");
286 } else {
287 break;
288 }
289 }
290 };
291 let addr = pkt.as_ptr() as u32;
292 *buf = Some(pkt);
293 self.rd[index].set_ready(addr);
294 last_index = index;
295 }
296 self.next_tail_idx = (last_index + 1) % N;
297
298 unsafe { 202 unsafe {
299 let dma = ETH.ethernet_dma(); 203 let dma = ETH.ethernet_dma();
300 204
301 dma.dmacrx_dlar().write(|w| w.0 = self.rd.as_ptr() as u32); 205 dma.dmacrx_dlar().write(|w| w.0 = descriptors.as_mut_ptr() as u32);
302 dma.dmacrx_rlr().write(|w| w.set_rdrl((N as u16) - 1)); 206 dma.dmacrx_rlr().write(|w| w.set_rdrl((descriptors.len() as u16) - 1));
303 207 dma.dmacrx_dtpr().write(|w| w.0 = 0);
304 // We manage to allocate all buffers, set the index to the last one, that means
305 // that the DMA won't consider the last one as ready, because it (unfortunately)
306 // stops at the tail ptr and wraps at the end of the ring, which means that we
307 // can't tell it to stop after the last buffer.
308 let tail_ptr = &self.rd[last_index] as *const _ as u32;
309 fence(Ordering::Release);
310
311 dma.dmacrx_dtpr().write(|w| w.0 = tail_ptr);
312 } 208 }
313 }
314 209
315 pub(crate) fn on_interrupt(&mut self) { 210 Self {
316 // XXX: Do we need to do anything here ? Maybe we should try to advance the tail ptr, but it 211 descriptors,
317 // would soon hit the read ptr anyway, and we will wake smoltcp's stack on the interrupt 212 buffers,
318 // which should try to pop a packet... 213 index: 0,
214 }
319 } 215 }
320 216
321 pub(crate) fn pop_packet(&mut self) -> Option<PacketBuf> { 217 /// Get a received packet if any, or None.
218 pub(crate) fn available(&mut self) -> Option<&mut [u8]> {
322 // Not sure if the contents of the write buffer on the M7 can affects reads, so we are using 219 // Not sure if the contents of the write buffer on the M7 can affects reads, so we are using
323 // a DMB here just in case, it also serves as a hint to the compiler that we're syncing the 220 // a DMB here just in case, it also serves as a hint to the compiler that we're syncing the
324 // buffer (I think .-.) 221 // buffer (I think .-.)
325 fence(Ordering::SeqCst); 222 fence(Ordering::SeqCst);
326 223
327 let read_available = self.rd[self.read_idx].available(); 224 // We might have to process many packets, in case some have been rx'd but are invalid.
328 let tail_index = (self.next_tail_idx + N - 1) % N; 225 loop {
329 226 let descriptor = &mut self.descriptors[self.index];
330 let pkt = if read_available && self.read_idx != tail_index { 227 if !descriptor.available() {
331 let pkt = self.buffers[self.read_idx].take(); 228 return None;
332 let len = (self.rd[self.read_idx].rdes3.get() & EMAC_RDES3_PKTLEN) as usize;
333
334 assert!(pkt.is_some());
335 let valid = self.rd[self.read_idx].valid();
336
337 self.read_idx = (self.read_idx + 1) % N;
338 if valid {
339 pkt.map(|p| p.slice(0..len))
340 } else {
341 None
342 } 229 }
343 } else { 230
344 None 231 // If packet is invalid, pop it and try again.
345 }; 232 if !descriptor.valid() {
346 233 warn!("invalid packet: {:08x}", descriptor.rdes0.get());
347 // Try to advance the tail_idx 234 self.pop_packet();
348 if self.next_tail_idx != self.read_idx { 235 continue;
349 match PacketBox::new(Packet::new()) {
350 Some(b) => {
351 let addr = b.as_ptr() as u32;
352 self.buffers[self.next_tail_idx].replace(b);
353 self.rd[self.next_tail_idx].set_ready(addr);
354
355 // "Preceding reads and writes cannot be moved past subsequent writes."
356 fence(Ordering::Release);
357
358 // NOTE(unsafe) atomic write
359 unsafe {
360 ETH.ethernet_dma()
361 .dmacrx_dtpr()
362 .write(|w| w.0 = &self.rd[self.next_tail_idx] as *const _ as u32);
363 }
364
365 self.next_tail_idx = (self.next_tail_idx + 1) % N;
366 }
367 None => {}
368 } 236 }
237
238 break;
369 } 239 }
370 pkt 240
241 let descriptor = &mut self.descriptors[self.index];
242 let len = (descriptor.rdes3.get() & EMAC_RDES3_PKTLEN) as usize;
243 return Some(&mut self.buffers[self.index].0[..len]);
371 } 244 }
372}
373 245
374pub struct DescriptorRing<const T: usize, const R: usize> { 246 /// Pop the packet previously returned by `available`.
375 pub(crate) tx: TDesRing<T>, 247 pub(crate) fn pop_packet(&mut self) {
376 pub(crate) rx: RDesRing<R>, 248 let descriptor = &mut self.descriptors[self.index];
377} 249 assert!(descriptor.available());
378 250
379impl<const T: usize, const R: usize> DescriptorRing<T, R> { 251 self.descriptors[self.index].set_ready(self.buffers[self.index].0.as_mut_ptr());
380 pub const fn new() -> Self { 252
381 Self { 253 // "Preceding reads and writes cannot be moved past subsequent writes."
382 tx: TDesRing::new(), 254 fence(Ordering::Release);
383 rx: RDesRing::new(), 255
384 } 256 // signal DMA it can try again.
385 } 257 // NOTE(unsafe) Atomic write
258 unsafe { ETH.ethernet_dma().dmacrx_dtpr().write(|w| w.0 = 0) }
386 259
387 pub fn init(&mut self) { 260 // Increment index.
388 self.tx.init(); 261 self.index += 1;
389 self.rx.init(); 262 if self.index == self.descriptors.len() {
263 self.index = 0
264 }
390 } 265 }
391} 266}
diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs
index 5b76d1e7f..fcb4a296c 100644
--- a/embassy-stm32/src/eth/v2/mod.rs
+++ b/embassy-stm32/src/eth/v2/mod.rs
@@ -1,35 +1,28 @@
1use core::marker::PhantomData; 1mod descriptors;
2
2use core::sync::atomic::{fence, Ordering}; 3use core::sync::atomic::{fence, Ordering};
3use core::task::Waker;
4 4
5use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; 5use embassy_cortex_m::interrupt::InterruptExt;
6use embassy_hal_common::{into_ref, PeripheralRef}; 6use embassy_hal_common::{into_ref, PeripheralRef};
7use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU};
8use embassy_sync::waitqueue::AtomicWaker;
9 7
8pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing};
9use super::*;
10use crate::gpio::sealed::{AFType, Pin as _}; 10use crate::gpio::sealed::{AFType, Pin as _};
11use crate::gpio::{AnyPin, Speed}; 11use crate::gpio::{AnyPin, Speed};
12use crate::pac::{ETH, RCC, SYSCFG}; 12use crate::pac::{ETH, RCC, SYSCFG};
13use crate::Peripheral; 13use crate::Peripheral;
14 14
15mod descriptors; 15const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet
16use descriptors::DescriptorRing;
17
18use super::*;
19 16
20pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>); 17pub struct Ethernet<'d, T: Instance, P: PHY> {
21impl<'d, T: Instance, const TX: usize, const RX: usize> State<'d, T, TX, RX> { 18 _peri: PeripheralRef<'d, T>,
22 pub const fn new() -> Self { 19 pub(crate) tx: TDesRing<'d>,
23 Self(StateStorage::new()) 20 pub(crate) rx: RDesRing<'d>,
24 }
25}
26pub struct Ethernet<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> {
27 state: PeripheralMutex<'d, Inner<'d, T, TX, RX>>,
28 pins: [PeripheralRef<'d, AnyPin>; 9], 21 pins: [PeripheralRef<'d, AnyPin>; 9],
29 _phy: P, 22 _phy: P,
30 clock_range: u8, 23 clock_range: u8,
31 phy_addr: u8, 24 phy_addr: u8,
32 mac_addr: [u8; 6], 25 pub(crate) mac_addr: [u8; 6],
33} 26}
34 27
35macro_rules! config_pins { 28macro_rules! config_pins {
@@ -44,10 +37,9 @@ macro_rules! config_pins {
44 }; 37 };
45} 38}
46 39
47impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, P, TX, RX> { 40impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
48 /// safety: the returned instance is not leak-safe 41 pub fn new<const TX: usize, const RX: usize>(
49 pub unsafe fn new( 42 queue: &'d mut PacketQueue<TX, RX>,
50 state: &'d mut State<'d, T, TX, RX>,
51 peri: impl Peripheral<P = T> + 'd, 43 peri: impl Peripheral<P = T> + 'd,
52 interrupt: impl Peripheral<P = crate::interrupt::ETH> + 'd, 44 interrupt: impl Peripheral<P = crate::interrupt::ETH> + 'd,
53 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd, 45 ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
@@ -63,126 +55,123 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
63 mac_addr: [u8; 6], 55 mac_addr: [u8; 6],
64 phy_addr: u8, 56 phy_addr: u8,
65 ) -> Self { 57 ) -> Self {
66 into_ref!(interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 58 into_ref!(peri, interrupt, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
67 59
68 // Enable the necessary Clocks 60 unsafe {
69 // NOTE(unsafe) We have exclusive access to the registers 61 // Enable the necessary Clocks
70 critical_section::with(|_| { 62 // NOTE(unsafe) We have exclusive access to the registers
71 RCC.apb4enr().modify(|w| w.set_syscfgen(true)); 63 critical_section::with(|_| {
72 RCC.ahb1enr().modify(|w| { 64 RCC.apb4enr().modify(|w| w.set_syscfgen(true));
73 w.set_eth1macen(true); 65 RCC.ahb1enr().modify(|w| {
74 w.set_eth1txen(true); 66 w.set_eth1macen(true);
75 w.set_eth1rxen(true); 67 w.set_eth1txen(true);
68 w.set_eth1rxen(true);
69 });
70
71 // RMII
72 SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
76 }); 73 });
77 74
78 // RMII 75 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
79 SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); 76
80 }); 77 // NOTE(unsafe) We have exclusive access to the registers
81 78 let dma = ETH.ethernet_dma();
82 config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); 79 let mac = ETH.ethernet_mac();
83 80 let mtl = ETH.ethernet_mtl();
84 // NOTE(unsafe) We are ourselves not leak-safe. 81
85 let state = PeripheralMutex::new(interrupt, &mut state.0, || Inner::new(peri)); 82 // Reset and wait
86 83 dma.dmamr().modify(|w| w.set_swr(true));
87 // NOTE(unsafe) We have exclusive access to the registers 84 while dma.dmamr().read().swr() {}
88 let dma = ETH.ethernet_dma(); 85
89 let mac = ETH.ethernet_mac(); 86 mac.maccr().modify(|w| {
90 let mtl = ETH.ethernet_mtl(); 87 w.set_ipg(0b000); // 96 bit times
91 88 w.set_acs(true);
92 // Reset and wait 89 w.set_fes(true);
93 dma.dmamr().modify(|w| w.set_swr(true)); 90 w.set_dm(true);
94 while dma.dmamr().read().swr() {} 91 // TODO: Carrier sense ? ECRSFD
95 92 });
96 mac.maccr().modify(|w| { 93
97 w.set_ipg(0b000); // 96 bit times 94 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core,
98 w.set_acs(true); 95 // so the LR write must happen after the HR write.
99 w.set_fes(true); 96 mac.maca0hr()
100 w.set_dm(true); 97 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8)));
101 // TODO: Carrier sense ? ECRSFD 98 mac.maca0lr().write(|w| {
102 }); 99 w.set_addrlo(
103 100 u32::from(mac_addr[0])
104 // Note: Writing to LR triggers synchronisation of both LR and HR into the MAC core, 101 | (u32::from(mac_addr[1]) << 8)
105 // so the LR write must happen after the HR write. 102 | (u32::from(mac_addr[2]) << 16)
106 mac.maca0hr() 103 | (u32::from(mac_addr[3]) << 24),
107 .modify(|w| w.set_addrhi(u16::from(mac_addr[4]) | (u16::from(mac_addr[5]) << 8))); 104 )
108 mac.maca0lr().write(|w| { 105 });
109 w.set_addrlo( 106
110 u32::from(mac_addr[0]) 107 mac.macqtx_fcr().modify(|w| w.set_pt(0x100));
111 | (u32::from(mac_addr[1]) << 8) 108
112 | (u32::from(mac_addr[2]) << 16) 109 // disable all MMC RX interrupts
113 | (u32::from(mac_addr[3]) << 24), 110 mac.mmc_rx_interrupt_mask().write(|w| {
114 ) 111 w.set_rxcrcerpim(true);
115 }); 112 w.set_rxalgnerpim(true);
116 113 w.set_rxucgpim(true);
117 mac.macqtx_fcr().modify(|w| w.set_pt(0x100)); 114 w.set_rxlpiuscim(true);
118 115 w.set_rxlpitrcim(true)
119 // disable all MMC RX interrupts 116 });
120 mac.mmc_rx_interrupt_mask().write(|w| { 117
121 w.set_rxcrcerpim(true); 118 // disable all MMC TX interrupts
122 w.set_rxalgnerpim(true); 119 mac.mmc_tx_interrupt_mask().write(|w| {
123 w.set_rxucgpim(true); 120 w.set_txscolgpim(true);
124 w.set_rxlpiuscim(true); 121 w.set_txmcolgpim(true);
125 w.set_rxlpitrcim(true) 122 w.set_txgpktim(true);
126 }); 123 w.set_txlpiuscim(true);
127 124 w.set_txlpitrcim(true);
128 // disable all MMC TX interrupts 125 });
129 mac.mmc_tx_interrupt_mask().write(|w| { 126
130 w.set_txscolgpim(true); 127 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true));
131 w.set_txmcolgpim(true); 128 mtl.mtltx_qomr().modify(|w| w.set_tsf(true));
132 w.set_txgpktim(true); 129
133 w.set_txlpiuscim(true); 130 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ?
134 w.set_txlpitrcim(true); 131 dma.dmacrx_cr().modify(|w| {
135 }); 132 w.set_rxpbl(1); // 32 ?
136 133 w.set_rbsz(MTU as u16);
137 mtl.mtlrx_qomr().modify(|w| w.set_rsf(true)); 134 });
138 mtl.mtltx_qomr().modify(|w| w.set_tsf(true)); 135
139 136 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
140 dma.dmactx_cr().modify(|w| w.set_txpbl(1)); // 32 ? 137 let hclk = crate::rcc::get_freqs().ahb1;
141 dma.dmacrx_cr().modify(|w| { 138 let hclk_mhz = hclk.0 / 1_000_000;
142 w.set_rxpbl(1); // 32 ? 139
143 w.set_rbsz(MTU as u16); 140 // Set the MDC clock frequency in the range 1MHz - 2.5MHz
144 }); 141 let clock_range = match hclk_mhz {
145 142 0..=34 => 2, // Divide by 16
146 // NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called 143 35..=59 => 3, // Divide by 26
147 let hclk = crate::rcc::get_freqs().ahb1; 144 60..=99 => 0, // Divide by 42
148 let hclk_mhz = hclk.0 / 1_000_000; 145 100..=149 => 1, // Divide by 62
149 146 150..=249 => 4, // Divide by 102
150 // Set the MDC clock frequency in the range 1MHz - 2.5MHz 147 250..=310 => 5, // Divide by 124
151 let clock_range = match hclk_mhz { 148 _ => {
152 0..=34 => 2, // Divide by 16 149 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider")
153 35..=59 => 3, // Divide by 26 150 }
154 60..=99 => 0, // Divide by 42 151 };
155 100..=149 => 1, // Divide by 62 152
156 150..=249 => 4, // Divide by 102 153 let pins = [
157 250..=310 => 5, // Divide by 124 154 ref_clk.map_into(),
158 _ => { 155 mdio.map_into(),
159 panic!("HCLK results in MDC clock > 2.5MHz even for the highest CSR clock divider") 156 mdc.map_into(),
160 } 157 crs.map_into(),
161 }; 158 rx_d0.map_into(),
162 159 rx_d1.map_into(),
163 let pins = [ 160 tx_d0.map_into(),
164 ref_clk.map_into(), 161 tx_d1.map_into(),
165 mdio.map_into(), 162 tx_en.map_into(),
166 mdc.map_into(), 163 ];
167 crs.map_into(), 164
168 rx_d0.map_into(), 165 let mut this = Self {
169 rx_d1.map_into(), 166 _peri: peri,
170 tx_d0.map_into(), 167 tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
171 tx_d1.map_into(), 168 rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
172 tx_en.map_into(), 169 pins,
173 ]; 170 _phy: phy,
174 171 clock_range,
175 let mut this = Self { 172 phy_addr,
176 state, 173 mac_addr,
177 pins, 174 };
178 _phy: phy,
179 clock_range,
180 phy_addr,
181 mac_addr,
182 };
183
184 this.state.with(|s| {
185 s.desc_ring.init();
186 175
187 fence(Ordering::SeqCst); 176 fence(Ordering::SeqCst);
188 177
@@ -205,17 +194,37 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T,
205 w.set_rie(true); 194 w.set_rie(true);
206 w.set_tie(true); 195 w.set_tie(true);
207 }); 196 });
208 });
209 P::phy_reset(&mut this);
210 P::phy_init(&mut this);
211 197
212 this 198 P::phy_reset(&mut this);
199 P::phy_init(&mut this);
200
201 interrupt.set_handler(Self::on_interrupt);
202 interrupt.enable();
203
204 this
205 }
206 }
207
208 fn on_interrupt(_cx: *mut ()) {
209 WAKER.wake();
210
211 // TODO: Check and clear more flags
212 unsafe {
213 let dma = ETH.ethernet_dma();
214
215 dma.dmacsr().modify(|w| {
216 w.set_ti(true);
217 w.set_ri(true);
218 w.set_nis(true);
219 });
220 // Delay two peripheral's clock
221 dma.dmacsr().read();
222 dma.dmacsr().read();
223 }
213 } 224 }
214} 225}
215 226
216unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationManagement 227unsafe impl<'d, T: Instance, P: PHY> StationManagement for Ethernet<'d, T, P> {
217 for Ethernet<'d, T, P, TX, RX>
218{
219 fn smi_read(&mut self, reg: u8) -> u16 { 228 fn smi_read(&mut self, reg: u8) -> u16 {
220 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self` 229 // NOTE(unsafe) These registers aren't used in the interrupt and we have `&mut self`
221 unsafe { 230 unsafe {
@@ -251,44 +260,7 @@ unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationMa
251 } 260 }
252} 261}
253 262
254impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Device for Ethernet<'d, T, P, TX, RX> { 263impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
255 fn is_transmit_ready(&mut self) -> bool {
256 self.state.with(|s| s.desc_ring.tx.available())
257 }
258
259 fn transmit(&mut self, pkt: PacketBuf) {
260 self.state.with(|s| unwrap!(s.desc_ring.tx.transmit(pkt)));
261 }
262
263 fn receive(&mut self) -> Option<PacketBuf> {
264 self.state.with(|s| s.desc_ring.rx.pop_packet())
265 }
266
267 fn register_waker(&mut self, waker: &Waker) {
268 WAKER.register(waker);
269 }
270
271 fn capabilities(&self) -> DeviceCapabilities {
272 let mut caps = DeviceCapabilities::default();
273 caps.max_transmission_unit = MTU;
274 caps.max_burst_size = Some(TX.min(RX));
275 caps
276 }
277
278 fn link_state(&mut self) -> LinkState {
279 if P::poll_link(self) {
280 LinkState::Up
281 } else {
282 LinkState::Down
283 }
284 }
285
286 fn ethernet_address(&self) -> [u8; 6] {
287 self.mac_addr
288 }
289}
290
291impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Ethernet<'d, T, P, TX, RX> {
292 fn drop(&mut self) { 264 fn drop(&mut self) {
293 // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers 265 // NOTE(unsafe) We have `&mut self` and the interrupt doesn't use this registers
294 unsafe { 266 unsafe {
@@ -325,46 +297,3 @@ impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Drop for Etherne
325 }) 297 })
326 } 298 }
327} 299}
328
329//----------------------------------------------------------------------
330
331struct Inner<'d, T: Instance, const TX: usize, const RX: usize> {
332 _peri: PhantomData<&'d mut T>,
333 desc_ring: DescriptorRing<TX, RX>,
334}
335
336impl<'d, T: Instance, const TX: usize, const RX: usize> Inner<'d, T, TX, RX> {
337 pub fn new(_peri: impl Peripheral<P = T> + 'd) -> Self {
338 Self {
339 _peri: PhantomData,
340 desc_ring: DescriptorRing::new(),
341 }
342 }
343}
344
345impl<'d, T: Instance, const TX: usize, const RX: usize> PeripheralState for Inner<'d, T, TX, RX> {
346 type Interrupt = crate::interrupt::ETH;
347
348 fn on_interrupt(&mut self) {
349 unwrap!(self.desc_ring.tx.on_interrupt());
350 self.desc_ring.rx.on_interrupt();
351
352 WAKER.wake();
353
354 // TODO: Check and clear more flags
355 unsafe {
356 let dma = ETH.ethernet_dma();
357
358 dma.dmacsr().modify(|w| {
359 w.set_ti(true);
360 w.set_ri(true);
361 w.set_nis(true);
362 });
363 // Delay two peripheral's clock
364 dma.dmacsr().read();
365 dma.dmacsr().read();
366 }
367 }
368}
369
370static WAKER: AtomicWaker = AtomicWaker::new();
diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs
index 4ccc0b5ef..551325ca4 100644
--- a/examples/stm32h7/src/bin/eth.rs
+++ b/examples/stm32h7/src/bin/eth.rs
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
7use embassy_net::tcp::TcpSocket; 7use embassy_net::tcp::TcpSocket;
8use embassy_net::{Ipv4Address, Stack, StackResources}; 8use embassy_net::{Ipv4Address, Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI; 9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, State}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use 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
29type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; 30type Device = Ethernet<'static, ETH, GenericSMI>;
30 31
31#[embassy_executor::task] 32#[embassy_executor::task]
32async fn net_task(stack: &'static Stack<Device>) -> ! { 33async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -51,25 +52,23 @@ async fn main(spawner: Spawner) -> ! {
51 let eth_int = interrupt::take!(ETH); 52 let eth_int = interrupt::take!(ETH);
52 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 53 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
53 54
54 let device = unsafe { 55 let device = Ethernet::new(
55 Ethernet::new( 56 singleton!(PacketQueue::<16, 16>::new()),
56 singleton!(State::new()), 57 p.ETH,
57 p.ETH, 58 eth_int,
58 eth_int, 59 p.PA1,
59 p.PA1, 60 p.PA2,
60 p.PA2, 61 p.PC1,
61 p.PC1, 62 p.PA7,
62 p.PA7, 63 p.PC4,
63 p.PC4, 64 p.PC5,
64 p.PC5, 65 p.PG13,
65 p.PG13, 66 p.PB13,
66 p.PB13, 67 p.PG11,
67 p.PG11, 68 GenericSMI,
68 GenericSMI, 69 mac_addr,
69 mac_addr, 70 0,
70 0, 71 );
71 )
72 };
73 72
74 let config = embassy_net::ConfigStrategy::Dhcp; 73 let config = embassy_net::ConfigStrategy::Dhcp;
75 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { 74 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {
diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs
index 64fd84141..61a08ae10 100644
--- a/examples/stm32h7/src/bin/eth_client.rs
+++ b/examples/stm32h7/src/bin/eth_client.rs
@@ -7,7 +7,7 @@ use embassy_executor::Spawner;
7use embassy_net::tcp::client::{TcpClient, TcpClientState}; 7use embassy_net::tcp::client::{TcpClient, TcpClientState};
8use embassy_net::{Stack, StackResources}; 8use embassy_net::{Stack, StackResources};
9use embassy_stm32::eth::generic_smi::GenericSMI; 9use embassy_stm32::eth::generic_smi::GenericSMI;
10use embassy_stm32::eth::{Ethernet, State}; 10use embassy_stm32::eth::{Ethernet, PacketQueue};
11use embassy_stm32::peripherals::ETH; 11use embassy_stm32::peripherals::ETH;
12use embassy_stm32::rng::Rng; 12use embassy_stm32::rng::Rng;
13use embassy_stm32::time::mhz; 13use embassy_stm32::time::mhz;
@@ -23,11 +23,12 @@ macro_rules! singleton {
23 ($val:expr) => {{ 23 ($val:expr) => {{
24 type T = impl Sized; 24 type T = impl Sized;
25 static STATIC_CELL: StaticCell<T> = StaticCell::new(); 25 static STATIC_CELL: StaticCell<T> = StaticCell::new();
26 STATIC_CELL.init_with(move || $val) 26 let (x,) = STATIC_CELL.init(($val,));
27 x
27 }}; 28 }};
28} 29}
29 30
30type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; 31type Device = Ethernet<'static, ETH, GenericSMI>;
31 32
32#[embassy_executor::task] 33#[embassy_executor::task]
33async fn net_task(stack: &'static Stack<Device>) -> ! { 34async fn net_task(stack: &'static Stack<Device>) -> ! {
@@ -52,25 +53,23 @@ async fn main(spawner: Spawner) -> ! {
52 let eth_int = interrupt::take!(ETH); 53 let eth_int = interrupt::take!(ETH);
53 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; 54 let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
54 55
55 let device = unsafe { 56 let device = Ethernet::new(
56 Ethernet::new( 57 singleton!(PacketQueue::<16, 16>::new()),
57 singleton!(State::new()), 58 p.ETH,
58 p.ETH, 59 eth_int,
59 eth_int, 60 p.PA1,
60 p.PA1, 61 p.PA2,
61 p.PA2, 62 p.PC1,
62 p.PC1, 63 p.PA7,
63 p.PA7, 64 p.PC4,
64 p.PC4, 65 p.PC5,
65 p.PC5, 66 p.PG13,
66 p.PG13, 67 p.PB13,
67 p.PB13, 68 p.PG11,
68 p.PG11, 69 GenericSMI,
69 GenericSMI, 70 mac_addr,
70 mac_addr, 71 0,
71 0, 72 );
72 )
73 };
74 73
75 let config = embassy_net::ConfigStrategy::Dhcp; 74 let config = embassy_net::ConfigStrategy::Dhcp;
76 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config { 75 //let config = embassy_net::ConfigStrategy::Static(embassy_net::Config {