diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-05-22 15:50:41 +0200 |
|---|---|---|
| committer | GitHub <[email protected]> | 2021-05-22 15:50:41 +0200 |
| commit | 62ad8ebab0919f5f7112a42ce4e93886439923e2 (patch) | |
| tree | ca956447830c71790f9aaec13341c59483b1eb5d | |
| parent | 3d520f8abe529cbfbbc4a4b575e15bae297a2dc8 (diff) | |
| parent | 55c3ba2a5fb2ffddca187c0b04ad353433508426 (diff) | |
Merge pull request #198 from lulf/saadc-multiple-pins
Makes it possible to use the ADC with different analog pins
| -rw-r--r-- | embassy-nrf/src/saadc.rs | 107 |
1 files changed, 53 insertions, 54 deletions
diff --git a/embassy-nrf/src/saadc.rs b/embassy-nrf/src/saadc.rs index c1afd00de..edb8aa21f 100644 --- a/embassy-nrf/src/saadc.rs +++ b/embassy-nrf/src/saadc.rs | |||
| @@ -30,9 +30,9 @@ pub use saadc::{ | |||
| 30 | pub enum Error {} | 30 | pub enum Error {} |
| 31 | 31 | ||
| 32 | /// One-shot saadc. Continuous sample mode TODO. | 32 | /// One-shot saadc. Continuous sample mode TODO. |
| 33 | pub struct OneShot<'d, T: PositivePin> { | 33 | pub struct OneShot<'d> { |
| 34 | irq: interrupt::SAADC, | 34 | irq: interrupt::SAADC, |
| 35 | phantom: PhantomData<(&'d mut peripherals::SAADC, &'d mut T)>, | 35 | phantom: PhantomData<&'d mut peripherals::SAADC>, |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | /// Used to configure the SAADC peripheral. | 38 | /// Used to configure the SAADC peripheral. |
| @@ -66,14 +66,13 @@ impl Default for Config { | |||
| 66 | } | 66 | } |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | impl<'d, T: PositivePin> OneShot<'d, T> { | 69 | impl<'d> OneShot<'d> { |
| 70 | pub fn new( | 70 | pub fn new( |
| 71 | _saadc: impl Unborrow<Target = peripherals::SAADC> + 'd, | 71 | _saadc: impl Unborrow<Target = peripherals::SAADC> + 'd, |
| 72 | irq: impl Unborrow<Target = interrupt::SAADC> + 'd, | 72 | irq: impl Unborrow<Target = interrupt::SAADC> + 'd, |
| 73 | positive_pin: impl Unborrow<Target = T> + 'd, | ||
| 74 | config: Config, | 73 | config: Config, |
| 75 | ) -> Self { | 74 | ) -> Self { |
| 76 | unborrow!(irq, positive_pin); | 75 | unborrow!(irq); |
| 77 | 76 | ||
| 78 | let r = unsafe { &*SAADC::ptr() }; | 77 | let r = unsafe { &*SAADC::ptr() }; |
| 79 | 78 | ||
| @@ -106,11 +105,6 @@ impl<'d, T: PositivePin> OneShot<'d, T> { | |||
| 106 | w | 105 | w |
| 107 | }); | 106 | }); |
| 108 | 107 | ||
| 109 | // Set positive channel | ||
| 110 | r.ch[0] | ||
| 111 | .pselp | ||
| 112 | .write(|w| w.pselp().variant(positive_pin.channel())); | ||
| 113 | |||
| 114 | // Disable all events interrupts | 108 | // Disable all events interrupts |
| 115 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); | 109 | r.intenclr.write(|w| unsafe { w.bits(0x003F_FFFF) }); |
| 116 | 110 | ||
| @@ -123,9 +117,52 @@ impl<'d, T: PositivePin> OneShot<'d, T> { | |||
| 123 | fn regs(&self) -> &saadc::RegisterBlock { | 117 | fn regs(&self) -> &saadc::RegisterBlock { |
| 124 | unsafe { &*SAADC::ptr() } | 118 | unsafe { &*SAADC::ptr() } |
| 125 | } | 119 | } |
| 120 | |||
| 121 | async fn sample_inner(&mut self, pin: PositiveChannel) -> i16 { | ||
| 122 | let r = self.regs(); | ||
| 123 | |||
| 124 | // Set positive channel | ||
| 125 | r.ch[0].pselp.write(|w| w.pselp().variant(pin)); | ||
| 126 | |||
| 127 | // Set up the DMA | ||
| 128 | let mut val: i16 = 0; | ||
| 129 | r.result | ||
| 130 | .ptr | ||
| 131 | .write(|w| unsafe { w.ptr().bits(((&mut val) as *mut _) as u32) }); | ||
| 132 | r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits(1) }); | ||
| 133 | |||
| 134 | // Reset and enable the end event | ||
| 135 | r.events_end.reset(); | ||
| 136 | r.intenset.write(|w| w.end().set()); | ||
| 137 | |||
| 138 | // Don't reorder the ADC start event before the previous writes. Hopefully self | ||
| 139 | // wouldn't happen anyway. | ||
| 140 | compiler_fence(Ordering::SeqCst); | ||
| 141 | |||
| 142 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 143 | r.tasks_sample.write(|w| unsafe { w.bits(1) }); | ||
| 144 | |||
| 145 | // Wait for 'end' event. | ||
| 146 | poll_fn(|cx| { | ||
| 147 | let r = self.regs(); | ||
| 148 | |||
| 149 | if r.events_end.read().bits() != 0 { | ||
| 150 | r.events_end.reset(); | ||
| 151 | return Poll::Ready(()); | ||
| 152 | } | ||
| 153 | |||
| 154 | wake_on_interrupt(&mut self.irq, cx.waker()); | ||
| 155 | |||
| 156 | Poll::Pending | ||
| 157 | }) | ||
| 158 | .await; | ||
| 159 | |||
| 160 | // The DMA wrote the sampled value to `val`. | ||
| 161 | val | ||
| 162 | } | ||
| 126 | } | 163 | } |
| 127 | 164 | ||
| 128 | impl<'d, T: PositivePin> Drop for OneShot<'d, T> { | 165 | impl<'d> Drop for OneShot<'d> { |
| 129 | fn drop(&mut self) { | 166 | fn drop(&mut self) { |
| 130 | let r = self.regs(); | 167 | let r = self.regs(); |
| 131 | r.enable.write(|w| w.enable().disabled()); | 168 | r.enable.write(|w| w.enable().disabled()); |
| @@ -137,60 +174,22 @@ pub trait Sample { | |||
| 137 | where | 174 | where |
| 138 | Self: 'a; | 175 | Self: 'a; |
| 139 | 176 | ||
| 140 | fn sample<'a>(&'a mut self) -> Self::SampleFuture<'a>; | 177 | fn sample<'a, T: PositivePin>(&'a mut self, pin: &mut T) -> Self::SampleFuture<'a>; |
| 141 | } | 178 | } |
| 142 | 179 | ||
| 143 | impl<'d, T: PositivePin> Sample for OneShot<'d, T> { | 180 | impl<'d> Sample for OneShot<'d> { |
| 144 | #[rustfmt::skip] | 181 | #[rustfmt::skip] |
| 145 | type SampleFuture<'a> where Self: 'a = impl Future<Output = i16> + 'a; | 182 | type SampleFuture<'a> where Self: 'a = impl Future<Output = i16> + 'a; |
| 146 | 183 | ||
| 147 | fn sample<'a>(&'a mut self) -> Self::SampleFuture<'a> { | 184 | fn sample<'a, T: PositivePin>(&'a mut self, pin: &mut T) -> Self::SampleFuture<'a> { |
| 148 | async move { | 185 | self.sample_inner(pin.channel()) |
| 149 | let r = self.regs(); | ||
| 150 | |||
| 151 | // Set up the DMA | ||
| 152 | let mut val: i16 = 0; | ||
| 153 | r.result | ||
| 154 | .ptr | ||
| 155 | .write(|w| unsafe { w.ptr().bits(((&mut val) as *mut _) as u32) }); | ||
| 156 | r.result.maxcnt.write(|w| unsafe { w.maxcnt().bits(1) }); | ||
| 157 | |||
| 158 | // Reset and enable the end event | ||
| 159 | r.events_end.reset(); | ||
| 160 | r.intenset.write(|w| w.end().set()); | ||
| 161 | |||
| 162 | // Don't reorder the ADC start event before the previous writes. Hopefully self | ||
| 163 | // wouldn't happen anyway. | ||
| 164 | compiler_fence(Ordering::SeqCst); | ||
| 165 | |||
| 166 | r.tasks_start.write(|w| unsafe { w.bits(1) }); | ||
| 167 | r.tasks_sample.write(|w| unsafe { w.bits(1) }); | ||
| 168 | |||
| 169 | // Wait for 'end' event. | ||
| 170 | poll_fn(|cx| { | ||
| 171 | let r = self.regs(); | ||
| 172 | |||
| 173 | if r.events_end.read().bits() != 0 { | ||
| 174 | r.events_end.reset(); | ||
| 175 | return Poll::Ready(()); | ||
| 176 | } | ||
| 177 | |||
| 178 | wake_on_interrupt(&mut self.irq, cx.waker()); | ||
| 179 | |||
| 180 | Poll::Pending | ||
| 181 | }) | ||
| 182 | .await; | ||
| 183 | |||
| 184 | // The DMA wrote the sampled value to `val`. | ||
| 185 | val | ||
| 186 | } | ||
| 187 | } | 186 | } |
| 188 | } | 187 | } |
| 189 | 188 | ||
| 190 | /// A pin that can be used as the positive end of a ADC differential in the SAADC periperhal. | 189 | /// A pin that can be used as the positive end of a ADC differential in the SAADC periperhal. |
| 191 | /// | 190 | /// |
| 192 | /// Currently negative is always shorted to ground (0V). | 191 | /// Currently negative is always shorted to ground (0V). |
| 193 | pub trait PositivePin: Unborrow<Target = Self> { | 192 | pub trait PositivePin { |
| 194 | fn channel(&self) -> PositiveChannel; | 193 | fn channel(&self) -> PositiveChannel; |
| 195 | } | 194 | } |
| 196 | 195 | ||
