embassy-rs/embassy · error

take called more than once!

Error message

take called more than once!

What it means

This panic is in the `impl_peri_interpolators`-style `take_with_cs` glue generated by a macro in embassy-rp's interpolator module. Each interpolator peripheral tracks a per-core `[bool; 2]` flag; if `take`/`take_with_cs` is called twice for the same peripheral on the same core, it panics to enforce single ownership of the hardware block.

Solutions

  1. Ensure `take`/`take_with_cs` for each interpolator is called exactly once per core; store the returned Peri and reuse it
  2. Pass the already-taken interpolator handle into second consumers instead of stealing again
  3. If ownership must move between tasks, structure code so the Peri is passed along rather than re-taken

Example fix

// before
let interp1 = Interp::<0, 0>::take();
let interp1b = Interp::<0, 0>::take(); // panics
// after
let interp1 = Interp::<0, 0>::take();
use_interp(&interp1);
use_interp(&interp1); // reuse the same handle
Defensive patterns

Strategy: type-guard

Validate before calling

static TAKEN: AtomicBool = AtomicBool::new(false);
if TAKEN.swap(true, Ordering::SeqCst) { /* skip re-take */ }

Type guard

fn already_taken(flag: &[bool; 2], core: usize) -> bool { flag[core] }

Prevention

When it happens

Trigger: Calling the interpolator's `take()` (or take_with_cs) more than once for the same interpolator instance on the same core — e.g. constructing two interpolator wrapper objects from the same static, or re-running init code after it already succeeded.

Common situations: Retry logic that re-runs peripheral setup, shared helper functions called from multiple places, or test harnesses initializing the same interpolator repeatedly on core0/core1.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at embassy-rp/src/interpolator.rs:140

        /// Interpolator peripheral type.
        #[derive(Copy, Clone)]
        pub struct $interp {
            not_send: PhantomData<*const ()>,
        }

        impl $interp {
            ///Returns the peripheral *once* for each core. Panics if called more than once per core.
            pub fn take() -> $crate::Peri<'static, Self> {
                critical_section::with(Self::take_with_cs)
            }

            fn take_with_cs(_cs: critical_section::CriticalSection) -> $crate::Peri<'static, Self> {
                #[unsafe(no_mangle)]
                static mut $static: [bool; 2] = [false, false];

                unsafe {
                    if $static[current_core()] {
                        panic!("take called more than once!");
                    }
                    $static[current_core()] = true;

                    Self::steal()
                }
            }

            /// Unsafely create an instance of this peripheral out of thin air.
            ///
            /// # Safety
            ///
            /// You must ensure that you're only using one instance of this type at a time.
            #[inline]
            pub unsafe fn steal() -> $crate::Peri<'static, Self> {
                $crate::Peri::new_unchecked(Self {
                    not_send: PhantomData,
                })
            }

View on GitHub (pinned to 463a07b963)