aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/rp/src/bin/zerocopy.rs94
1 files changed, 94 insertions, 0 deletions
diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
new file mode 100644
index 000000000..39f03c8e4
--- /dev/null
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -0,0 +1,94 @@
1//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
2//! sending large values between two tasks without copying.
3//! The example also shows how to use the RP2040 ADC with DMA.
4#![no_std]
5#![no_main]
6
7use core::sync::atomic::{AtomicU16, Ordering};
8
9use defmt::*;
10use embassy_executor::Spawner;
11use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
12use embassy_rp::bind_interrupts;
13use embassy_rp::gpio::Pull;
14use embassy_rp::peripherals::DMA_CH0;
15use embassy_sync::blocking_mutex::raw::NoopRawMutex;
16use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
17use embassy_time::{Duration, Ticker, Timer};
18use static_cell::StaticCell;
19use {defmt_rtt as _, panic_probe as _};
20
21type SampleBuffer = [u16; 512];
22
23bind_interrupts!(struct Irqs {
24 ADC_IRQ_FIFO => InterruptHandler;
25});
26
27const BLOCK_SIZE: usize = 512;
28const NUM_BLOCKS: usize = 2;
29static MAX: AtomicU16 = AtomicU16::new(0);
30
31struct AdcParts {
32 adc: Adc<'static, Async>,
33 pin: adc::Channel<'static>,
34 dma: DMA_CH0,
35}
36
37#[embassy_executor::main]
38async fn main(spawner: Spawner) {
39 let p = embassy_rp::init(Default::default());
40 info!("Here we go!");
41
42 let adc_parts = AdcParts {
43 adc: Adc::new(p.ADC, Irqs, Config::default()),
44 pin: adc::Channel::new_pin(p.PIN_29, Pull::None),
45 dma: p.DMA_CH0,
46 };
47
48 static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new();
49 let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]);
50
51 static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new();
52 let channel = CHANNEL.init(Channel::new(buf));
53 let (sender, receiver) = channel.split();
54
55 spawner.must_spawn(consumer(receiver));
56 spawner.must_spawn(producer(sender, adc_parts));
57
58 let mut ticker = Ticker::every(Duration::from_secs(1));
59 loop {
60 ticker.next().await;
61 let max = MAX.load(Ordering::Relaxed);
62 info!("latest block's max value: {:?}", max);
63 }
64}
65
66#[embassy_executor::task]
67async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) {
68 loop {
69 // Obtain a free buffer from the channel
70 let buf = sender.send().await;
71
72 // Fill it with data
73 adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap();
74
75 // Notify the channel that the buffer is now ready to be received
76 sender.send_done();
77 }
78}
79
80#[embassy_executor::task]
81async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) {
82 loop {
83 // Receive a buffer from the channel
84 let buf = receiver.receive().await;
85
86 // Simulate using the data, while the producer is filling up the next buffer
87 Timer::after_micros(1000).await;
88 let max = buf.iter().max().unwrap();
89 MAX.store(*max, Ordering::Relaxed);
90
91 // Notify the channel that the buffer is now ready to be reused
92 receiver.receive_done();
93 }
94}