diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6c7591f57..698febf71 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -68,7 +68,7 @@ rand_core = "0.6.3" sdio-host = "0.5.0" critical-section = "1.1" #stm32-metapac = { version = "15" } -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab2bc2a739324793656ca1640e1caee2d88df72d" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15" } vcell = "0.1.3" bxcan = "0.7.0" nb = "1.0.0" @@ -89,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] } proc-macro2 = "1.0.36" quote = "1.0.15" #stm32-metapac = { version = "15", default-features = false, features = ["metadata"]} -stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ab2bc2a739324793656ca1640e1caee2d88df72d", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]} [features] diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 414723573..bd4195619 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs @@ -735,13 +735,20 @@ fn main() { (("can", "TX"), quote!(crate::can::TxPin)), (("can", "RX"), quote!(crate::can::RxPin)), (("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)), + (("eth", "RX_CLK"), quote!(crate::eth::RXClkPin)), + (("eth", "TX_CLK"), quote!(crate::eth::TXClkPin)), (("eth", "MDIO"), quote!(crate::eth::MDIOPin)), (("eth", "MDC"), quote!(crate::eth::MDCPin)), (("eth", "CRS_DV"), quote!(crate::eth::CRSPin)), + (("eth", "RX_DV"), quote!(crate::eth::RXDVPin)), (("eth", "RXD0"), quote!(crate::eth::RXD0Pin)), (("eth", "RXD1"), quote!(crate::eth::RXD1Pin)), + (("eth", "RXD2"), quote!(crate::eth::RXD2Pin)), + (("eth", "RXD3"), quote!(crate::eth::RXD3Pin)), (("eth", "TXD0"), quote!(crate::eth::TXD0Pin)), (("eth", "TXD1"), quote!(crate::eth::TXD1Pin)), + (("eth", "TXD2"), quote!(crate::eth::TXD2Pin)), + (("eth", "TXD3"), quote!(crate::eth::TXD3Pin)), (("eth", "TX_EN"), quote!(crate::eth::TXEnPin)), (("fmc", "A0"), quote!(crate::fmc::A0Pin)), (("fmc", "A1"), quote!(crate::fmc::A1Pin)), diff --git a/embassy-stm32/src/eth/mod.rs b/embassy-stm32/src/eth/mod.rs index 448405507..fbcdd7fae 100644 --- a/embassy-stm32/src/eth/mod.rs +++ b/embassy-stm32/src/eth/mod.rs @@ -192,12 +192,19 @@ impl sealed::Instance for crate::peripherals::ETH { } impl Instance for crate::peripherals::ETH {} +pin_trait!(RXClkPin, Instance); +pin_trait!(TXClkPin, Instance); pin_trait!(RefClkPin, Instance); pin_trait!(MDIOPin, Instance); pin_trait!(MDCPin, Instance); +pin_trait!(RXDVPin, Instance); pin_trait!(CRSPin, Instance); pin_trait!(RXD0Pin, Instance); pin_trait!(RXD1Pin, Instance); +pin_trait!(RXD2Pin, Instance); +pin_trait!(RXD3Pin, Instance); pin_trait!(TXD0Pin, Instance); pin_trait!(TXD1Pin, Instance); +pin_trait!(TXD2Pin, Instance); +pin_trait!(TXD3Pin, Instance); pin_trait!(TXEnPin, Instance); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 59745cba0..4b22d1d21 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -39,12 +39,18 @@ pub struct Ethernet<'d, T: Instance, P: PHY> { _peri: PeripheralRef<'d, T>, pub(crate) tx: TDesRing<'d>, pub(crate) rx: RDesRing<'d>, - pins: [PeripheralRef<'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([PeripheralRef<'d, AnyPin>; 9]), + Mii([PeripheralRef<'d, AnyPin>; 14]), +} + macro_rules! config_pins { ($($pin:ident),*) => { critical_section::with(|_| { @@ -57,11 +63,11 @@ macro_rules! config_pins { } impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { - /// Create a new Ethernet driver. + /// Create a new RMII ethernet driver using 9 pins. pub fn new( queue: &'d mut PacketQueue, peri: impl Peripheral

+ 'd, - _irq: impl interrupt::typelevel::Binding + 'd, + irq: impl interrupt::typelevel::Binding + 'd, ref_clk: impl Peripheral

