1#[cfg(feature = "stm32f4xx-hal")]
8use stm32f4xx_hal::{
9 bb,
10 gpio::{
11 gpioa::{PA1, PA7},
12 gpiob::{PB11, PB12, PB13},
13 gpioc::{PC4, PC5},
14 gpiog::{PG11, PG13, PG14},
15 Input,
16 Speed::VeryHigh,
17 },
18 pac::{RCC, SYSCFG},
19};
20
21#[cfg(feature = "stm32f7xx-hal")]
22use cortex_m::interrupt;
23
24#[cfg(feature = "stm32f7xx-hal")]
25use stm32f7xx_hal::{
26 gpio::{
27 gpioa::{PA1, PA7},
28 gpiob::{PB11, PB12, PB13},
29 gpioc::{PC4, PC5},
30 gpiog::{PG11, PG13, PG14},
31 Input,
32 Speed::VeryHigh,
33 },
34 pac::{RCC, SYSCFG},
35};
36
37use crate::{
38 dma::EthernetDMA,
39 stm32::{ETHERNET_DMA, ETHERNET_MAC, ETHERNET_MMC},
40};
41
42#[cfg(feature = "ptp")]
43use crate::{ptp::EthernetPTP, stm32::ETHERNET_PTP};
44
45pub(crate) fn setup() {
47 #[cfg(feature = "stm32f4xx-hal")]
48 unsafe {
49 const SYSCFG_BIT: u8 = 14;
50 const ETH_MAC_BIT: u8 = 25;
51 const ETH_TX_BIT: u8 = 26;
52 const ETH_RX_BIT: u8 = 27;
53 const MII_RMII_BIT: u8 = 23;
54
55 let rcc = &*RCC::ptr();
57 let syscfg = &*SYSCFG::ptr();
58
59 bb::set(&rcc.apb2enr, SYSCFG_BIT);
61
62 if rcc.ahb1enr.read().ethmacen().bit_is_set() {
63 bb::clear(&rcc.ahb1enr, ETH_MAC_BIT);
65 }
66 bb::set(&syscfg.pmc, MII_RMII_BIT);
69
70 bb::set(&rcc.ahb1enr, ETH_MAC_BIT);
72 bb::set(&rcc.ahb1enr, ETH_TX_BIT);
73 bb::set(&rcc.ahb1enr, ETH_RX_BIT);
74
75 bb::set(&rcc.ahb1rstr, ETH_MAC_BIT);
77 bb::clear(&rcc.ahb1rstr, ETH_MAC_BIT);
78 }
79 #[cfg(feature = "stm32f7xx-hal")]
80 interrupt::free(|_| unsafe {
82 let rcc = &*RCC::ptr();
84 let syscfg = &*SYSCFG::ptr();
85 rcc.apb2enr.modify(|_, w| w.syscfgen().set_bit());
87
88 if rcc.ahb1enr.read().ethmacen().bit_is_set() {
89 rcc.ahb1enr.modify(|_, w| w.ethmacen().clear_bit());
91 }
92
93 syscfg.pmc.modify(|_, w| w.mii_rmii_sel().set_bit());
96
97 rcc.ahb1enr.modify(|_, w| {
99 w.ethmacen()
100 .set_bit()
101 .ethmactxen()
102 .set_bit()
103 .ethmacrxen()
104 .set_bit()
105 });
106
107 rcc.ahb1rstr.modify(|_, w| w.ethmacrst().set_bit());
109 rcc.ahb1rstr.modify(|_, w| w.ethmacrst().clear_bit());
110 });
111
112 #[cfg(feature = "stm32f1xx-hal")]
113 cortex_m::interrupt::free(|_| unsafe {
114 let afio = &*crate::stm32::AFIO::ptr();
115 let rcc = &*crate::stm32::RCC::ptr();
116
117 rcc.apb2enr.modify(|_, w| w.afioen().set_bit());
119
120 if rcc.ahbenr.read().ethmacen().bit_is_set() {
121 rcc.ahbenr.modify(|_, w| w.ethmacen().clear_bit());
123 }
124
125 afio.mapr.modify(|_, w| w.mii_rmii_sel().set_bit());
128
129 rcc.ahbenr.modify(|_, w| {
131 w.ethmacen()
132 .set_bit()
133 .ethmactxen()
134 .set_bit()
135 .ethmacrxen()
136 .set_bit()
137 .ethmacen()
138 .set_bit()
139 });
140
141 rcc.ahbrstr.modify(|_, w| w.ethmacrst().set_bit());
143 rcc.ahbrstr.modify(|_, w| w.ethmacrst().clear_bit());
144
145 if rcc.ahbenr.read().dma1en().is_disabled() && rcc.ahbenr.read().dma2en().is_disabled() {
156 rcc.ahbenr.modify(|_, w| w.dma2en().enabled());
157 while rcc.ahbenr.read().dma2en().is_disabled() {}
158 }
159 });
160}
161
162macro_rules ! pin_trait {
163 ($([$name:ident, $doc:literal, $rm_name:literal]),*) => {
164 $(
165 #[doc = concat!($doc, "\n# Safety\nOnly pins specified as `ETH_RMII_", $rm_name, "` in a part's Reference Manual\nmay implement this trait.")]
166 pub unsafe trait $name {}
167 )*
168 }
169}
170
171pin_trait!(
172 [RmiiRefClk, "RMII Reference Clock", "REF_CLK"],
173 [RmiiCrsDv, "RMII Rx Data Valid", "CRS_DV"],
174 [RmiiTxEN, "RMII TX Enable", "TX_EN"],
175 [RmiiTxD0, "RMII TX Data Pin 0", "TXD0"],
176 [RmiiTxD1, "RMII TX Data Pin 1", "TXD1"],
177 [RmiiRxD0, "RMII RX Data Pin 0", "RXD0"],
178 [RmiiRxD1, "RMII RX Data Pin 1", "RXD1"]
179);
180
181pub trait AlternateVeryHighSpeed {
183 fn into_af11_very_high_speed(self);
185}
186
187#[allow(missing_docs)]
190pub struct PartsIn {
191 pub mac: ETHERNET_MAC,
192 pub mmc: ETHERNET_MMC,
193 pub dma: ETHERNET_DMA,
194 #[cfg(feature = "ptp")]
195 pub ptp: ETHERNET_PTP,
196}
197
198#[cfg(feature = "ptp")]
199impl From<(ETHERNET_MAC, ETHERNET_MMC, ETHERNET_DMA, ETHERNET_PTP)> for PartsIn {
200 fn from(value: (ETHERNET_MAC, ETHERNET_MMC, ETHERNET_DMA, ETHERNET_PTP)) -> Self {
201 Self {
202 mac: value.0,
203 mmc: value.1,
204 dma: value.2,
205 ptp: value.3,
206 }
207 }
208}
209
210#[cfg(not(feature = "ptp"))]
211impl From<(ETHERNET_MAC, ETHERNET_MMC, ETHERNET_DMA)> for PartsIn {
212 fn from(value: (ETHERNET_MAC, ETHERNET_MMC, ETHERNET_DMA)) -> Self {
213 Self {
214 mac: value.0,
215 mmc: value.1,
216 dma: value.2,
217 }
218 }
219}
220
221pub struct Parts<'rx, 'tx, T> {
223 pub mac: T,
225 pub dma: EthernetDMA<'rx, 'tx>,
227 #[cfg(feature = "ptp")]
229 pub ptp: EthernetPTP,
230}
231
232#[cfg(feature = "ptp")]
233impl<'rx, 'tx, T> Parts<'rx, 'tx, T> {
234 pub fn split(self) -> (T, EthernetDMA<'rx, 'tx>, EthernetPTP) {
236 (self.mac, self.dma, self.ptp)
237 }
238}
239
240#[cfg(not(feature = "ptp"))]
241impl<'rx, 'tx, T> Parts<'rx, 'tx, T> {
242 pub fn split(self) -> (T, EthernetDMA<'rx, 'tx>) {
244 (self.mac, self.dma)
245 }
246}
247
248#[allow(missing_docs)]
252pub struct EthPins<REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1> {
253 pub ref_clk: REFCLK,
254 pub crs: CRS,
255 pub tx_en: TXEN,
256 pub tx_d0: TXD0,
257 pub tx_d1: TXD1,
258 pub rx_d0: RXD0,
259 pub rx_d1: RXD1,
260}
261
262impl<REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1> EthPins<REFCLK, CRS, TXEN, TXD0, TXD1, RXD0, RXD1>
263where
264 REFCLK: RmiiRefClk + AlternateVeryHighSpeed,
265 CRS: RmiiCrsDv + AlternateVeryHighSpeed,
266 TXEN: RmiiTxEN + AlternateVeryHighSpeed,
267 TXD0: RmiiTxD0 + AlternateVeryHighSpeed,
268 TXD1: RmiiTxD1 + AlternateVeryHighSpeed,
269 RXD0: RmiiRxD0 + AlternateVeryHighSpeed,
270 RXD1: RmiiRxD1 + AlternateVeryHighSpeed,
271{
272 pub fn setup_pins(self) {
281 self.ref_clk.into_af11_very_high_speed();
282 self.crs.into_af11_very_high_speed();
283 self.tx_en.into_af11_very_high_speed();
284 self.tx_d0.into_af11_very_high_speed();
285 self.tx_d1.into_af11_very_high_speed();
286 self.rx_d0.into_af11_very_high_speed();
287 self.rx_d1.into_af11_very_high_speed();
288 }
289}
290
291#[allow(unused_macros)]
292macro_rules! impl_pins {
293 ( $($traity:ident: [$($pin:ty,)+],)+ ) => {
294 $(
295 $(
296 unsafe impl $traity for $pin {}
297
298 impl AlternateVeryHighSpeed for $pin {
299 fn into_af11_very_high_speed(self) {
300 self.into_alternate::<11>().set_speed(VeryHigh);
301 }
302 }
303 )+
304 )+
305 };
306}
307
308#[cfg(any(feature = "stm32f4xx-hal", feature = "stm32f7xx-hal"))]
309impl_pins!(
310 RmiiRefClk: [
311 PA1<Input>,
312 ],
313 RmiiCrsDv: [
314 PA7<Input>,
315 ],
316 RmiiTxEN: [
317 PB11<Input>,
318 PG11<Input>,
319 ],
320 RmiiTxD0: [
321 PB12<Input>,
322 PG13<Input>,
323 ],
324 RmiiTxD1: [
325 PB13<Input>,
326 PG14<Input>,
327 ],
328 RmiiRxD0: [
329 PC4<Input>,
330 ],
331 RmiiRxD1: [
332 PC5<Input>,
333 ],
334);
335
336#[cfg(feature = "stm32f1xx-hal")]
337mod stm32f1 {
338 use super::*;
339 use stm32f1xx_hal::gpio::{
340 gpioa::*, gpiob::*, gpioc::*, gpiod::*, Alternate, Floating, IOPinSpeed, Input,
341 OutputSpeed, PushPull,
342 };
343
344 macro_rules! impl_pins {
349 ($($type:ident: [$(($PIN:ty, $is_input:literal)),+]),*) => {
350 $(
351 $(
352 unsafe impl $type for $PIN {}
353 impl AlternateVeryHighSpeed for $PIN {
354 fn into_af11_very_high_speed(self) {
355 cortex_m::interrupt::free(|_| {
359 let cr: &mut _ = &mut unsafe { core::mem::transmute(()) };
365 let mut pin = self.into_alternate_push_pull(cr);
367 pin.set_speed(cr, IOPinSpeed::Mhz50);
368
369 if $is_input {
370 pin.into_floating_input(cr);
371 }
372 });
373 }
374 }
375 )+
376 )*
377 };
378 }
379
380 impl_pins!(
381 RmiiRefClk: [(PA1<Input<Floating>>, true)],
382 RmiiCrsDv: [(PA7<Input<Floating>>, true), (PD8<Input<Floating>>, true)],
383 RmiiTxEN: [(PB11<Alternate<PushPull>>, false)],
384 RmiiTxD0: [(PB12<Alternate<PushPull>>, false)],
385 RmiiTxD1: [(PB13<Alternate<PushPull>>, false)],
386 RmiiRxD0: [(PC4<Input<Floating>>, true), (PD9<Input<Floating>>, true)],
387 RmiiRxD1: [(PC5<Input<Floating>>, true), (PD10<Input<Floating>>, true)]
388 );
389}