{"record":{"id":"43cd57862d3153a1","repo":"embassy-rs/embassy","slug":"ethernet-ptp-clock-already-started-43cd57","errorCode":null,"errorMessage":"Ethernet PTP clock already started","messagePattern":"Ethernet PTP clock already started","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-stm32/src/eth/v2/mod.rs","lineNumber":582,"sourceCode":"        #[cfg(eth_v2)]\n        {\n            interrupt::ETH.unpend();\n            unsafe { interrupt::ETH.enable() };\n        }\n        #[cfg(any(eth_v2a, eth_v2b))]\n        {\n            interrupt::ETH1.unpend();\n            unsafe { interrupt::ETH1.enable() };\n        }\n\n        this\n    }\n\n    /// Start the Ethernet MAC PTP clock.\n    #[cfg(feature = \"ptp\")]\n    pub fn start_ptp(&mut self, config: PtpClockConfig) -> PtpClock<T> {\n        if self.ptp_clock_taken {\n            panic!(\"Ethernet PTP clock already started\");\n        }\n\n        let clock = PtpClock::start(config);\n        self.ptp_clock_taken = true;\n        clock\n    }\n}\n\nimpl<'d, T: Instance, P: Phy> Drop for Ethernet<'d, T, P> {\n    fn drop(&mut self) {\n        let dma = T::regs().ethernet_dma();\n        let mac = T::regs().ethernet_mac();\n        let mtl = T::regs().ethernet_mtl();\n\n        // Disable the TX DMA and wait for any previous transmissions to be completed\n        ch0!(dma, dmac_tx_cr).modify(|w| w.set_st(false));\n        while {\n            let txqueue = ch0!(mtl, mtl_tx_qdr).read();","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/eth/v2/mod.rs#L564-L600","documentation":"start_ptp() guards on the ptp_clock_taken flag: the Ethernet peripheral exposes a single PTP clock, and this instance already handed out a PtpClock from a previous call. The panic prevents two PtpClock handles from racing over the same hardware timestamping block; the faulting input is a duplicate start_ptp() call on the same Ethernet object.","triggerScenarios":"Calling start_ptp() twice on the same v2 Ethernet instance, or restarting PTP while the previous PtpClock has not been dropped.","commonSituations":"Network re-init on reconnect; two tasks both calling start_ptp; duplicated init sequences in different code paths.","solutions":["Call start_ptp only once; keep and reuse the returned PtpClock.","Drop the existing PtpClock before calling start_ptp again.","Guard PTP startup behind a OnceCell/init flag in application code."],"exampleFix":"// before\n// each reconnect:\nlet ptp = eth.start_ptp(cfg);\n// after\nstatic PTP: OnceCell<PtpClock<...>> = OnceCell::new();\nPTP.get_or_init(|| eth.start_ptp(cfg));","handlingStrategy":"validation","validationCode":"static PTP_TAKEN: AtomicBool = AtomicBool::new(false);\nfn start_ptp_once(eth: &mut Ethernet) -> PtpClock<...> {\n    if PTP_TAKEN.load(Ordering::SeqCst) { panic!(\"start_ptp must only be called once\"); }\n    PTP_TAKEN.store(true, Ordering::SeqCst);\n    eth.start_ptp(ptp_cfg)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the returned PtpClock alive in app state instead of restarting.","Route all network init through one function so start_ptp cannot be duplicated.","Drop the PtpClock before any re-init."],"tags":["embedded","rust","ethernet","ptp","api-misuse"],"backgroundTag":"invalid-state-transition","analyzedSha":"463a07b963419a1bfe61d5d597c44acb810afb8b","analyzedAt":"2026-09-10T13:38:26.660Z","contentChangedAt":"2026-09-10T13:38:26.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}