> + 'd, mdio: impl Peripheral

> + 'd, mdc: impl Peripheral

> + 'd, @@ -74,8 +80,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { phy: P, mac_addr: [u8; 6], ) -> Self { - into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); - // Enable the necessary Clocks #[cfg(not(rcc_h5))] critical_section::with(|_| { @@ -85,7 +89,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_eth1rxen(true); }); - // RMII crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100)); }); @@ -99,14 +102,110 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { w.set_ethrxen(true); }); - // RMII crate::pac::SYSCFG .pmcr() .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); }); + into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en); + let pins = Pins::Rmii([ + ref_clk.map_into(), + mdio.map_into(), + mdc.map_into(), + crs.map_into(), + rx_d0.map_into(), + rx_d1.map_into(), + tx_d0.map_into(), + tx_d1.map_into(), + tx_en.map_into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } + + /// Create a new MII ethernet driver using 14 pins. + pub fn new_mii( + queue: &'d mut PacketQueue, + peri: impl Peripheral

+ 'd, + irq: impl interrupt::typelevel::Binding + 'd, + rx_clk: impl Peripheral

> + 'd, + tx_clk: impl Peripheral

> + 'd, + mdio: impl Peripheral

> + 'd, + mdc: impl Peripheral

> + 'd, + rxdv: impl Peripheral

> + 'd, + rx_d0: impl Peripheral

> + 'd, + rx_d1: impl Peripheral

> + 'd, + rx_d2: impl Peripheral

> + 'd, + rx_d3: impl Peripheral

> + 'd, + tx_d0: impl Peripheral

> + 'd, + tx_d1: impl Peripheral

> + 'd, + tx_d2: impl Peripheral

> + 'd, + tx_d3: impl Peripheral

> + 'd, + tx_en: impl Peripheral

> + 'd, + phy: P, + mac_addr: [u8; 6], + ) -> Self { + // Enable necessary clocks. + #[cfg(not(rcc_h5))] + critical_section::with(|_| { + crate::pac::RCC.ahb1enr().modify(|w| { + w.set_eth1macen(true); + w.set_eth1txen(true); + w.set_eth1rxen(true); + }); + + crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b000)); + }); + + #[cfg(rcc_h5)] + critical_section::with(|_| { + crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true)); + + crate::pac::RCC.ahb1enr().modify(|w| { + w.set_ethen(true); + w.set_ethtxen(true); + w.set_ethrxen(true); + }); + + // TODO: This is for RMII - what would MII need here? + crate::pac::SYSCFG + .pmcr() + .modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4)); + }); + + into_ref!(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); + 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.map_into(), + tx_clk.map_into(), + mdio.map_into(), + mdc.map_into(), + rxdv.map_into(), + rx_d0.map_into(), + rx_d1.map_into(), + rx_d2.map_into(), + rx_d3.map_into(), + tx_d0.map_into(), + tx_d1.map_into(), + tx_d2.map_into(), + tx_d3.map_into(), + tx_en.map_into(), + ]); + + Self::new_inner(queue, peri, irq, pins, phy, mac_addr) + } + + fn new_inner( + queue: &'d mut PacketQueue, + peri: impl Peripheral

