user: I have an embedded application written in Rust (so using #![no_std]). I am using the embassy (https://embassy.dev/) as my async runtime. In my program I have two tasks: one data acquisition task, and a data processing task. I want the data gathered in the acquisition task to find its way inside the data processing task. Ideally, I want to only react on new data, as shown in the example below. What are some idiomatic ways to do so?
Here's a rough idea of how my code looks like:
```rust
#[embassy_executor::task]
async fn data_acquisition(mut used_peripherals: UsedPeripherals) {
    let data = sample_data(&mut used_peripherals).await;
    // Now I want to access the data in another task.
}

#[embassy_executor::task]
async fn data_processing() {
    // Somehow wait for new data.
    // Do stuff with the received data.
}
```

assistant: One way to accomplish this is to use a channel to pass data between the two tasks. Here's an example of how you could modify your code to use a channel:
```rust
use embassy::channel::{mpmc, Receiver};
use embassy_executor::task;

#[task]
async fn data_acquisition(mut used_peripherals: UsedPeripherals, tx: mpmc::Sender<Data>) {
    loop {
        let data = sample_data(&mut used_peripherals).await;
        if tx.try_send(data).is_err() {
            // Handle the case where the channel is full
            // (i.e. the data processing task isn't keeping up).
        }
    }
}

#[task]
async fn data_processing(mut rx: Receiver<Data>) {
    while let Some(data) = rx.recv().await {
        // Do stuff with the received data.
    }
}
```

In this example, mpmc::Sender and Receiver are used to create a multi-producer, multi-consumer channel that can be used to pass data between tasks. The data_acquisition task sends data over the channel using try_send, which returns an error if the channel is full. The data_processing task receives data from the channel using recv, which blocks until new data is available.

Note that the try_send method is used instead of send because send would block if the channel is full, which could cause the data acquisition task to miss new data from the peripherals. Also, the while let Some(data) = rx.recv().await loop is used to continuously process new data as it becomes available.

user: Could you rewrite this response and make sure all code is put into code blocks. Your response was difficult to read.

assistant: Sure!

```rust
use embassy::channel::{mpmc, Receiver};
use embassy_executor::task;

#[task]
async fn data_acquisition(mut used_peripherals: UsedPeripherals, tx: mpmc::Sender<Data>) {
    loop {
        let data = sample_data(&mut used_peripherals).await;
        if tx.try_send(data).is_err() {
            // Handle the case where the channel is full
            // (i.e. the data processing task isn't keeping up).
        }
    }
}

#[task]
async fn data_processing(mut rx: Receiver<Data>) {
    while let Some(data) = rx.recv().await {
        // Do stuff with the received data.
    }
}
```

In this example, `mpmc::Sender` and `Receiver` are used to create a multi-producer, multi-consumer channel that can be used to pass data between tasks. The `data_acquisition` task sends data over the channel using `try_send`, which returns an error if the channel is full. The `data_processing` task receives data from the channel using `recv`, which blocks until new data is available.

Note that the `try_send` method is used instead of `send` because `send` would block if the channel is full, which could cause the data acquisition task to miss new data from the peripherals. Also, the `while let Some(data) = rx.recv().await` loop is used to continuously process new data as it becomes available.