embassy-rs/embassy · error

Context switching only supported on ARM

Error message

Context switching only supported on ARM

What it means

The WBA context-switching implementation in embassy-stm32-wpan relies on hand-written ARM assembly (context_switch_asm) to save/restore stack pointers. On any non-ARM target_arch the cfg branch falls through to a panic in do_switch, since there is no portable context switch.

Solutions

  1. Build and run only on ARM targets (thumbv7em/thumbv8m etc.) — gate the context manager code behind target_arch = "arm"
  2. Stub or mock the ContextManager in host-side tests with cfg(target_arch) conditionals
  3. Use an emulator/QEMU ARM target instead of running on the host

Example fix

// before
cm.task_yield(); // run on x86_64 host → panics
// after
#[cfg(target_arch = "arm")]
cm.task_yield();
#[cfg(not(target_arch = "arm"))]
log::warn!("task_yield not available on non-ARM targets");
Defensive patterns

Strategy: type-guard

Validate before calling

#[cfg(target_arch = "arm")]
fn context_switching_supported() -> bool { true }
#[cfg(not(target_arch = "arm"))]
fn context_switching_supported() -> bool { false }

Type guard

fn is_arm_target() -> bool { cfg!(target_arch = "arm") }

Prevention

When it happens

Trigger: Calling task_resume or task_yield on the ContextManager while compiling for a non-ARM target (e.g. x86_64 during host-side tests or simulation).

Common situations: Running unit tests of code that depends on the context manager with `cargo test` on a desktop x86 machine; accidentally building for a non-ARM target on an STM32WBA project.

Understand the failure class

Background: "unsupported platform" / "not supported on this platform" errors: what they mean and how to fix them — this error's family across 47 libraries.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/1f962cf35173328d. Report an issue: GitHub.

Appendix: source

Thrown at embassy-stm32-wpan/src/wba/context.rs:186

                self.do_switch(self.task_sp.get(), self.runner_sp.get());
                // Returns here when runner resumes us
            }
            ContextManagerState::Uninitialized => warn!("task_yield called while uninitialized"),
            ContextManagerState::Yielded => warn!("task_yield called while yielded"),
        }
    }

    #[inline]
    fn do_switch(&'static self, save_sp: *mut u32, restore_sp: *mut u32) {
        #[cfg(target_arch = "arm")]
        unsafe {
            context_switch_asm(save_sp, restore_sp);
        }

        #[cfg(not(target_arch = "arm"))]
        {
            let _ = (save_sp, restore_sp);
            panic!("Context switching only supported on ARM");
        }
    }

    pub fn in_task_context(&self) -> bool {
        self.get_state() == ContextManagerState::Running
    }

    fn get_state(&self) -> ContextManagerState {
        self.state.load(Ordering::Acquire).into()
    }

    fn set_state(&self, state: ContextManagerState) {
        self.state.store(state as u8, Ordering::Release);
    }
}

View on GitHub (pinned to 463a07b963)