diff --git a/embassy-stm32/src/eth/v1/mod.rs b/embassy-stm32/src/eth/v1/mod.rs index 640191d69..01e321bce 100644 --- a/embassy-stm32/src/eth/v1/mod.rs +++ b/embassy-stm32/src/eth/v1/mod.rs @@ -51,12 +51,18 @@ pub struct Ethernet<'d, T: Instance, P: Phy> { pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, - pins: [Peri<'d, AnyPin>; 9], + pins: Pins<'d>, pub(crate) phy: P, pub(crate) station_management: EthernetStationManagement, pub(crate) mac_addr: [u8; 6], } +/// Pins of ethernet driver. +enum Pins<'d> { + Rmii([Peri<'d, AnyPin>; 9]), + Mii([Peri<'d, AnyPin>; 14]), +} + #[cfg(eth_v1a)] macro_rules! config_in_pins { ($($pin:ident),*) => { @@ -96,7 +102,7 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { pub fn new( queue: &'d mut PacketQueue, peri: Peri<'d, T>, - _irq: impl interrupt::typelevel::Binding + 'd, + irq: impl interrupt::typelevel::Binding + 'd, ref_clk: Peri<'d, impl RefClkPin>, mdio: Peri<'d, impl MDIOPin>, mdc: Peri<'d, impl MDCPin>, @@ -146,6 +152,29 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { #[cfg(any(eth_v1b, eth_v1c))] config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); + let pins = Pins::Rmii([ + ref_clk.into(), + mdio.into(), + mdc.into(), + crs.into(), + rx_d0.into(), + rx_d1.into(), + tx_d0.into(), + tx_d1.into(), + tx_en.into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } + + fn new_inner( + queue: &'d mut PacketQueue, + peri: Peri<'d, T>, + _irq: impl interrupt::typelevel::Binding + 'd, + pins: Pins<'d>, + phy: P, + mac_addr: [u8; 6], + ) -> Self { let dma = T::regs().ethernet_dma(); let mac = T::regs().ethernet_mac(); @@ -210,18 +239,6 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { } }; - let pins = [ - ref_clk.into(), - mdio.into(), - mdc.into(), - crs.into(), - rx_d0.into(), - rx_d1.into(), - tx_d0.into(), - tx_d1.into(), - tx_en.into(), - ]; - let mut this = Self { _peri: peri, pins, @@ -267,6 +284,87 @@ impl<'d, T: Instance, P: Phy> Ethernet<'d, T, P> { this } + + /// Create a new MII ethernet driver using 14 pins. + pub fn new_mii( + queue: &'d mut PacketQueue, + peri: Peri<'d, T>, + irq: impl interrupt::typelevel::Binding + 'd, + rx_clk: Peri<'d, impl RXClkPin>, + tx_clk: Peri<'d, impl TXClkPin>, + mdio: Peri<'d, impl MDIOPin>, + mdc: Peri<'d, impl MDCPin>, + rxdv: Peri<'d, impl RXDVPin>, + rx_d0: Peri<'d, impl RXD0Pin>, + rx_d1: Peri<'d, impl RXD1Pin>, + rx_d2: Peri<'d, impl RXD2Pin>, + rx_d3: Peri<'d, impl RXD3Pin>, + tx_d0: Peri<'d, impl TXD0Pin>, + tx_d1: Peri<'d, impl TXD1Pin>, + tx_d2: Peri<'d, impl TXD2Pin>, + tx_d3: Peri<'d, impl TXD3Pin>, + tx_en: Peri<'d, impl TXEnPin>, + phy: P, + mac_addr: [u8; 6], + ) -> Self { + // TODO: Handle optional signals like CRS, MII_COL, RX_ER? + + // Enable the necessary Clocks + #[cfg(eth_v1a)] + critical_section::with(|_| { + RCC.apb2enr().modify(|w| w.set_afioen(true)); + + // Select MII (Media Independent Interface) + // Must be done prior to enabling peripheral clock + AFIO.mapr().modify(|w| w.set_mii_rmii_sel(false)); + + RCC.ahbenr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + }); + + #[cfg(any(eth_v1b, eth_v1c))] + critical_section::with(|_| { + RCC.ahb1enr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + + // MII (Media Independent Interface) + SYSCFG.pmc().modify(|w| w.set_mii_rmii_sel(false)); + }); + + #[cfg(eth_v1a)] + { + config_in_pins!(rx_clk, tx_clk, rx_d0, rx_d1, rx_d2, rx_d3, rxdv); + config_af_pins!(mdio, mdc, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + } + + #[cfg(any(eth_v1b, eth_v1c))] + config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en); + + let pins = Pins::Mii([ + rx_clk.into(), + tx_clk.into(), + mdio.into(), + mdc.into(), + rxdv.into(), + rx_d0.into(), + rx_d1.into(), + rx_d2.into(), + rx_d3.into(), + tx_d0.into(), + tx_d1.into(), + tx_d2.into(), + tx_d3.into(), + tx_en.into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } } /// Ethernet station management interface. @@ -322,7 +420,10 @@ impl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> { dma.dmaomr().modify(|w| w.set_sr(DmaomrSr::STOPPED)); critical_section::with(|_| { - for pin in self.pins.iter_mut() { + for pin in match self.pins { + Pins::Rmii(ref mut pins) => pins.iter_mut(), + Pins::Mii(ref mut pins) => pins.iter_mut(), + } { pin.set_as_disconnected(); } })