{"record":{"id":"dae3d180cf27b147","repo":"embassy-rs/embassy","slug":"ethernet-ptp-clock-already-started","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/v1/mod.rs","lineNumber":430,"sourceCode":"            Flex::new(rx_d0),\n            Flex::new(rx_d1),\n            Flex::new(rx_d2),\n            Flex::new(rx_d3),\n            Flex::new(tx_d0),\n            Flex::new(tx_d1),\n            Flex::new(tx_d2),\n            Flex::new(tx_d3),\n            Flex::new(tx_en),\n        ]);\n\n        Self::new_inner(queue, peri, irq, pins, phy, mac_addr, false)\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\n        // Disable the TX DMA and wait for any previous transmissions to be completed\n        dma.dmaomr().modify(|w| w.set_st(St::Stopped));\n\n        // Disable MAC transmitter and receiver\n        mac.maccr().modify(|w| {","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-stm32/src/eth/v1/mod.rs#L412-L448","documentation":"The Ethernet MAC's PTP clock is a singleton per instance, guarded by a ptp_clock_taken flag. Calling start_ptp() a second time without releasing the returned PtpClock panics, since exclusive ownership would be violated.","triggerScenarios":"Calling eth.start_ptp(config) twice on the same instance; restarting PTP without dropping the previous PtpClock; re-running init code that starts PTP again.","commonSituations":"Retry/reconnect logic reinitializing the network stack; calling start_ptp from two tasks; forgetting the singleton nature.","solutions":["Call start_ptp at most once per instance; store and reuse the returned PtpClock.","Drop the previous PtpClock before starting again, if the driver releases the resource on drop.","Restructure so PTP start happens once in a single init path."],"exampleFix":"// before\nlet ptp = eth.start_ptp(cfg);\nlet ptp2 = eth.start_ptp(cfg); // panics\n// after\nlet ptp = eth.start_ptp(cfg);\ndrop(ptp);\nlet ptp = eth.start_ptp(cfg);","handlingStrategy":"validation","validationCode":"static PTP_STARTED: AtomicBool = AtomicBool::new(false);\nfn start_ptp_once(eth: &mut Ethernet) -> PtpClock<...> {\n    assert!(!PTP_STARTED.swap(true, Ordering::SeqCst), \"PTP clock already started\");\n    eth.start_ptp(ptp_cfg)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Start PTP exactly once, from a single init path.","Store the PtpClock in a OnceCell/static and reuse it.","Drop the PtpClock before any restart attempt."],"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"}