A RPi Pico powered Lightning Detector
1use embassy_rp::{
2 Peri,
3 adc::{self, Adc, AdcPin, Async, Config},
4 dma,
5 peripherals::ADC,
6};
7use embassy_sync::{blocking_mutex::raw::RawMutex, mutex::Mutex};
8
9use crate::Irqs;
10
11struct AdcInner<'device, T: dma::Channel> {
12 adc: Adc<'device, Async>,
13 pin: adc::Channel<'device>,
14 dma: Peri<'device, T>,
15}
16
17pub struct AdcDriver<'device, M: RawMutex, T: dma::Channel> {
18 inner: Mutex<M, AdcInner<'device, T>>,
19}
20
21impl<T: dma::Channel> AdcInner<'_, T> {
22 /// Samples at 100Khz, or 10us per sample. If a sampling fails due to conversion error,
23 /// it tries again until the sampling succeeds.
24 async fn read_many(&mut self, buf: &mut [u16]) {
25 while self
26 .adc
27 .read_many(&mut self.pin, buf, 480, self.dma.reborrow())
28 .await
29 .is_err()
30 {}
31 }
32}
33
34impl<'device, M: RawMutex, T: dma::Channel> AdcDriver<'device, M, T> {
35 pub fn new(
36 inner: Peri<'device, ADC>,
37 pin: Peri<'device, impl AdcPin + 'device>,
38 dma: Peri<'device, T>,
39 ) -> Self {
40 Self {
41 inner: Mutex::new(AdcInner {
42 adc: Adc::new(inner, Irqs, Config::default()),
43 pin: adc::Channel::new_pin(pin, embassy_rp::gpio::Pull::None),
44 dma,
45 }),
46 }
47 }
48
49 /// Samples at 100Khz, or 10us per sample. If a sampling fails due to conversion error,
50 /// it tries again until the sampling succeeds.
51 pub async fn sample(&self, buf: &mut [u16]) {
52 // Gain a lock to the inner ADC state, then do a read.
53 self.inner.lock().await.read_many(buf).await;
54 }
55
56 pub async fn sample_average(&self, buf: &mut [u16]) -> u16 {
57 self.sample(buf).await;
58
59 let len = buf.len() as u32;
60
61 (buf.iter().copied().map(u32::from).sum::<u32>() / len) as u16
62 }
63}