Implement MII for STM32 V1 ethernet peripheral
This commit is contained in:
parent
dd787c3727
commit
d9f708ca6d
@ -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<T>,
|
||||
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<const TX: usize, const RX: usize>(
|
||||
queue: &'d mut PacketQueue<TX, RX>,
|
||||
peri: Peri<'d, T>,
|
||||
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
ref_clk: Peri<'d, impl RefClkPin<T>>,
|
||||
mdio: Peri<'d, impl MDIOPin<T>>,
|
||||
mdc: Peri<'d, impl MDCPin<T>>,
|
||||
@ -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<const TX: usize, const RX: usize>(
|
||||
queue: &'d mut PacketQueue<TX, RX>,
|
||||
peri: Peri<'d, T>,
|
||||
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + '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<const TX: usize, const RX: usize>(
|
||||
queue: &'d mut PacketQueue<TX, RX>,
|
||||
peri: Peri<'d, T>,
|
||||
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
rx_clk: Peri<'d, impl RXClkPin<T>>,
|
||||
tx_clk: Peri<'d, impl TXClkPin<T>>,
|
||||
mdio: Peri<'d, impl MDIOPin<T>>,
|
||||
mdc: Peri<'d, impl MDCPin<T>>,
|
||||
rxdv: Peri<'d, impl RXDVPin<T>>,
|
||||
rx_d0: Peri<'d, impl RXD0Pin<T>>,
|
||||
rx_d1: Peri<'d, impl RXD1Pin<T>>,
|
||||
rx_d2: Peri<'d, impl RXD2Pin<T>>,
|
||||
rx_d3: Peri<'d, impl RXD3Pin<T>>,
|
||||
tx_d0: Peri<'d, impl TXD0Pin<T>>,
|
||||
tx_d1: Peri<'d, impl TXD1Pin<T>>,
|
||||
tx_d2: Peri<'d, impl TXD2Pin<T>>,
|
||||
tx_d3: Peri<'d, impl TXD3Pin<T>>,
|
||||
tx_en: Peri<'d, impl TXEnPin<T>>,
|
||||
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();
|
||||
}
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user