#![no_std] #![feature(rustc_private)] extern crate fusible; use core::net::Ipv4Addr; use core::num::NonZeroU8; use core::pin::Pin; use imxrt_rt as _; use imxrt1170evk_fcb as _; use rust_threadx_cortex_m as _; use rust_threadx_imxrt::*; use rust_threadx_stdio_semihosting as _; use drivers::{enet, gpio}; use imxrt1170::interrupt; use fusible::netx_duo::{ ip::{Ip, IpContext}, packet::{PacketPool, PacketPoolContext, StaticPacketStorage, packet_storage_size}, }; #[doc(hidden)] #[unsafe(no_mangle)] pub unsafe extern "C" fn _tx_initialize_low_level() { use cortex_m::{ Peripherals, peripheral::{scb::SystemHandler, syst::SystClkSource}, }; cortex_m::interrupt::disable(); unsafe { let Peripherals { mut SYST, mut SCB, .. } = Peripherals::steal(); SCB.set_priority(SystemHandler::SysTick, 0x40); SCB.set_priority(SystemHandler::PendSV, 0xff); SCB.set_priority(SystemHandler::SVCall, 0xff); SYST.set_clock_source(SystClkSource::External); SYST.set_reload(100_000 / 100 - 1); SYST.clear_current(); SYST.enable_interrupt(); SYST.enable_counter(); } } use fusible::thread::{StaticStack, Thread, ThreadContext}; static STACK: StaticStack<512> = StaticStack::new(); static THREAD: ThreadContext = Thread::context(); #[unsafe(no_mangle)] #[doc(hidden)] pub extern "C" fn __rust_threadx_app_define() { configure_clocks(); configure_pins(); unsafe { cortex_m::peripheral::NVIC::unmask(interrupt::ENET); let gpio3 = GPIO3.create(const { imxrt1170::instances::gpio3() }); let gpio6 = GPIO6.create(const { imxrt1170::instances::gpio6() }); let led = gpio3.make_output(gpio::IO::IO03); let phy_rst = gpio6.make_output(gpio::IO::IO12); let enet = ENET.create( imxrt1170::instances::enet(), ENET_TX_RING.as_slice(), ENET_RX_RING.as_slice(), rust_threadx_net_phys::ksz8081::Ksz8081::new(), phy_rst, BUS_FREQUENCY_HZ, ); let pool = PacketPool::create( Pin::static_ref(&PACKET_POOL), PACKET_STORAGE.0.take().unwrap(), 1536 / 12, &Default::default(), ) .unwrap(); let ip = Ip::create( Pin::static_ref(&IP), Ipv4Addr::new(192, 168, 5, 1), 0xffff_ff00, pool, enet, IP_THREAD_STACK.take().unwrap(), &Default::default(), ) .unwrap(); ip.set_physical_address(0x0011, 0x22334456); ip.enable_arp(); ip.enable_udp(); ip.enable_icmp(); Thread::create( Pin::static_ref(&THREAD), STACK.take().unwrap(), &Default::default(), move || loop { fusible::thread::sleep(25); led.toggle(); }, ) .unwrap(); } } #[unsafe(no_mangle)] #[doc(hidden)] pub extern "C" fn __rust_threadx_ip() -> Option<&'static Ip> { Pin::static_ref(&IP).try_created() } fn configure_clocks() { use imxrt1170::{ccm, gpc_cpu_mode_ctrl as gpc_cpu, pmu}; let ccm = unsafe { imxrt1170::instances::ccm() }; let pmu = unsafe { imxrt1170::instances::pmu() }; let gpc_cpu = unsafe { imxrt1170::instances::gpc_cpu_mode_ctrl0() }; let pll = unsafe { imxrt1170::instances::pll() }; // Switch the core to something stable before we // start changing upstream sources. ccm::set_clock_root( ccm, ccm::ClockRoot::M7, const { ccm::mux(ccm::ClockRoot::M7, ccm::ClockSource::Xtal) }, NO_DIVIDER, ); ccm::set_clock_root( ccm, ccm::ClockRoot::Bus, const { ccm::mux(ccm::ClockRoot::Bus, ccm::ClockSource::Xtal) }, NO_DIVIDER, ); ccm::set_clock_root( ccm, ccm::ClockRoot::BusLpsr, const { ccm::mux(ccm::ClockRoot::BusLpsr, ccm::ClockSource::Xtal) }, NO_DIVIDER, ); ccm::set_clock_root( ccm, ccm::ClockRoot::M7Systick, const { ccm::mux(ccm::ClockRoot::M7Systick, ccm::ClockSource::Xtal) }, const { NonZeroU8::new(240).unwrap() }, ); pmu::enable_pll_reference_voltage(pmu, true); pmu::set_phy_ldo_setpoints(pmu, u16::MAX); pmu::enable_phy_ldo_setpoints(pmu); pmu::enable_pll_reference_setpoints(pmu); for clock_source in { use ccm::ClockSource::*; [ Pll1, Pll1Clk, Pll1Div2, Pll1Div5, ArmPll, ArmPllClk, // Pll2, Pll2Clk, Pll2Pfd0, Pll2Pfd1, Pll2Pfd2, Pll2Pfd3, // Pll3, Pll3Clk, Pll3Div2, Pll3Pfd0, Pll3Pfd1, Pll3Pfd2, Pll3Pfd3, // ] } { ccm::set_source_setpoints(ccm, clock_source, u16::MAX, 0); ccm::enable_source_setpoints(ccm, clock_source).unwrap(); } ccm::pll::enable_sys_pll1_setpoints(pll); ccm::pll::enable_arm_pll_setpoints(pll, ARM_PLL_POST_DIV, ARM_PLL_DIV_SELECT); ccm::pll::enable_sys_pll2_setpoints(pll); ccm::pll::enable_sys_pll3_setpoints(pll); gpc_cpu::request_setpoint_transition(gpc_cpu, 1).unwrap(); ccm::pll::set_pll3_pfd_fracs( pll, [ SYS_PLL3_PFD0_DIV, SYS_PLL3_PFD1_DIV, SYS_PLL3_PFD2_DIV, SYS_PLL3_PFD3_DIV, ], ); ccm::pll::update_pll3_pfd_fracs(pll, [true, true, true, true]); ccm::set_clock_root( ccm, ccm::ClockRoot::M7, const { ccm::mux(ccm::ClockRoot::M7, ccm::ClockSource::ArmPll) }, M7_DIVIDER, ); ccm::set_clock_root( ccm, ccm::ClockRoot::Bus, const { ccm::mux(ccm::ClockRoot::Bus, ccm::ClockSource::Pll1Div5) }, BUS_DIVIDER, ); ccm::set_clock_root( ccm, ccm::ClockRoot::Enet, const { ccm::mux(ccm::ClockRoot::Enet, ccm::ClockSource::Pll1Div2) }, const { NonZeroU8::new((SYS_PLL1_DIV2_FREQUENCY_HZ / ENET_FREQUENCY_HZ) as u8).unwrap() }, ); } const NO_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap(); const M7_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap(); const BUS_DIVIDER: NonZeroU8 = NonZeroU8::new(1).unwrap(); const FLEXSPI1_DIVIDER: NonZeroU8 = NonZeroU8::new(2).unwrap(); pub const XTAL_FREQUENCY_HZ: u32 = 24_000_000; pub const BUS_FREQUENCY_HZ: u32 = SYS_PLL1_DIV5_FREQUENCY_HZ / BUS_DIVIDER.get() as u32; pub const ENET_FREQUENCY_HZ: u32 = 50_000_000; pub const SYS_PLL1_FREQUENCY_HZ: u32 = 1_000_000_000; pub const SYS_PLL1_DIV2_FREQUENCY_HZ: u32 = SYS_PLL1_FREQUENCY_HZ / 2; pub const SYS_PLL1_DIV5_FREQUENCY_HZ: u32 = SYS_PLL1_FREQUENCY_HZ / 5; pub const M7_FREQUENCY_HZ: u32 = ARM_PLL_FREQUENCY_HZ / M7_DIVIDER.get() as u32; pub const SYS_PLL2_FREQUENCY_HZ: u32 = 528_000_000; pub const SYS_PLL3_FREQUENCY_HZ: u32 = 480_000_000; pub const FLEXSPI1_FREQUENCY_HZ: u32 = SYS_PLL3_FREQUENCY_HZ / SYS_PLL3_PFD0_DIV.get() as u32 / FLEXSPI1_DIVIDER.get() as u32 * 18; const ARM_PLL_DIV_SELECT: imxrt1170::ccm::pll::ArmPllDivSelect = imxrt1170::ccm::pll::ArmPllDivSelect::new(200).unwrap(); const ARM_PLL_POST_DIV: imxrt1170::ccm::pll::ArmPllPostDiv = imxrt1170::ccm::pll::ArmPllPostDiv::Div4; const ARM_PLL_FREQUENCY_HZ: u32 = imxrt1170::ccm::pll::arm_pll_frequency(ARM_PLL_POST_DIV, ARM_PLL_DIV_SELECT); const SYS_PLL3_PFD0_DIV: imxrt1170::ccm::pll::PfdFrac = imxrt1170::ccm::pll::PfdFrac::new(33).unwrap(); const SYS_PLL3_PFD1_DIV: imxrt1170::ccm::pll::PfdFrac = imxrt1170::ccm::pll::PfdFrac::new(27).unwrap(); const SYS_PLL3_PFD2_DIV: imxrt1170::ccm::pll::PfdFrac = imxrt1170::ccm::pll::PfdFrac::new(21).unwrap(); const SYS_PLL3_PFD3_DIV: imxrt1170::ccm::pll::PfdFrac = imxrt1170::ccm::pll::PfdFrac::new(17).unwrap(); fn configure_pins() { use imxrt1170::{ iomuxc::{self, select_input}, iomuxc_gpr, iomuxc_lpsr, }; let iomuxc = unsafe { imxrt1170::instances::iomuxc() }; let iomuxc_gpr = unsafe { imxrt1170::instances::iomuxc_gpr() }; let iomuxc_lpsr = unsafe { imxrt1170::instances::iomuxc_lpsr() }; // ENET_REF_CLK driven as output. modify_reg!(iomuxc_gpr, iomuxc_gpr, GPR[4], |gpr| gpr | (1 << 1)); // ERR050396 handling. modify_reg!(iomuxc_gpr, iomuxc_gpr, GPR[28], |gpr| gpr | (1 << 5) | (1 << 7)); // LED. write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[4], MUX_MODE: 5); write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[4], PUE: 0); // ENET PHY_RST. write_reg!(iomuxc_lpsr, iomuxc_lpsr, SW_MUX_CTL_PAD[12], MUX_MODE: 5); // ENET RMII. write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[32], MUX_MODE: 3, SION: 0); // MDC write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_AD[33], MUX_MODE: 3, SION: 0); // MDIO write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[2], MUX_MODE: 1, SION: 0); // TX_DATA0 write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[3], MUX_MODE: 1, SION: 0); // TX_DATA1 write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[4], MUX_MODE: 1, SION: 0); // TX_EN write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[5], MUX_MODE: 2, SION: 1); // REF_CLK write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[6], MUX_MODE: 1, SION: 1); // RX_DATA0 write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[7], MUX_MODE: 1, SION: 1); // RX_DATA1 write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[8], MUX_MODE: 1, SION: 0); // RX_EN write_reg!(iomuxc, iomuxc, SW_MUX_CTL_PAD.GPIO_DISP_B2[9], MUX_MODE: 1, SION: 0); // RX_ER write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[32], PUE: 1, PUS: PULL_UP, ODE: 0); // MDC write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_AD[33], PUE: 1, PUS: PULL_UP, ODE: 1); // MDIO write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[2], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_DATA0 write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[3], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_DATA1 write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[4], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // TX_EN write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[5], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // REF_CLK write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[6], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_DATA0 write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[7], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_DATA1 write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[8], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_EN write_reg!(iomuxc, iomuxc, SW_PAD_CTL_PAD.GPIO_DISP_B2[9], PUE: 0, SRE: SLOW, DSE: HIGH, ODE: 0); // RX_ER for select_input in [ select_input::ENET_IPG_CLK_RMII, select_input::ENET_MAC0_MDIO, select_input::ENET_MAC0_RXDATA_0, select_input::ENET_MAC0_RXDATA_1, select_input::ENET_MAC0_RXEN, select_input::ENET_MAC0_RXERR, ] { write_reg!(iomuxc, iomuxc, SELECT_INPUT[select_input], 1); } } type Enet = drivers::enet::Enet; static ENET: enet::EnetContext = enet::EnetContext::new(); static ENET_TX_RING: enet::TxRing<16> = enet::TxRing::ZEROED; static ENET_RX_RING: enet::RxRing<16> = enet::RxRing::ZEROED; static IP: IpContext = Ip::context(); #[repr(align(64))] pub struct AlignedPacketStorage(StaticPacketStorage<{ packet_storage_size(8 * 12, 1536 / 12) }>); static PACKET_POOL: PacketPoolContext = PacketPool::context(); static PACKET_STORAGE: AlignedPacketStorage = AlignedPacketStorage(StaticPacketStorage::new()); static IP_THREAD_STACK: StaticStack<4096> = StaticStack::new(); static GPIO3: gpio::GpioContext = gpio::GpioContext::new(); static GPIO6: gpio::GpioContext = gpio::GpioContext::new(); #[imxrt_rt::interrupt] fn ENET() { unsafe { ENET.on_interrupt( const { imxrt1170::instances::enet() }, Pin::static_ref(&IP).assume_created(), ) } }