diff options
| author | Dario Nieuwenhuis <[email protected]> | 2022-12-12 02:04:33 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2022-12-13 16:43:25 +0100 |
| commit | 3005ee0178af46ef8a2b7f8b02f4aea69ed9202b (patch) | |
| tree | 237592613fc66e1a2613feafc7c9ac8de40f67be | |
| parent | 8f3065210927b6e92f6d727741189155b2eab91e (diff) | |
stm32/eth_v2: update to new embassy-net trait, remove PeripheralMutex.
| -rw-r--r-- | embassy-stm32/src/eth/v2/descriptors.rs | 333 | ||||
| -rw-r--r-- | embassy-stm32/src/eth/v2/mod.rs | 383 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/eth.rs | 43 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/eth_client.rs | 43 |
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 @@ | |||
| 1 | use core::sync::atomic::{fence, Ordering}; | 1 | use core::sync::atomic::{fence, Ordering}; |
| 2 | 2 | ||
| 3 | use embassy_net::{Packet, PacketBox, PacketBoxExt, PacketBuf}; | ||
| 4 | use vcell::VolatileCell; | 3 | use vcell::VolatileCell; |
| 5 | 4 | ||
| 5 | use crate::eth::{Packet, RX_BUFFER_SIZE, TX_BUFFER_SIZE}; | ||
| 6 | use crate::pac::ETH; | 6 | use crate::pac::ETH; |
| 7 | 7 | ||
| 8 | #[non_exhaustive] | ||
| 9 | #[derive(Debug, Copy, Clone)] | ||
| 10 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 11 | pub 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)] |
| 19 | mod emac_consts { | 10 | mod 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)] |
| 44 | struct TDes { | 35 | pub(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 | ||
| 67 | pub(crate) struct TDesRing<const N: usize> { | 58 | pub(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 | ||
| 73 | impl<const N: usize> TDesRing<N> { | 64 | impl<'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)] |
| 188 | struct RDes { | 144 | pub(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 | /// | 186 | pub(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 | /// | ||
| 252 | pub(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 | ||
| 259 | impl<const N: usize> RDesRing<N> { | 192 | impl<'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 | ||
| 374 | pub 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 | ||
| 379 | impl<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 @@ | |||
| 1 | use core::marker::PhantomData; | 1 | mod descriptors; |
| 2 | |||
| 2 | use core::sync::atomic::{fence, Ordering}; | 3 | use core::sync::atomic::{fence, Ordering}; |
| 3 | use core::task::Waker; | ||
| 4 | 4 | ||
| 5 | use embassy_cortex_m::peripheral::{PeripheralMutex, PeripheralState, StateStorage}; | 5 | use embassy_cortex_m::interrupt::InterruptExt; |
| 6 | use embassy_hal_common::{into_ref, PeripheralRef}; | 6 | use embassy_hal_common::{into_ref, PeripheralRef}; |
| 7 | use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU}; | ||
| 8 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 9 | 7 | ||
| 8 | pub(crate) use self::descriptors::{RDes, RDesRing, TDes, TDesRing}; | ||
| 9 | use super::*; | ||
| 10 | use crate::gpio::sealed::{AFType, Pin as _}; | 10 | use crate::gpio::sealed::{AFType, Pin as _}; |
| 11 | use crate::gpio::{AnyPin, Speed}; | 11 | use crate::gpio::{AnyPin, Speed}; |
| 12 | use crate::pac::{ETH, RCC, SYSCFG}; | 12 | use crate::pac::{ETH, RCC, SYSCFG}; |
| 13 | use crate::Peripheral; | 13 | use crate::Peripheral; |
| 14 | 14 | ||
| 15 | mod descriptors; | 15 | const MTU: usize = 1514; // 14 Ethernet header + 1500 IP packet |
| 16 | use descriptors::DescriptorRing; | ||
| 17 | |||
| 18 | use super::*; | ||
| 19 | 16 | ||
| 20 | pub struct State<'d, T: Instance, const TX: usize, const RX: usize>(StateStorage<Inner<'d, T, TX, RX>>); | 17 | pub struct Ethernet<'d, T: Instance, P: PHY> { |
| 21 | impl<'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 | } | ||
| 26 | pub 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 | ||
| 35 | macro_rules! config_pins { | 28 | macro_rules! config_pins { |
| @@ -44,10 +37,9 @@ macro_rules! config_pins { | |||
| 44 | }; | 37 | }; |
| 45 | } | 38 | } |
| 46 | 39 | ||
| 47 | impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Ethernet<'d, T, P, TX, RX> { | 40 | impl<'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 | ||
| 216 | unsafe impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> StationManagement | 227 | unsafe 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 | ||
| 254 | impl<'d, T: Instance, P: PHY, const TX: usize, const RX: usize> Device for Ethernet<'d, T, P, TX, RX> { | 263 | impl<'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 | |||
| 291 | impl<'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 | |||
| 331 | struct Inner<'d, T: Instance, const TX: usize, const RX: usize> { | ||
| 332 | _peri: PhantomData<&'d mut T>, | ||
| 333 | desc_ring: DescriptorRing<TX, RX>, | ||
| 334 | } | ||
| 335 | |||
| 336 | impl<'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 | |||
| 345 | impl<'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 | |||
| 370 | static 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; | |||
| 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>) -> ! { |
| @@ -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; | |||
| 7 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; | 7 | use embassy_net::tcp::client::{TcpClient, TcpClientState}; |
| 8 | use embassy_net::{Stack, StackResources}; | 8 | use embassy_net::{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; |
| @@ -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 | ||
| 30 | type Device = Ethernet<'static, ETH, GenericSMI, 4, 4>; | 31 | type Device = Ethernet<'static, ETH, GenericSMI>; |
| 31 | 32 | ||
| 32 | #[embassy_executor::task] | 33 | #[embassy_executor::task] |
| 33 | async fn net_task(stack: &'static Stack<Device>) -> ! { | 34 | async 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 { |