+ 'd, + _irq: impl interrupt::typelevel::Binding + 'd, + pins: Pins<'d>, + phy: P, + mac_addr: [u8; 6], + ) -> Self { let dma = ETH.ethernet_dma(); let mac = ETH.ethernet_mac(); let mtl = ETH.ethernet_mtl(); @@ -182,24 +281,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> { } }; - let pins = [ - ref_clk.map_into(), - mdio.map_into(), - mdc.map_into(), - crs.map_into(), - rx_d0.map_into(), - rx_d1.map_into(), - tx_d0.map_into(), - tx_d1.map_into(), - tx_en.map_into(), - ]; - let mut this = Self { - _peri: peri, + _peri: peri.into_ref(), tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf), rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf), pins, - phy: phy, + phy, station_management: EthernetStationManagement { peri: PhantomData, clock_range: clock_range, @@ -302,7 +389,10 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> { dma.dmacrx_cr().modify(|w| w.set_sr(false)); 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(); } }) diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index dcc6e36e2..aeb169e19 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -65,6 +65,7 @@ async fn main(spawner: Spawner) -> ! { let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; static PACKETS: StaticCell> = StaticCell::new(); + let device = Ethernet::new( PACKETS.init(PacketQueue::<16, 16>::new()), p.ETH, diff --git a/examples/stm32h7/src/bin/eth_client_mii.rs b/examples/stm32h7/src/bin/eth_client_mii.rs new file mode 100644 index 000000000..de6ea522a --- /dev/null +++ b/examples/stm32h7/src/bin/eth_client_mii.rs @@ -0,0 +1,142 @@ +#![no_std] +#![no_main] + +use defmt::*; +use embassy_executor::Spawner; +use embassy_net::tcp::client::{TcpClient, TcpClientState}; +use embassy_net::{Stack, StackResources}; +use embassy_stm32::eth::generic_smi::GenericSMI; +use embassy_stm32::eth::{Ethernet, PacketQueue}; +use embassy_stm32::peripherals::ETH; +use embassy_stm32::rng::Rng; +use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config}; +use embassy_time::Timer; +use embedded_io_async::Write; +use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect}; +use rand_core::RngCore; +use static_cell::StaticCell; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + ETH => eth::InterruptHandler; + RNG => rng::InterruptHandler; +}); + +type Device = Ethernet<'static, ETH, GenericSMI>; + +#[embassy_executor::task] +async fn net_task(stack: &'static Stack) -> ! { + stack.run().await +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) -> ! { + let mut config = Config::default(); + { + use embassy_stm32::rcc::*; + config.rcc.hsi = Some(HSIPrescaler::DIV1); + config.rcc.csi = true; + config.rcc.hsi48 = Some(Default::default()); // needed for RNG + config.rcc.pll1 = Some(Pll { + source: PllSource::HSI, + prediv: PllPreDiv::DIV4, + mul: PllMul::MUL50, + divp: Some(PllDiv::DIV2), + divq: None, + divr: None, + }); + config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz + config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz + config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz + config.rcc.voltage_scale = VoltageScale::Scale1; + } + let p = embassy_stm32::init(config); + info!("Hello World!"); + + // Generate random seed. + let mut rng = Rng::new(p.RNG, Irqs); + let mut seed = [0; 8]; + rng.fill_bytes(&mut seed); + let seed = u64::from_le_bytes(seed); + + let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF]; + + static PACKETS: StaticCell> = StaticCell::new(); + + let device = Ethernet::new_mii( + PACKETS.init(PacketQueue::<16, 16>::new()), + p.ETH, + Irqs, + p.PA1, + p.PC3, + p.PA2, + p.PC1, + p.PA7, + p.PC4, + p.PC5, + p.PB0, + p.PB1, + p.PG13, + p.PG12, + p.PC2, + p.PE2, + p.PG11, + GenericSMI::new(1), + mac_addr, + ); + info!("Device created"); + + let config = embassy_net::Config::dhcpv4(Default::default()); + //let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 { + // address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24), + // dns_servers: Vec::new(), + // gateway: Some(Ipv4Address::new(10, 42, 0, 1)), + //}); + + // Init network stack + static STACK: StaticCell> = StaticCell::new(); + static RESOURCES: StaticCell> = StaticCell::new(); + let stack = &*STACK.init(Stack::new( + device, + config, + RESOURCES.init(StackResources::<3>::new()), + seed, + )); + + // Launch network task + unwrap!(spawner.spawn(net_task(stack))); + + // Ensure DHCP configuration is up before trying connect + stack.wait_config_up().await; + + info!("Network task initialized"); + + let state: TcpClientState<1, 1024, 1024> = TcpClientState::new(); + let client = TcpClient::new(&stack, &state); + + loop { + // You need to start a server on the host machine, for example: `nc -l 8000` + let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 100, 1), 8000)); + + info!("connecting..."); + let r = client.connect(addr).await; + if let Err(e) = r { + info!("connect error: {:?}", e); + Timer::after_secs(1).await; + continue; + } + let mut connection = r.unwrap(); + info!("connected!"); + loop { + let r = connection.write_all(b"Hello\n").await; + if let Err(e) = r { + info!("write error: {:?}", e); + break; + } + Timer::after_secs(1).await; + } + } +}