Skip to content
Snippets Groups Projects
Forked from PMRust / website
18 commits behind the upstream repository.
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
index.md 21.53 KiB
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

  1. Bert Peters, How does async Rust work
  2. 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.