nrf52_hal_common/
saadc.rs1use crate::{
2 gpio::{Floating, Input},
3 target::{saadc, SAADC},
4};
5use core::{
6 hint::unreachable_unchecked,
7 ops::Deref,
8 sync::atomic::{compiler_fence, Ordering::SeqCst},
9};
10use embedded_hal::adc::{Channel, OneShot};
11
12pub use crate::target::saadc::{
13 ch::config::{GAINW as Gain, REFSELW as Reference, RESPW as Resistor, TACQW as Time},
14 oversample::OVERSAMPLEW as Oversample,
15 resolution::VALW as Resolution,
16};
17
18pub trait SaadcExt: Deref<Target = saadc::RegisterBlock> + Sized {
23 fn constrain(self) -> Saadc;
24}
25
26impl SaadcExt for SAADC {
27 fn constrain(self) -> Saadc {
28 Saadc::new(self, SaadcConfig::default())
29 }
30}
31
32pub struct Saadc(SAADC);
33
34impl Saadc {
35 pub fn new(saadc: SAADC, config: SaadcConfig) -> Self {
36 let SaadcConfig {
39 resolution,
40 oversample,
41 reference,
42 gain,
43 resistor,
44 time
45 } = config;
46
47 saadc.enable.write(|w| w.enable().enabled());
48 saadc
49 .resolution
50 .write(|w| w.val().variant(resolution));
51 saadc
52 .oversample
53 .write(|w| w.oversample().variant(oversample));
54 saadc.samplerate.write(|w| w.mode().task());
55
56 saadc.ch[0].config.write(|w| {
57 w.refsel()
58 .variant(reference)
59 .gain()
60 .variant(gain)
61 .tacq()
62 .variant(time)
63 .mode()
64 .se()
65 .resp()
66 .variant(resistor)
67 .resn()
68 .bypass()
69 .burst()
70 .enabled()
71 });
72 saadc.ch[0].pseln.write(|w| w.pseln().nc());
73
74 saadc.tasks_calibrateoffset.write(|w| unsafe { w.bits(1) });
76 while saadc.events_calibratedone.read().bits() == 0 {}
77
78 Saadc(saadc)
79 }
80}
81
82pub struct SaadcConfig {
83 resolution: Resolution,
84 oversample: Oversample,
85 reference: Reference,
86 gain: Gain,
87 resistor: Resistor,
88 time: Time,
89}
90
91impl Default for SaadcConfig {
93 fn default() -> Self {
94 SaadcConfig {
95 resolution: Resolution::_14BIT,
96 oversample: Oversample::OVER8X,
97 reference: Reference::VDD1_4,
98 gain: Gain::GAIN1_4,
99 resistor: Resistor::BYPASS,
100 time: Time::_20US,
101 }
102 }
103}
104
105impl<PIN> OneShot<Saadc, u16, PIN> for Saadc
106where
107 PIN: Channel<Saadc, ID = u8>,
108{
109 type Error = ();
110 fn read(&mut self, _pin: &mut PIN) -> nb::Result<u16, Self::Error> {
111 match PIN::channel() {
112 0 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input0()),
113 1 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input1()),
114 2 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input2()),
115 3 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input3()),
116 4 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input4()),
117 5 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input5()),
118 6 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input6()),
119 7 => self.0.ch[0].pselp.write(|w| w.pselp().analog_input7()),
120 _ => unsafe { unreachable_unchecked() },
123 }
124
125 let mut val: u16 = 0;
126 self.0
127 .result
128 .ptr
129 .write(|w| unsafe { w.ptr().bits(((&mut val) as *mut _) as u32) });
130 self.0
131 .result
132 .maxcnt
133 .write(|w| unsafe { w.maxcnt().bits(1) });
134
135 compiler_fence(SeqCst);
138
139 self.0.tasks_start.write(|w| unsafe { w.bits(1) });
140 self.0.tasks_sample.write(|w| unsafe { w.bits(1) });
141
142 while self.0.events_end.read().bits() == 0 {}
143 self.0.events_end.reset();
144
145 if self.0.result.amount.read().bits() != 1 {
147 return Err(nb::Error::Other(()));
148 }
149
150 compiler_fence(SeqCst);
152
153 Ok(val)
154 }
155}
156
157macro_rules! channel_mappings {
158 ($($n:expr => $pin:path),*) => {
159 $(
160 impl Channel<Saadc> for $pin {
161 type ID = u8;
162
163 fn channel() -> <Self as embedded_hal::adc::Channel<Saadc>>::ID {
164 $n
165 }
166 }
167 )*
168 };
169}
170
171channel_mappings! {
172 0 => crate::gpio::p0::P0_02<Input<Floating>>,
173 1 => crate::gpio::p0::P0_03<Input<Floating>>,
174 2 => crate::gpio::p0::P0_04<Input<Floating>>,
175 3 => crate::gpio::p0::P0_05<Input<Floating>>,
176 4 => crate::gpio::p0::P0_28<Input<Floating>>,
177 5 => crate::gpio::p0::P0_29<Input<Floating>>,
178 6 => crate::gpio::p0::P0_30<Input<Floating>>,
179 7 => crate::gpio::p0::P0_31<Input<Floating>>
180}