Skip to content

A simple embedded Rust project running on the Raspberry Pi Pico (RP2040), built with Embassy async framework and no_std runtime.

License

Notifications You must be signed in to change notification settings

mytechnotalent/rust_embassy_pico_project

Repository files navigation

image

Rust Embassy Pico Project

A simple embedded Rust project running on the Raspberry Pi Pico (RP2040), built with Embassy async framework and no_std runtime.


FREE Reverse Engineering Self-Study Course HERE


Wiring

image image

Features

  • Configures an onboard LED (GPIO25).
  • Configures a button (GPIO16) with internal pull-up.
  • Turns LED on when button is pressed, off when released.
  • Debounces the button with async timer.
  • Runs under Embassy's async executor with no RTOS, no heap.

Project Structure

  • main.rs: Initializes Embassy, spawns the main async task.
  • button.rs: Provides button GPIO initialization.
  • led.rs: Provides simple onboard LED control abstraction.
  • run_cycle.rs: Defines a single button-press LED-control cycle.

How It Works (Step-by-Step)

  1. Startup

    • The RP2040 boot ROM loads your program from flash.
    • The Cortex-M cortex-m-rt runtime (#[no_main]) skips the traditional main() and jumps into the reset vector.
    • The __cortex_m_rt_main_trampoline is called automatically at startup.
    • __cortex_m_rt_main_trampoline calls __cortex_m_rt_main, which manually initializes and starts the async executor.
  2. Executor Initialization

    • A static instance of Executor is created by transmute-ing a stack object to 'static lifetime.
    • executor.run() is called, entering Embassy’s async runtime loop.
    • A Spawner is provided by the executor, allowing you to spawn tasks.
  3. Task Spawning (Enqueue Operation)

    • Spawner::must_spawn(__embassy_main(spawner)) is called.
    • The __embassy_main_task future is created and wrapped into a Task.
    • Enqueue:
      • The Task is added to the Task Queue, a statically allocated double-ended queue (deque) implemented internally by the Executor.
      • This is a lock-free queue; in single-core systems like RP2040, no locks are needed.
      • Enqueue happens at the tail (back) of the queue — FIFO behavior is preserved.
  4. Executor Main Loop (Deque + Polling)

    • The Executor enters its main loop:
      • Dequeue:
        • A Task is popped from the head (front) of the queue.
      • The Executor polls the Task’s future by calling its poll() method.
        • If the Future returns Poll::Pending, it means it cannot complete immediately:
          • The Task registers a Waker — when an awaited event (e.g., timer, GPIO interrupt) completes, the Waker re-schedules the task.
          • The task is then re-enqueued at the tail for future polling.
        • If the Future returns Poll::Ready, the Task has completed:
          • The Task is dropped and removed permanently from the system.
      • If there are no tasks left in the queue, the Executor executes a WFI (Wait-For-Interrupt) instruction, entering low-power sleep until an interrupt occurs.
  5. Peripheral Setup

    • In the spawned ____embassy_main_task:
      • embassy_rp::init() is called to set up clocks, watchdog, and peripherals.
      • PIN_16 is configured as an input GPIO with an internal pull-up resistor (for the button).
      • PIN_25 is configured as an output GPIO (for the onboard LED).
  6. Task Execution

    • Inside the loop {}:
      • run_cycle is called and awaited:
        • Waits for a button press (falling edge detected on the input pin).
        • Turns the LED on by driving PIN_25 high.
        • Waits for a button release (rising edge).
        • Turns the LED off by driving PIN_25 low.
        • Waits 10ms for debounce using Timer::after_millis.
      • run_cycle returns Poll::Ready, but since it's inside an infinite loop, a new future is immediately constructed for the next cycle.
    • As run_cycle awaits on GPIO events and timers, the task yields control back to the Executor, causing the task to be re-enqueued and other pending tasks (if any) to be polled.
  7. Event Handling and Re-Scheduling

    • When the awaited GPIO or timer event completes:
      • The Task’s registered Waker is triggered.
      • The Task is re-enqueued into the Task Queue tail.
      • On the next executor loop iteration, it will be dequeued and poll() will resume where it left off in its await.
  8. Continuous Loop

    • The ____embassy_main_task is never terminated due to its infinite loop.
    • This cycle continues indefinitely, reacting to button presses/releases, toggling the LED accordingly.

Embassy Executor Enqueue/Dequeue In Detail

  • Enqueue (Push-Back):

    • When a Future yields Poll::Pending, the Task’s Waker will call spawn().
    • Internally, this pushes the Task to the back of the Task Queue.
    • The Task Queue is lock-free, array-backed with bounded capacity.
    • Waker ensures the task is only enqueued if it was not already enqueued (no duplication).
  • Dequeue (Pop-Front):

    • Executor pops a Task from the front of the queue (FIFO order).
    • Calls poll() on the Task.
    • If Poll::Pending, the Task will re-enqueue after its awaited event is ready.
    • If Poll::Ready, the Task is cleaned up and removed.
  • Task Scheduling:

    • Tasks are cooperatively scheduled.
    • No preemption — a task must yield (await) to allow others to run.
    • If all tasks are Pending, Executor enters WFI (low-power wait).
  • Wakers:

    • Embassy provides a lightweight Waker implementation tied to the Task.
    • When a peripheral (e.g., Timer or GPIO interrupt) completes, the Waker triggers the task re-enqueue.
  • No Dynamic Memory:

    • All Tasks are statically allocated.
    • The queue and task structures are baked into flash/ram at compile time.
    • Ensures no heap fragmentation and determinism — critical for embedded systems.

Deep Dive: From Reset to run_cycle Poll

Below is every assembler instruction captured, with mangled ↔ demangled names and addresses.

1. Reset Vector (Reset @ 0x100001c0)

0x100001c0 <+0>: bl 0x10007a94 <__pre_init> 0x100001c4 <+4>: ldr r0, [pc, #32] @ (0x100001e8) 0x100001c6 <+6>: ldr r1, [pc, #36] @ (0x100001ec) 0x100001c8 <+8>: movs r2, #0 0x100001ca <+10>: cmp r1, r0 0x100001cc <+12>: beq.n 0x100001d2 <Reset+18> 0x100001ce <+14>: stmia r0!, {r2} 0x100001d0 <+16>: b.n 0x100001ca <Reset+10> 0x100001d2 <+18>: ldr r0, [pc, #28] @ (0x100001f0) 0x100001d4 <+20>: ldr r1, [pc, #28] @ (0x100001f4) 0x100001d6 <+22>: ldr r2, [pc, #32] @ (0x100001f8) 0x100001d8 <+24>: cmp r1, r0 0x100001da <+26>: beq.n 0x100001e2 <Reset+34> 0x100001dc <+28>: ldmia r2!, {r3} 0x100001de <+30>: stmia r0!, {r3} 0x100001e0 <+32>: b.n 0x100001d8 <Reset+24> 0x100001e2 <+34>: bl 0x1000066c <main> 0x100001e6 <+38>: udf #0

2. main Trampoline (@ 0x1000066c)

0x1000066c <+0>: push {r7, lr} 0x1000066e <+2>: add r7, sp, #0 0x10000670 <+4>: bl 0x10000674 <_ZN25rust_embassy_pico_project18__cortex_m_rt_main17h…>

3. __cortex_m_rt_main (@ 0x10000674)

0x10000674 <+0>: push {r7, lr} 0x10000676 <+2>: add r7, sp, #0 0x10000678 <+4>: sub sp, #16 0x1000067a <+6>: bl 0x10009a20 <_ZN16embassy_executor4arch6thread8Executor3new17h…> 0x1000067e <+10>: str r0, [sp, #4] 0x10000680 <+12>: str r1, [sp, #8] 0x10000682 <+14>: add r0, sp, #4 0x10000684 <+16>: bl 0x10000e24 <_ZN25rust_embassy_pico_project18__cortex_m_rt_main13__make_static17h…> 0x10000688 <+20>: str r0, [sp, #12] 0x1000068a <+22>: bl 0x1000163c <_ZN16embassy_executor4arch6thread8Executor3run17h…>

4. Executor::newraw::Executor::newSyncExecutor::new

  • Executor::new (arch::cortex_m.rs:77): calls raw::Executor::new(THREAD_PENDER)
  • raw::Executor::new (mod.rs:495): creates SyncExecutor::new
  • SyncExecutor::new (mod.rs:383): run_queue: RunQueue::new()
  • RunQueue::new (run_queue_critical_section.rs:35): head: Mutex::new(Cell::new(None)), etc.

5. Executor::run (@ 0x1000163c)

0x1000163c <+0>: push {r7, lr} 0x1000163e <+2>: add r7, sp, #0 0x10001640 <+4>: sub sp, #16 0x10001642 <+6>: str r0, [sp, #4] 0x10001644 <+8>: str r0, [sp, #8] 0x10001646 <+10>: bl 0x10009dba <raw::Executor::spawner> 0x1000164a <+14>: bl 0x10000e30 <__cortex_m_rt_main::{closure}> 0x10001650 <+20>: ldr r0, [sp, #4] 0x10001652 <+22>: bl 0x10009daa <raw::Executor::poll> 0x10001656 <+26>: wfe 0x10001658 <+28>: b.n 0x10001650

6. run_cycle Future Constructor (@ 0x10001904)

0x10001904 <+0>: push {r7, lr} 0x10001906 <+2>: add r7, sp, #0 0x10001908 <+4>: sub sp, #12 0x1000190a <+6>: str r1, [sp, #0] # button ptr 0x1000190c <+8>: mov r1, r0 0x1000190e <+10>: ldr r0, [sp, #0] # button 0x10001910 <+12>: str r0, [sp, #4] # store in struct 0x10001912 <+14>: str r2, [sp, #8] # store led ptr 0x10001914 <+16>: str r0, [r1, #0] 0x10001916 <+18>: str r2, [r1, #4] 0x10001918 <+20>: movs r0, #0 # initial state=0 0x1000191a <+22>: strb r0, [r1, #16] # .state=0 0x1000191c <+24>: add sp, #12 0x1000191e <+26>: pop {r7, pc}

7. run_cycle Poll State Machine (@ 0x100006a0)

0x100006a0 <+0>: push {r4, r6, r7, lr} 0x100006a2 <+2>: add r7, sp, #8 0x100006a4 <+4>: sub sp, #192 @ 0xc0 0x100006a6 <+6>: str r1, [sp, #20] 0x100006a8 <+8>: str r0, [sp, #28] 0x100006aa <+10>: str r1, [sp, #136] @ 0x88 0x100006ac <+12>: ldr r0, [sp, #28] 0x100006ae <+14>: ldrb r0, [r0, #16] 0x100006b0 <+16>: str r0, [sp, #24] 0x100006b2 <+18>: ldr r0, [sp, #24] 0x100006b4 <+20>: lsls r1, r0, #2 0x100006b6 <+22>: add r0, pc, #4 @ (adr r0, 0x100006bc <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+28>) 0x100006b8 <+24>: ldr r0, [r0, r1] 0x100006ba <+26>: mov pc, r0 0x100006bc <+28>: lsls r3, r3, #27 0x100006be <+30>: asrs r0, r0, #32 0x100006c0 <+32>: lsls r1, r7, #27 0x100006c2 <+34>: asrs r0, r0, #32 0x100006c4 <+36>: lsls r1, r3, #27 0x100006c6 <+38>: asrs r0, r0, #32 0x100006c8 <+40>: lsls r1, r0, #28 0x100006ca <+42>: asrs r0, r0, #32 0x100006cc <+44>: lsls r7, r0, #28 0x100006ce <+46>: asrs r0, r0, #32 0x100006d0 <+48>: lsls r5, r1, #28 0x100006d2 <+50>: asrs r0, r0, #32 0x100006d4 <+52>: lsls r3, r2, #28 0x100006d6 <+54>: asrs r0, r0, #32 0x100006d8 <+56>: udf #254 @ 0xfe 0x100006da <+58>: ldr r0, [sp, #20] 0x100006dc <+60>: str r0, [sp, #132] @ 0x84 0x100006de <+62>: ldr r1, [sp, #28] 0x100006e0 <+64>: ldr r0, [r1, #0] 0x100006e2 <+66>: str r0, [r1, #8] 0x100006e4 <+68>: ldr r1, [sp, #28] 0x100006e6 <+70>: ldr r0, [r1, #4] 0x100006e8 <+72>: str r0, [r1, #12] 0x100006ea <+74>: ldr r0, [sp, #28] 0x100006ec <+76>: ldr r0, [r0, #12] 0x100006ee <+78>: bl 0x100005d6 <_ZN10embassy_rp4gpio5Input6is_low17h279e6840f083881cE> 0x100006f2 <+82>: cmp r0, #0 0x100006f4 <+84>: bne.n 0x10000740 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+160> 0x100006f6 <+86>: b.n 0x10000718 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+120> 0x100006f8 <+88>: movs r0, #0 0x100006fa <+90>: cmp r0, #0 0x100006fc <+92>: bne.n 0x100006f8 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+88> 0x100006fe <+94>: b.n 0x1000077a <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+218> 0x10000700 <+96>: ldr r0, [sp, #20] 0x10000702 <+98>: str r0, [sp, #132] @ 0x84 0x10000704 <+100>: b.n 0x10000768 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+200> 0x10000706 <+102>: ldr r0, [sp, #20] 0x10000708 <+104>: str r0, [sp, #132] @ 0x84 0x1000070a <+106>: b.n 0x1000079c <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+252> 0x1000070c <+108>: ldr r0, [sp, #20] 0x1000070e <+110>: str r0, [sp, #132] @ 0x84 0x10000710 <+112>: b.n 0x100007f8 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+344> 0x10000712 <+114>: ldr r0, [sp, #20] 0x10000714 <+116>: str r0, [sp, #132] @ 0x84 0x10000716 <+118>: b.n 0x1000085c <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+444> 0x10000718 <+120>: ldr r0, [sp, #28] 0x1000071a <+122>: ldr r1, [r0, #12] 0x1000071c <+124>: add r0, sp, #84 @ 0x54 0x1000071e <+126>: str r0, [sp, #16] 0x10000720 <+128>: bl 0x100005a6 <_ZN10embassy_rp4gpio5Input12wait_for_low17h2cb7b01158f39cecE> 0x10000724 <+132>: ldr r1, [sp, #16] 0x10000726 <+134>: add r0, sp, #68 @ 0x44 0x10000728 <+136>: bl 0x10001378 <_ZN59_$LT$F$u20$as$u20$core..future..into_future..IntoFuture$GT$11into_future17h2ba7c62ecd8f03eaE> 0x1000072c <+140>: ldr r1, [sp, #28] 0x1000072e <+142>: ldr r0, [sp, #80] @ 0x50 0x10000730 <+144>: str r0, [r1, #32] 0x10000732 <+146>: ldr r0, [sp, #76] @ 0x4c 0x10000734 <+148>: str r0, [r1, #28] 0x10000736 <+150>: ldr r0, [sp, #72] @ 0x48 0x10000738 <+152>: str r0, [r1, #24] 0x1000073a <+154>: ldr r0, [sp, #68] @ 0x44 0x1000073c <+156>: str r0, [r1, #20] 0x1000073e <+158>: b.n 0x1000079c <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+252> 0x10000740 <+160>: ldr r0, [sp, #28] 0x10000742 <+162>: ldr r1, [r0, #12] 0x10000744 <+164>: add r0, sp, #52 @ 0x34 0x10000746 <+166>: str r0, [sp, #12] 0x10000748 <+168>: bl 0x100005be <_ZN10embassy_rp4gpio5Input13wait_for_high17h9118f9d341070139E> 0x1000074c <+172>: ldr r1, [sp, #12] 0x1000074e <+174>: add r0, sp, #36 @ 0x24 0x10000750 <+176>: bl 0x100013d6 <_ZN59_$LT$F$u20$as$u20$core..future..into_future..IntoFuture$GT$11into_future17hf8591a67ae3e02adE> 0x10000754 <+180>: ldr r1, [sp, #28] 0x10000756 <+182>: ldr r0, [sp, #48] @ 0x30 0x10000758 <+184>: str r0, [r1, #32] 0x1000075a <+186>: ldr r0, [sp, #44] @ 0x2c 0x1000075c <+188>: str r0, [r1, #28] 0x1000075e <+190>: ldr r0, [sp, #40] @ 0x28 0x10000760 <+192>: str r0, [r1, #24] 0x10000762 <+194>: ldr r0, [sp, #36] @ 0x24 0x10000764 <+196>: str r0, [r1, #20] 0x10000766 <+198>: b.n 0x10000768 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+200> 0x10000768 <+200>: ldr r0, [sp, #28] 0x1000076a <+202>: adds r0, #20 0x1000076c <+204>: str r0, [sp, #188] @ 0xbc 0x1000076e <+206>: ldr r1, [sp, #132] @ 0x84 0x10000770 <+208>: bl 0x10001274 <_ZN10embassy_rp4gpio5Input13wait_for_high28_$u7b$$u7b$closure$u7d$$u7d$17h76cb204e6020303dE> 0x10000774 <+212>: cmp r0, #0 0x10000776 <+214>: bne.n 0x10000780 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+224> 0x10000778 <+216>: b.n 0x10000792 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+242> 0x1000077a <+218>: ldr r0, [pc, #280] @ (0x10000894 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+500>) 0x1000077c <+220>: bl 0x1000b38c <_ZN4core9panicking11panic_const28panic_const_async_fn_resumed17h823dff9daf7f5c44E> 0x10000780 <+224>: add r0, sp, #32 0x10000782 <+226>: movs r1, #1 0x10000784 <+228>: strb r1, [r0, #0] 0x10000786 <+230>: ldr r2, [sp, #28] 0x10000788 <+232>: movs r1, #3 0x1000078a <+234>: strb r1, [r2, #16] 0x1000078c <+236>: ldrb r0, [r0, #0] 0x1000078e <+238>: add sp, #192 @ 0xc0 0x10000790 <+240>: pop {r4, r6, r7, pc} 0x10000792 <+242>: ldr r0, [sp, #28] 0x10000794 <+244>: adds r0, #20 0x10000796 <+246>: bl 0x10001ae8 <_ZN4core3ptr88drop_in_place$LT$embassy_rp..gpio..Input..wait_for_high..$u7b$$u7b$closure$u7d$$u7d$$GT$17h412df48bae41fb14E> 0x1000079a <+250>: b.n 0x10000718 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+120> 0x1000079c <+252>: ldr r0, [sp, #28] 0x1000079e <+254>: adds r0, #20 0x100007a0 <+256>: str r0, [sp, #176] @ 0xb0 0x100007a2 <+258>: ldr r1, [sp, #132] @ 0x84 0x100007a4 <+260>: bl 0x100011d4 <_ZN10embassy_rp4gpio5Input12wait_for_low28_$u7b$$u7b$closure$u7d$$u7d$17hde464f8f1fd28345E> 0x100007a8 <+264>: cmp r0, #0 0x100007aa <+266>: beq.n 0x100007c0 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+288> 0x100007ac <+268>: b.n 0x100007ae <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+270> 0x100007ae <+270>: add r0, sp, #32 0x100007b0 <+272>: movs r1, #1 0x100007b2 <+274>: strb r1, [r0, #0] 0x100007b4 <+276>: ldr r2, [sp, #28] 0x100007b6 <+278>: movs r1, #4 0x100007b8 <+280>: strb r1, [r2, #16] 0x100007ba <+282>: ldrb r0, [r0, #0] 0x100007bc <+284>: add sp, #192 @ 0xc0 0x100007be <+286>: pop {r4, r6, r7, pc} 0x100007c0 <+288>: ldr r0, [sp, #28] 0x100007c2 <+290>: adds r0, #20 0x100007c4 <+292>: bl 0x10001ab8 <_ZN4core3ptr87drop_in_place$LT$embassy_rp..gpio..Input..wait_for_low..$u7b$$u7b$closure$u7d$$u7d$$GT$17h649af93cb28f11c1E> 0x100007c8 <+296>: ldr r0, [sp, #28] 0x100007ca <+298>: ldr r0, [r0, #8] 0x100007cc <+300>: bl 0x1000020a <_ZN25rust_embassy_pico_project3led3Led2on17h75f7deaba411d497E> 0x100007d0 <+304>: ldr r0, [sp, #28] 0x100007d2 <+306>: ldr r1, [r0, #12] 0x100007d4 <+308>: add r0, sp, #116 @ 0x74 0x100007d6 <+310>: str r0, [sp, #8] 0x100007d8 <+312>: bl 0x100005be <_ZN10embassy_rp4gpio5Input13wait_for_high17h9118f9d341070139E> 0x100007dc <+316>: ldr r1, [sp, #8] 0x100007de <+318>: add r0, sp, #100 @ 0x64 0x100007e0 <+320>: bl 0x100013d6 <_ZN59_$LT$F$u20$as$u20$core..future..into_future..IntoFuture$GT$11into_future17hf8591a67ae3e02adE> 0x100007e4 <+324>: ldr r1, [sp, #28] 0x100007e6 <+326>: ldr r0, [sp, #112] @ 0x70 0x100007e8 <+328>: str r0, [r1, #32] 0x100007ea <+330>: ldr r0, [sp, #108] @ 0x6c 0x100007ec <+332>: str r0, [r1, #28] 0x100007ee <+334>: ldr r0, [sp, #104] @ 0x68 0x100007f0 <+336>: str r0, [r1, #24] 0x100007f2 <+338>: ldr r0, [sp, #100] @ 0x64 0x100007f4 <+340>: str r0, [r1, #20] 0x100007f6 <+342>: b.n 0x100007f8 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+344> 0x100007f8 <+344>: ldr r0, [sp, #28] 0x100007fa <+346>: adds r0, #20 0x100007fc <+348>: str r0, [sp, #184] @ 0xb8 0x100007fe <+350>: ldr r1, [sp, #132] @ 0x84 0x10000800 <+352>: bl 0x10001274 <_ZN10embassy_rp4gpio5Input13wait_for_high28_$u7b$$u7b$closure$u7d$$u7d$17h76cb204e6020303dE> 0x10000804 <+356>: cmp r0, #0 0x10000806 <+358>: beq.n 0x1000081c <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+380> 0x10000808 <+360>: b.n 0x1000080a <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+362> 0x1000080a <+362>: add r0, sp, #32 0x1000080c <+364>: movs r1, #1 0x1000080e <+366>: strb r1, [r0, #0] 0x10000810 <+368>: ldr r2, [sp, #28] 0x10000812 <+370>: movs r1, #5 0x10000814 <+372>: strb r1, [r2, #16] 0x10000816 <+374>: ldrb r0, [r0, #0] 0x10000818 <+376>: add sp, #192 @ 0xc0 0x1000081a <+378>: pop {r4, r6, r7, pc} 0x1000081c <+380>: ldr r0, [sp, #28] 0x1000081e <+382>: adds r0, #20 0x10000820 <+384>: bl 0x10001ae8 <_ZN4core3ptr88drop_in_place$LT$embassy_rp..gpio..Input..wait_for_high..$u7b$$u7b$closure$u7d$$u7d$$GT$17h412df48bae41fb14E> 0x10000824 <+388>: ldr r0, [sp, #28] 0x10000826 <+390>: ldr r0, [r0, #8] 0x10000828 <+392>: bl 0x1000021a <_ZN25rust_embassy_pico_project3led3Led3off17h3284da408f5fdb1cE> 0x1000082c <+396>: add r0, sp, #144 @ 0x90 0x1000082e <+398>: str r0, [sp, #4] 0x10000830 <+400>: movs r2, #10 0x10000832 <+402>: movs r3, #0 0x10000834 <+404>: bl 0x100018de <_ZN12embassy_time5timer5Timer12after_millis17h2c899eceea774000E> 0x10000838 <+408>: ldr r0, [sp, #4] 0x1000083a <+410>: ldr r3, [sp, #148] @ 0x94 0x1000083c <+412>: ldr r2, [sp, #144] @ 0x90 0x1000083e <+414>: ldrb r0, [r0, #8] 0x10000840 <+416>: str r0, [sp, #0] 0x10000842 <+418>: add r0, sp, #160 @ 0xa0 0x10000844 <+420>: bl 0x10000266 <_ZN59_$LT$F$u20$as$u20$core..future..into_future..IntoFuture$GT$11into_future17h2f5362e0faebbbd9E> 0x10000848 <+424>: ldr r2, [sp, #160] @ 0xa0 0x1000084a <+426>: ldr r4, [sp, #164] @ 0xa4 0x1000084c <+428>: ldr r0, [sp, #168] @ 0xa8 0x1000084e <+430>: ldr r3, [sp, #28] 0x10000850 <+432>: mov r1, r3 0x10000852 <+434>: adds r1, #24 0x10000854 <+436>: str r4, [r3, #28] 0x10000856 <+438>: str r2, [r3, #24] 0x10000858 <+440>: strb r0, [r1, #8] 0x1000085a <+442>: b.n 0x1000085c <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+444> 0x1000085c <+444>: ldr r0, [sp, #28] 0x1000085e <+446>: adds r0, #24 0x10000860 <+448>: str r0, [sp, #180] @ 0xb4 0x10000862 <+450>: ldr r1, [sp, #132] @ 0x84 0x10000864 <+452>: bl 0x10008ec0 <_ZN75_$LT$embassy_time..timer..Timer$u20$as$u20$core..future..future..Future$GT$4poll17hdbee4e72f640d006E> 0x10000868 <+456>: cmp r0, #0 0x1000086a <+458>: beq.n 0x10000880 <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+480> 0x1000086c <+460>: b.n 0x1000086e <_ZN25rust_embassy_pico_project9run_cycle9run_cycle28_$u7b$$u7b$closure$u7d$$u7d$17h1e5426774f161f69E+462> 0x1000086e <+462>: add r0, sp, #32 0x10000870 <+464>: movs r1, #1 0x10000872 <+466>: strb r1, [r0, #0] 0x10000874 <+468>: ldr r2, [sp, #28] 0x10000876 <+470>: movs r1, #6 0x10000878 <+472>: strb r1, [r2, #16] 0x1000087a <+474>: ldrb r0, [r0, #0] 0x1000087c <+476>: add sp, #192 @ 0xc0 0x1000087e <+478>: pop {r4, r6, r7, pc} 0x10000880 <+480>: add r0, sp, #32 0x10000882 <+482>: movs r1, #0 0x10000884 <+484>: strb r1, [r0, #0] 0x10000886 <+486>: ldr r2, [sp, #28] 0x10000888 <+488>: movs r1, #1 0x1000088a <+490>: strb r1, [r2, #16] 0x1000088c <+492>: ldrb r0, [r0, #0] 0x1000088e <+494>: add sp, #192 @ 0xc0 0x10000890 <+496>: pop {r4, r6, r7, pc} 0x10000892 <+498>: nop @ (mov r8, r8) 0x10000894 <+500>: stmia r0!, {r4} 0x10000896 <+502>: asrs r0, r0, #32

Each bne or b.n jump corresponds to one of the await suspension points:

  • state = 0 → evaluate button.is_low() and possibly await wait_for_high()
  • state = 1 → resumed after wait_for_high().await
  • state = 2 → await wait_for_low().await
  • state = 3 → execute led.on()
  • state = 4 → await wait_for_high().await
  • state = 5 → execute led.off()
  • state = 6 → await Timer::after_millis().await
  • state = DONE → return Poll::Ready and exit

By placing a breakpoint at the closure entry (0x100006a0), you dive directly into your button-press/LED logic, skipping the trivial constructor at 0x10001904.


Building and Flashing

Make sure you have:

  • Rust toolchain with thumbv6m-none-eabi target installed.
  • Probe-rs or OpenOCD for flashing.

Build:

cargo build

Flash:

cargo flash


Requirements

  • Rust nightly (for async embedded features).
  • Embassy (embassy-rp crate) for async HAL support.
  • A Raspberry Pi Pico board.

License

Apache-2.0 License


References

About

A simple embedded Rust project running on the Raspberry Pi Pico (RP2040), built with Embassy async framework and no_std runtime.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published