From 03d8f99aa57d71c27745972f2bcd9ba3450bd8c3 Mon Sep 17 00:00:00 2001
From: kalkyl <henrik.alser@me.com>
Date: Tue, 4 Jun 2024 00:38:51 +0200
Subject: [PATCH 1/3] rp: Add zerocopy channel example

---
 examples/rp/src/bin/zerocopy.rs | 90 +++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)
 create mode 100644 examples/rp/src/bin/zerocopy.rs

diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
new file mode 100644
index 000000000..b5bd11512
--- /dev/null
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -0,0 +1,90 @@
+#![no_std]
+#![no_main]
+
+use defmt::*;
+use embassy_executor::Spawner;
+use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
+use embassy_rp::bind_interrupts;
+use embassy_rp::gpio::Pull;
+use embassy_rp::peripherals::DMA_CH0;
+use embassy_sync::blocking_mutex::raw::NoopRawMutex;
+use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
+use embassy_time::{Duration, Ticker, Timer};
+use portable_atomic::{AtomicU16, Ordering};
+use static_cell::StaticCell;
+use {defmt_rtt as _, panic_probe as _};
+
+type SampleBuffer = [u16; 512];
+
+bind_interrupts!(struct Irqs {
+    ADC_IRQ_FIFO => InterruptHandler;
+});
+
+const BLOCK_SIZE: usize = 512;
+const NUM_BLOCKS: usize = 2;
+static MAX: AtomicU16 = AtomicU16::new(0);
+
+struct AdcParts {
+    adc: Adc<'static, Async>,
+    pin: adc::Channel<'static>,
+    dma: DMA_CH0,
+}
+
+#[embassy_executor::main]
+async fn main(spawner: Spawner) {
+    let p = embassy_rp::init(Default::default());
+    info!("Here we go!");
+
+    let adc_parts = AdcParts {
+        adc: Adc::new(p.ADC, Irqs, Config::default()),
+        pin: adc::Channel::new_pin(p.PIN_29, Pull::None),
+        dma: p.DMA_CH0,
+    };
+
+    static BUF: StaticCell<[SampleBuffer; NUM_BLOCKS]> = StaticCell::new();
+    let buf = BUF.init([[0; BLOCK_SIZE]; NUM_BLOCKS]);
+
+    static CHANNEL: StaticCell<Channel<'_, NoopRawMutex, SampleBuffer>> = StaticCell::new();
+    let channel = CHANNEL.init(Channel::new(buf));
+    let (sender, receiver) = channel.split();
+
+    spawner.must_spawn(consumer(receiver));
+    spawner.must_spawn(producer(sender, adc_parts));
+
+    let mut ticker = Ticker::every(Duration::from_secs(1));
+    loop {
+        ticker.next().await;
+        let max = MAX.load(Ordering::Relaxed);
+        info!("latest block's max value: {:?}", max);
+    }
+}
+
+#[embassy_executor::task]
+async fn producer(mut sender: Sender<'static, NoopRawMutex, SampleBuffer>, mut adc: AdcParts) {
+    loop {
+        // Obtain a free buffer from the channel
+        let buf = sender.send().await;
+
+        // Fill it with data
+        adc.adc.read_many(&mut adc.pin, buf, 1, &mut adc.dma).await.unwrap();
+
+        // Notify the channel that the buffer is now ready to be received
+        sender.send_done();
+    }
+}
+
+#[embassy_executor::task]
+async fn consumer(mut receiver: Receiver<'static, NoopRawMutex, SampleBuffer>) {
+    loop {
+        // Receive a buffer from the channel
+        let buf = receiver.receive().await;
+
+        // Simulate using the data, while the producer is filling up the next buffer
+        Timer::after_micros(1000).await;
+        let max = buf.iter().max().unwrap();
+        MAX.store(*max, Ordering::Relaxed);
+
+        // Notify the channel that the buffer is now ready to be reused
+        receiver.receive_done();
+    }
+}

From 874d5f7c65f2af21e4666bf92800d304c2d9e01d Mon Sep 17 00:00:00 2001
From: kalkyl <henrik.alser@me.com>
Date: Tue, 4 Jun 2024 00:53:51 +0200
Subject: [PATCH 2/3] core atomic

---
 examples/rp/src/bin/zerocopy.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
index b5bd11512..730a3ae0c 100644
--- a/examples/rp/src/bin/zerocopy.rs
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -1,6 +1,8 @@
 #![no_std]
 #![no_main]
 
+use core::sync::atomic::{AtomicU16, Ordering};
+
 use defmt::*;
 use embassy_executor::Spawner;
 use embassy_rp::adc::{self, Adc, Async, Config, InterruptHandler};
@@ -10,7 +12,6 @@ use embassy_rp::peripherals::DMA_CH0;
 use embassy_sync::blocking_mutex::raw::NoopRawMutex;
 use embassy_sync::zerocopy_channel::{Channel, Receiver, Sender};
 use embassy_time::{Duration, Ticker, Timer};
-use portable_atomic::{AtomicU16, Ordering};
 use static_cell::StaticCell;
 use {defmt_rtt as _, panic_probe as _};
 

From f9d8c68fc8ed490e72e61b74d2b3b26bbbd0434c Mon Sep 17 00:00:00 2001
From: kalkyl <henrik.alser@me.com>
Date: Tue, 4 Jun 2024 01:20:19 +0200
Subject: [PATCH 3/3] Add description

---
 examples/rp/src/bin/zerocopy.rs | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/examples/rp/src/bin/zerocopy.rs b/examples/rp/src/bin/zerocopy.rs
index 730a3ae0c..39f03c8e4 100644
--- a/examples/rp/src/bin/zerocopy.rs
+++ b/examples/rp/src/bin/zerocopy.rs
@@ -1,3 +1,6 @@
+//! This example shows how to use `zerocopy_channel` from `embassy_sync` for
+//! sending large values between two tasks without copying.
+//! The example also shows how to use the RP2040 ADC with DMA.
 #![no_std]
 #![no_main]