description: Asynchronous Programming with Embassy
slug: /lab/04
04 - Asynchronous Development
This lab will teach you the principles of asynchronous programming, and its application in Embassy.
Resources
- Bert Peters, How does async Rust work
- Omar Hiari, Sharing Data Among Tasks in Rust Embassy: Synchronization Primitives
Asynchronous functions and Tasks
Until now you've only worked with simple (almost) serial programs. However, not all programs can be designed to run serially/sequentially. Handling multiple I/O events concurrently usually requires separate parallel tasks. Example: Reading a button press while blinking an LED. A single loop would block the button reading event while waiting for the timer to finish.
sequenceDiagram
participant Button as Button
participant Timer as Timer
participant Task as Main Task (LED + Button)
participant LED as LED Control
loop
%% LED starts blinking
Task->>LED: Turn LED ON
Timer->>+Task: Delay 1 sec (Blocks everything)
%% Button presses button during delay
Button-->>Task: Button Press Sent (but microcontroller is busy)
Task->>-Task: Continue with next instruction
%% LED continues
Task->>LED: Turn LED OFF
Timer->>+Task: Delay 1 sec (Blocks everything)
Button-->>Task:Button Press Sent (but microcontroller is busy)
Task->>-Task: Continue with next instruction
%% Now the task checks the button, but it's too late
Task->>Button: Check if button is pressed
Button-->>Task: No press detected (press was missed)
end
Note over Button, Button: User pressed button, but MCU was busy!
Note over Task: Button check happens too late.
To address this issue, we would need to spawn a new task in which we would wait for the button press, while blinking the LED in the main
function.
When thinking of how exactly this works, you would probably think that the task is running on a separate thread than the main
function. Usually this would be the case when developing a normal computer application. Multithreading is possible, but requires a preemptive operating system. Without one, only one thread can independently run per processor core and that means that, since we are using only one core of the RP2350 (which actually has only 2), we would only be able to run one thread at a time. So how exactly does the task wait for the button press in parallel with the LED blinking?
Short answer is: it doesn't. In reality, both functions run asynchronously.