diff options
| author | Ulf Lilleengen <[email protected]> | 2024-06-04 06:37:45 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2024-06-04 06:37:45 +0000 |
| commit | 5f9bc6def7ea8698a6ce45d8e12e1d1bd8cce876 (patch) | |
| tree | 428f0d698d58dd569f9b3fb8b1ee47c2ca9a70a1 | |
| parent | 9856d216939d9433e840289966e313c9aa377fca (diff) | |
| parent | f9d8c68fc8ed490e72e61b74d2b3b26bbbd0434c (diff) | |
Merge pull request #3037 from kalkyl/zerocopy
rp: Add zerocopy channel example
| -rw-r--r-- | examples/rp/src/bin/zerocopy.rs | 94 |
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 | |||
| 7 | use core::sync::atomic::{AtomicU16, Ordering}; | ||
| 8 | |||
| 9 | use defmt::*; | ||
| 10 | use embassy_executor::Spawner; | ||
| 11 | use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler}; | ||
| 12 | use embassy_rp::bind_interrupts; | ||
| 13 | use embassy_rp::gpio::Pull; | ||
| 14 | use embassy_rp::peripherals::DMA_CH0; | ||
| 15 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 16 | use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender}; | ||
| 17 | use embassy_time::{Duration, Ticker, Timer}; | ||
| 18 | use static_cell::StaticCell; | ||
| 19 | use {defmt_rtt as _, panic_probe as _}; | ||
| 20 | |||
| 21 | type SampleBuffer = [u16; 512]; | ||
| 22 | |||
| 23 | bind_interrupts!(struct Irqs { | ||
| 24 | ADC_IRQ_FIFO => InterruptHandler; | ||
| 25 | }); | ||
| 26 | |||
| 27 | const BLOCK_SIZE: usize = 512; | ||
| 28 | const NUM_BLOCKS: usize = 2; | ||
| 29 | static MAX: AtomicU16 = AtomicU16::new(0); | ||
| 30 | |||
| 31 | struct AdcParts { | ||
| 32 | adc: Adc<'static, Async>, | ||
| 33 | pin: adc::Channel<'static>, | ||
| 34 | dma: DMA_CH0, | ||
| 35 | } | ||
| 36 | |||
| 37 | #[embassy_executor::main] | ||
| 38 | async 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] | ||
| 67 | async 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] | ||
| 81 | async 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 | } | ||
