1use crate::gpio::{Analog, Pin};
19use crate::pac;
20use crate::rcu::{Clocks, Enable, Rcu, Reset};
21
22const VREFINT_CAL_ADDR: *const u16 = 0x1FFF_F7C0 as *const u16;
23const VREFINT_CAL_BLANK: u16 = 0xFFFF;
25const VREFINT_TYP_MV: i32 = 1200;
28const NOMINAL_VDDA_MV: i32 = 3300;
29const ADC_MAX_CODE: i32 = 4095;
30const V25_MV: i32 = 1450;
32const AVG_SLOPE_X10: i32 = 43;
34
35const TEMP_CHANNEL: u8 = 16;
36const VREF_CHANNEL: u8 = 17;
37
38const CALIBRATION_DELAY_CYCLES: u32 = 14;
40const TEMP_MIN_SAMPTIME_US_X10: u64 = 171;
42const MAX_SAMPTIME_CYCLES_X10: u64 = 2395;
44const US_PER_S: u64 = 1_000_000;
45
46#[derive(Clone, Copy, PartialEq, Eq)]
52#[cfg_attr(feature = "defmt", derive(defmt::Format))]
53#[allow(missing_docs)]
54pub enum SampTime {
55 Cycles1_5 = 0b000,
56 Cycles7_5 = 0b001,
57 Cycles13_5 = 0b010,
58 Cycles28_5 = 0b011,
59 Cycles41_5 = 0b100,
60 Cycles55_5 = 0b101,
61 Cycles71_5 = 0b110,
62 Cycles239_5 = 0b111,
63}
64
65pub trait Channel {
70 const CHANNEL: u8;
72}
73
74macro_rules! channel {
75 ($($(#[$cfg:meta])? $port:literal $pin:literal => $channel:literal),+ $(,)?) => {
76 $($(#[$cfg])? impl Channel for Pin<$port, $pin, Analog> { const CHANNEL: u8 = $channel; })+
77 };
78}
79
80channel!(
81 'A' 0 => 0,
82 'A' 1 => 1,
83 'A' 2 => 2,
84 'A' 3 => 3,
85 'A' 4 => 4,
86 'A' 5 => 5,
87 'A' 6 => 6,
88 'A' 7 => 7,
89 #[cfg(pads_ge_24)] 'B' 0 => 8,
90 'B' 1 => 9,
91);
92
93#[derive(Clone, Copy, PartialEq, Eq)]
95#[cfg_attr(feature = "defmt", derive(defmt::Format))]
96pub enum Event {
97 Eoc,
100}
101
102pub struct Adc {
104 adc: pac::Adc,
105 clocks: Clocks,
106}
107
108impl Adc {
109 pub fn release(mut self, rcu: &mut Rcu) -> pac::Adc {
112 self.unlisten(Event::Eoc);
113 self.adc.ctl1().modify(|_, w| w.adcon().disabled());
114 <pac::Adc as Enable>::disable(rcu);
115 self.adc
116 }
117
118 fn set_channel(&mut self, channel: u8) {
119 self.adc.rsq0().modify(|_, w| w.rl().bits(0b0));
120 self.adc
123 .rsq2()
124 .modify(|_, w| unsafe { w.rsq0().bits(channel) });
125 }
126 fn set_sample_time(&mut self, channel: u8, time: SampTime) {
127 self.adc.sampt1().modify(|_, w| match channel {
128 0 => w.spt0().bits(time as u8),
129 1 => w.spt1().bits(time as u8),
130 2 => w.spt2().bits(time as u8),
131 3 => w.spt3().bits(time as u8),
132 4 => w.spt4().bits(time as u8),
133 5 => w.spt5().bits(time as u8),
134 6 => w.spt6().bits(time as u8),
135 7 => w.spt7().bits(time as u8),
136 8 => w.spt8().bits(time as u8),
137 9 => w.spt9().bits(time as u8),
138 _ => unreachable!(),
139 });
140 }
141 fn set_internal_channel(&mut self, channel: u8) {
142 self.set_channel(channel);
143 }
144 fn sample_time_sufficient(&self) -> bool {
145 TEMP_MIN_SAMPTIME_US_X10 * self.clocks.ck_adc().to_Hz() as u64
146 <= MAX_SAMPTIME_CYCLES_X10 * US_PER_S
147 }
148 fn set_internal_sample_time(&mut self, channel: u8, time: SampTime) {
149 self.adc.sampt0().modify(|_, w| match channel {
150 TEMP_CHANNEL => w.spt16().bits(time as u8),
151 VREF_CHANNEL => w.spt17().bits(time as u8),
152 _ => unreachable!(),
153 });
154 }
155 fn convert(&mut self) -> u16 {
156 self.start_conversion();
157 while self.adc.stat().read().eoc().is_not_complete() {}
158 self.read_result()
159 }
160 fn start_conversion(&mut self) {
161 self.adc.ctl1().modify(|_, w| w.swrcst().start());
162 while self.adc.ctl1().read().swrcst().is_not_started() {}
163 }
164 fn read_result(&mut self) -> u16 {
165 self.adc.rdata().read().rdata().bits()
166 }
167 fn with_internal<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
168 let was_enabled = self.adc.ctl1().read().tsvren().is_enabled();
169 if !was_enabled {
170 self.adc.ctl1().modify(|_, w| w.tsvren().enabled());
171 }
172 let result = f(self);
173 if !was_enabled {
174 self.adc.ctl1().modify(|_, w| w.tsvren().disabled());
175 }
176 result
177 }
178
179 pub fn start<PIN: Channel>(&mut self, _pin: &PIN, time: SampTime) {
183 self.set_channel(PIN::CHANNEL);
184 self.set_sample_time(PIN::CHANNEL, time);
185 self.start_conversion();
186 }
187 pub fn result(&mut self) -> u16 {
192 self.read_result()
193 }
194
195 pub fn listen(&mut self, event: Event) {
198 match event {
199 Event::Eoc => self.adc.ctl0().modify(|_, w| w.eocie().enabled()),
200 }
201 }
202 pub fn unlisten(&mut self, event: Event) {
204 match event {
205 Event::Eoc => self.adc.ctl0().modify(|_, w| w.eocie().disabled()),
206 }
207 }
208
209 pub fn read<PIN: Channel>(&mut self, _pin: &PIN, time: SampTime) -> u16 {
214 self.set_channel(PIN::CHANNEL);
215 self.set_sample_time(PIN::CHANNEL, time);
216 self.convert()
217 }
218 pub fn read_temperature(&mut self) -> Option<i32> {
226 if !self.sample_time_sufficient() {
227 return None;
228 }
229 let vdda_mv = self.read_vref();
230 let raw = self.with_internal(|s| {
231 s.set_internal_channel(TEMP_CHANNEL);
232 s.set_internal_sample_time(TEMP_CHANNEL, SampTime::Cycles239_5);
233 s.convert()
234 });
235 let v_temperature_mv = raw as i32 * vdda_mv / ADC_MAX_CODE;
236 let temperature_x10 = 100 * (V25_MV - v_temperature_mv) / AVG_SLOPE_X10 + 250;
237 Some(temperature_x10)
238 }
239 pub fn read_vref(&mut self) -> i32 {
248 let vrefint_cal = unsafe { core::ptr::read_volatile(VREFINT_CAL_ADDR) };
251 let raw = self.with_internal(|s| {
252 s.set_internal_channel(VREF_CHANNEL);
253 s.set_internal_sample_time(VREF_CHANNEL, SampTime::Cycles239_5);
254 s.convert()
255 }) as i32;
256 if vrefint_cal == VREFINT_CAL_BLANK {
257 VREFINT_TYP_MV * ADC_MAX_CODE / raw
258 } else {
259 NOMINAL_VDDA_MV * vrefint_cal as i32 / raw
260 }
261 }
262}
263
264pub trait AdcExt {
266 fn constrain(self, rcu: &mut Rcu) -> Adc;
277}
278
279impl AdcExt for pac::Adc {
280 fn constrain(self, rcu: &mut Rcu) -> Adc {
281 let clocks = rcu.clocks();
282 <pac::Adc as Enable>::enable(rcu);
283 <pac::Adc as Reset>::reset(rcu);
284 self.ctl1().modify(|_, w| w.adcon().enabled());
285 cortex_m::asm::delay(
286 (CALIBRATION_DELAY_CYCLES * clocks.hclk().to_Hz()).div_ceil(clocks.ck_adc().to_Hz()),
287 );
288 self.ctl1().modify(|_, w| w.rstclb().start());
289 self.ctl1().modify(|_, w| w.clb().start());
290 while self.ctl1().read().clb().is_not_complete() {}
291 self.ctl1()
292 .modify(|_, w| w.eterc().enabled().etsrc().swrcst());
293 Adc { adc: self, clocks }
294 }
295}