{"record":{"id":"db0be6ef9d4f94f7","repo":"embassy-rs/embassy","slug":"must-be-called-from-core-0","errorCode":null,"errorMessage":"Must be called from Core 0","messagePattern":"Must be called from Core 0","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"embassy-rp/src/bootsel.rs","lineNumber":40,"sourceCode":"/// task and for any DMAs from flash to complete\npub fn is_bootsel_pressed(_p: Peri<'_, crate::peripherals::BOOTSEL>) -> bool {\n    unsafe {\n        // Compute the base address for the GPIO_QSPI_SS_STATUS/GPIO_QSPI_SS_CTRL registers.\n        let cs_gpio: *mut ();\n        if cfg!(feature = \"rp2040\") {\n            cs_gpio = IO_QSPI.gpio(1).as_ptr();\n        } else if cfg!(feature = \"_rp235x\") {\n            cs_gpio = IO_QSPI.gpio(3).as_ptr();\n        } else {\n            unimplemented!()\n        };\n\n        let mut cs_ctrl = GpioCtrl::default();\n        cs_ctrl.set_oeover(Oeover::Disable);\n        let cs_ctrl: u32 = mem::transmute(cs_ctrl);\n\n        let mut cs_status = 0;\n        in_ram(|| cs_status = ram_helpers::read_cs_status(cs_gpio, cs_ctrl)).expect(\"Must be called from Core 0\");\n\n        // bootsel is active low, so invert\n        !mem::transmute::<u32, GpioStatus>(cs_status).infrompad()\n    }\n}\n\nmod ram_helpers {\n\n    /// Temporally reconfigures the CS gpio and returns the GpioStatus.\n\n    /// This function runs from RAM so it can disable flash XIP.\n    ///\n    /// # Safety\n    ///\n    /// The caller must ensure flash is idle and will remain idle.\n    /// This function must live in ram. It uses inline asm to avoid any\n    /// potential calls to ABI functions that might be in flash.\n    #[inline(never)]","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/embassy-rs/embassy/blob/463a07b963419a1bfe61d5d597c44acb810afb8b/embassy-rp/src/bootsel.rs#L22-L58","documentation":"rp2040_bootsel (the SIO ROM-based BOOTSEL button read routine) uses SIO FIFO inter-core messaging that must run on core 0. embassy-rp wraps it in in_ram(|| ...), whose Result is unwrapped with expect(\"Must be called from Core 0\"), so calling is_bootsel_pressed() from core 1 panics at runtime.","triggerScenarios":"Calling embassy_rp::bootsel::is_bootsel_pressed() (directly or via something like `read_cs_status`) from code running on RP2040 core 1 — e.g. inside a closure spawned on CORE1, or in a task pinned to core 1.","commonSituations":"Spawning a task that reads the BOOTSEL button on the second core for load balancing; using the helper inside a multicore worker loop; calling it from an interrupt handled on core 1.","solutions":["Call is_bootsel_pressed() only from core 0 code (main task or a core-0-executed function).","If the button read must happen on core 1, send a request over a channel to core 0, read the button there, and send the result back.","Restructure so boot/button logic stays in setup code that always runs on core 0 before spawning core 1 work."],"exampleFix":"// before (runs on core 1)\ncore1.spawn(move |_| { if is_bootsel_pressed() { ... } });\n// after\ncore0_task: let pressed = is_bootsel_pressed();\nchannel.send(pressed).await; // forward to core 1 consumer","handlingStrategy":"type-guard","validationCode":"// only read BOOTSEL on core 0\n#[cfg(feature = \"rp2040\")]\nfn safe_bootsel_check() -> bool {\n    debug_assert!(!cortex_m::register::mpsir::read().is_some()); // main task runs on core 0\n    embassy_rp::bootsel::is_bootsel_pressed()\n}","typeGuard":null,"tryCatchPattern":"// route the result through core 0 instead of calling directly on core 1\nlet pressed = core0_channel.request(ButtonRead).await;","preventionTips":["Never call is_bootsel_pressed() from closures spawned on CORE1.","Keep hardware/SIO helpers on core 0 and communicate results via channels.","Document core-0-only APIs in your project's architecture notes."],"tags":["embedded","multicore","rp2040","panic","runtime"],"backgroundTag":"unsupported-operation","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"}