use core::ops::{Deref, DerefMut};
use crate::{dma::EthernetDMA, hal::rcc::Clocks, peripherals::ETHERNET_MAC, stm32::ETHERNET_MMC};
mod miim;
pub use miim::*;
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Speed {
HalfDuplexBase10T,
FullDuplexBase10T,
HalfDuplexBase100Tx,
FullDuplexBase100Tx,
}
mod consts {
pub const ETH_MACMIIAR_CR_HCLK_DIV_42: u8 = 0;
pub const ETH_MACMIIAR_CR_HCLK_DIV_62: u8 = 1;
pub const ETH_MACMIIAR_CR_HCLK_DIV_16: u8 = 2;
pub const ETH_MACMIIAR_CR_HCLK_DIV_26: u8 = 3;
pub const ETH_MACMIIAR_CR_HCLK_DIV_102: u8 = 4;
}
use self::consts::*;
#[derive(Debug)]
pub struct WrongClock;
pub struct EthernetMAC {
eth_mac: ETHERNET_MAC,
}
impl EthernetMAC {
pub(crate) fn new(
eth_mac: ETHERNET_MAC,
eth_mmc: ETHERNET_MMC,
clocks: Clocks,
initial_speed: Speed,
_dma: &EthernetDMA,
) -> Result<Self, WrongClock> {
let clock_frequency = clocks.hclk().to_Hz();
let clock_range = match clock_frequency {
0..=24_999_999 => return Err(WrongClock),
25_000_000..=34_999_999 => ETH_MACMIIAR_CR_HCLK_DIV_16,
35_000_000..=59_999_999 => ETH_MACMIIAR_CR_HCLK_DIV_26,
60_000_000..=99_999_999 => ETH_MACMIIAR_CR_HCLK_DIV_42,
100_000_000..=149_999_999 => ETH_MACMIIAR_CR_HCLK_DIV_62,
_ => ETH_MACMIIAR_CR_HCLK_DIV_102,
};
eth_mac
.macmiiar
.modify(|_, w| unsafe { w.cr().bits(clock_range) });
eth_mac.maccr.modify(|_, w| {
#[cfg(any(feature = "stm32f4xx-hal", feature = "stm32f7xx-hal"))]
let w = w.cstf().set_bit();
w.fes()
.set_bit()
.dm()
.set_bit()
.ipco()
.set_bit()
.apcs()
.set_bit()
.rd()
.set_bit()
.re()
.set_bit()
.te()
.set_bit()
});
eth_mac.macffr.modify(|_, w| {
w.ra()
.set_bit()
.pm()
.set_bit()
});
eth_mac.macfcr.modify(|_, w| {
w.pt().bits(0x100)
});
eth_mmc
.mmcrimr
.write(|w| w.rgufm().set_bit().rfaem().set_bit().rfcem().set_bit());
eth_mmc
.mmctimr
.write(|w| w.tgfm().set_bit().tgfmscm().set_bit().tgfscm().set_bit());
eth_mmc
.mmctimr
.modify(|r, w| unsafe { w.bits(r.bits() | (1 << 21)) });
let mut me = Self { eth_mac };
me.set_speed(initial_speed);
Ok(me)
}
pub fn mii<'eth, 'pins, Mdio, Mdc>(
&'eth mut self,
mdio: &'pins mut Mdio,
mdc: &'pins mut Mdc,
) -> Stm32Mii<'eth, 'pins, Mdio, Mdc>
where
Mdio: MdioPin,
Mdc: MdcPin,
{
Stm32Mii::new(self, mdio, mdc)
}
pub fn with_mii<MDIO, MDC>(self, mdio: MDIO, mdc: MDC) -> EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
EthernetMACWithMii {
eth_mac: self,
mdio,
mdc,
}
}
pub fn set_speed(&mut self, speed: Speed) {
self.eth_mac.maccr.modify(|_, w| match speed {
Speed::HalfDuplexBase10T => w.fes().clear_bit().dm().clear_bit(),
Speed::FullDuplexBase10T => w.fes().clear_bit().dm().set_bit(),
Speed::HalfDuplexBase100Tx => w.fes().set_bit().dm().clear_bit(),
Speed::FullDuplexBase100Tx => w.fes().set_bit().dm().set_bit(),
});
}
pub fn get_speed(&self) -> Speed {
let cr = self.eth_mac.maccr.read();
match (cr.fes().bit_is_set(), cr.dm().bit_is_set()) {
(false, false) => Speed::HalfDuplexBase10T,
(false, true) => Speed::FullDuplexBase10T,
(true, false) => Speed::HalfDuplexBase100Tx,
(true, true) => Speed::FullDuplexBase100Tx,
}
}
#[cfg(feature = "ptp")]
pub(crate) fn mask_timestamp_trigger_interrupt() {
let mac = &unsafe { &*ETHERNET_MAC::ptr() };
mac.macimr.write(|w| w.tstim().set_bit());
}
#[allow(dead_code)]
pub(crate) fn unmask_timestamp_trigger_interrupt() {
let macimr = &unsafe { &*ETHERNET_MAC::ptr() }.macimr;
macimr.write(|w| w.tstim().clear_bit());
}
}
pub struct EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
pub(crate) eth_mac: EthernetMAC,
mdio: MDIO,
mdc: MDC,
}
impl<MDIO, MDC> EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
pub fn new(eth_mac: EthernetMAC, mdio: MDIO, mdc: MDC) -> Self {
Self { eth_mac, mdio, mdc }
}
pub fn release_pins(self) -> (EthernetMAC, MDIO, MDC) {
(self.eth_mac, self.mdio, self.mdc)
}
}
impl<MDIO, MDC> Deref for EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
type Target = EthernetMAC;
fn deref(&self) -> &Self::Target {
&self.eth_mac
}
}
impl<MDIO, MDC> DerefMut for EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.eth_mac
}
}
impl<MDIO, MDC> EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
pub fn read(&mut self, phy: u8, reg: u8) -> u16 {
self.eth_mac
.mii(&mut self.mdio, &mut self.mdc)
.read(phy, reg)
}
pub fn write(&mut self, phy: u8, reg: u8, data: u16) {
self.eth_mac
.mii(&mut self.mdio, &mut self.mdc)
.write(phy, reg, data)
}
}
impl<MDIO, MDC> miim::Miim for EthernetMACWithMii<MDIO, MDC>
where
MDIO: MdioPin,
MDC: MdcPin,
{
fn read(&mut self, phy: u8, reg: u8) -> u16 {
self.read(phy, reg)
}
fn write(&mut self, phy: u8, reg: u8, data: u16) {
self.write(phy, reg, data)
}
}