1use core::future::poll_fn;
4use core::marker::PhantomData;
5use core::sync::atomic::{compiler_fence, AtomicBool, Ordering};
6use core::task::Poll;
7
8use embassy_hal_internal::Peripheral;
9use embassy_sync::waitqueue::AtomicWaker;
10use sifli_pac::HPSYS_CFG;
11
12use crate::_generated::{FIRST_CHANNEL_PIN, VBAT_CHANNEL_ID, VOL_OFFSET, VOL_RATIO};
13use crate::{blocking_delay_us, interrupt, rcc};
14use crate::mode::{Async, Blocking, Mode};
15use crate::gpio::{self, Analog};
16use crate::interrupt::typelevel::{Binding};
17use crate::interrupt::InterruptExt;
18use crate::pac::gpadc::vals as AdcVals;
19use crate::pac::GPADC;
20use crate::peripherals;
21
22static WAKER: AtomicWaker = AtomicWaker::new();
23static IRQ_DONE: AtomicBool = AtomicBool::new(false);
24
25#[non_exhaustive]
28pub struct Config {
29 pub sample_width: u32,
31 pub conv_width: u8,
33 pub data_samp_dly: u8,
35}
36
37impl Default for Config {
38 fn default() -> Self {
39 Self {
41 sample_width: 0x71,
42 conv_width: 75,
43 data_samp_dly: 0x4,
44 }
45 }
46}
47
48#[derive(Debug, Eq, PartialEq, Copy, Clone)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51pub enum Error {
52 ConversionFailed,
54}
55
56#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Default)]
60#[cfg_attr(feature = "defmt", derive(defmt::Format))]
61#[repr(transparent)]
62pub struct Sample(u16);
63
64impl Sample {
65 pub fn value(&self) -> u16 {
67 self.0
68 }
69
70 pub fn to_mv(&self) -> u16 {
72 if self.0 <= VOL_OFFSET {
73 0 } else {
75 ((self.0 - VOL_OFFSET) as u32 * VOL_RATIO as u32 / 1000) as u16
78 }
79 }
80
81 pub fn to_v_float(&self) -> f32 {
83 if self.0 <= VOL_OFFSET {
84 0.0 } else {
86 (self.0 - VOL_OFFSET) as f32 * VOL_RATIO as f32 / 1_000_000.0
89 }
90 }
91}
92
93pub struct Channel<'p> {
95 pub id: u8,
96 phantom: PhantomData<&'p ()>,
97}
98
99pub trait AdcPin: gpio::Pin {
103 fn adc_channel_id(&self) -> u8 {
104 self.pin() - FIRST_CHANNEL_PIN
105 }
106}
107
108impl<'p> Channel<'p> {
109 pub fn new_pin(pin: impl AdcPin + 'p) -> Self {
111 let id = pin.adc_channel_id();
112 Analog::new(pin);
113 Self {
114 id,
115 phantom: PhantomData,
116 }
117 }
118
119 pub fn new_vbat(_vbat: impl Peripheral<P = peripherals::ADC_VBAT> + 'p) -> Self {
123 Self {
124 id: VBAT_CHANNEL_ID,
125 phantom: PhantomData,
126 }
127 }
128}
129
130pub struct Adc<'d, M: Mode> {
132 _phantom: PhantomData<(&'d peripherals::GPADC, M)>,
133}
134
135impl<'d, M: Mode> Adc<'d, M> {
136 fn new_inner(
138 _inner: impl Peripheral<P = peripherals::GPADC> + 'd,
139 config: Config,
140 ) -> Self {
141 rcc::enable_and_reset::<peripherals::GPADC>();
142 let regs = GPADC;
143
144 HPSYS_CFG.anau_cr().modify(|r| r.set_en_bg(true));
151
152 regs.cfg_reg1().modify(|r| r.set_anau_gpadc_se(true));
154
155 regs.ctrl_reg2().write(|w| {
157 w.set_samp_width(config.sample_width);
158 w.set_conv_width(config.conv_width);
159 });
160 regs.ctrl_reg().modify(|r| {
161 r.set_data_samp_dly(config.data_samp_dly);
162 r.set_init_time(8);
164 r.set_timer_trig_en(false);
166 });
167
168 regs.cfg_reg1().modify(|r| {
170 r.set_anau_gpadc_vsp(AdcVals::Vsp::V0_642); r.set_anau_gpadc_cmm(0x10);
172 r.set_anau_gpadc_en_v18(false); });
174
175 for i in 0..8 {
177 regs.slot(i).modify(|r| r.set_slot_en(false));
178 }
179
180 Self {
181 _phantom: PhantomData,
182 }
183 }
184
185 fn prepare(&mut self, channel: &Channel) {
187 if channel.id == VBAT_CHANNEL_ID {
190 HPSYS_CFG.anau_cr().modify(|r| r.set_en_vbat_mon(true));
192 }
193
194 GPADC.slot(channel.id as _).modify(|r| r.set_slot_en(true));
196
197 GPADC.cfg_reg1().modify(|r| r.set_anau_gpadc_ldoref_en(true));
199 blocking_delay_us(200);
201
202 GPADC.cfg_reg1().modify(|r| {r.set_anau_gpadc_mute(false)});
204
205 GPADC.ctrl_reg().modify(|r| r.set_frc_en_adc(true));
207 blocking_delay_us(200);
209 }
210
211 fn finish(&mut self, channel: &Channel) {
213 if channel.id == VBAT_CHANNEL_ID {
216 HPSYS_CFG.anau_cr().modify(|r| r.set_en_vbat_mon(false));
218 }
219
220 GPADC.ctrl_reg().modify(|r| r.set_frc_en_adc(false));
221 GPADC.cfg_reg1().modify(|r| {
222 r.set_anau_gpadc_ldoref_en(false);
223 r.set_anau_gpadc_mute(true);
225 });
226 }
227
228 pub fn blocking_read(&mut self, ch: &mut Channel) -> Result<Sample, Error> {
230 self.prepare(ch);
231
232 GPADC.ctrl_reg().modify(|r| {
234 r.set_adc_op_mode(false); r.set_chnl_sel_frc_en(true); });
237 GPADC.cfg_reg1().modify(|r| r.set_anau_gpadc_sel_pch(ch.id));
238
239 GPADC.ctrl_reg().modify(|r| r.set_adc_start(true));
241
242 while !GPADC.gpadc_irq().read().gpadc_irsr() {}
244
245 GPADC.gpadc_irq().write(|w| w.set_gpadc_icr(true));
247
248 let result = GPADC.rdata(0).read().even_slot_rdata();
250
251 self.finish(ch);
252
253 Ok(Sample(result & 0xfff))
254 }
255}
256
257impl<'d, M: Mode> Drop for Adc<'d, M> {
258 fn drop(&mut self) {
259 GPADC.ctrl_reg().modify(|r| r.set_frc_en_adc(false));
261 GPADC.cfg_reg1().modify(|r| r.set_anau_gpadc_ldoref_en(false));
262 }
265}
266
267impl<'d> Adc<'d, Blocking> {
268 pub fn new_blocking(
274 inner: impl Peripheral<P = peripherals::GPADC> + 'd,
275 config: Config,
276 ) -> Self {
277 Self::new_inner(inner, config)
278 }
279}
280
281pub struct InterruptHandler;
283
284impl interrupt::typelevel::Handler<interrupt::typelevel::GPADC> for InterruptHandler {
285 unsafe fn on_interrupt() {
286 if GPADC.gpadc_irq().read().gpadc_irsr() {
287 IRQ_DONE.store(true, Ordering::SeqCst);
288 }
289 GPADC.gpadc_irq().modify(|w| w.set_gpadc_icr(true));
290 WAKER.wake();
291 }
292}
293
294impl<'d> Adc<'d, Async> {
295 pub fn new(
297 inner: impl Peripheral<P = peripherals::GPADC> + 'd,
298 _irq: impl Binding<interrupt::typelevel::GPADC, InterruptHandler>,
299 config: Config,
300 ) -> Self {
301 let s = Self::new_inner(inner, config);
302
303 let irq = crate::interrupt::GPADC;
304 irq.unpend();
305 unsafe { irq.enable() };
306
307 s
308 }
309
310 async fn wait_for_completion(&mut self) {
312 let regs = GPADC;
313 poll_fn(move |cx| {
314 WAKER.register(cx.waker());
315 regs.gpadc_irq().modify(|r| r.set_gpadc_imr(false));
317 compiler_fence(Ordering::SeqCst);
318
319 if IRQ_DONE.load(Ordering::SeqCst) {
320 IRQ_DONE.store(false, Ordering::SeqCst);
321 Poll::Ready(())
322 } else {
323 Poll::Pending
324 }
325 })
326 .await
327 }
328
329 pub async fn read(&mut self, ch: &mut Channel<'_>) -> Result<Sample, Error> {
331 self.prepare(ch);
332
333 GPADC.ctrl_reg().modify(|r| {
335 r.set_adc_op_mode(false);
336 r.set_chnl_sel_frc_en(true);
337 });
338 GPADC.cfg_reg1().modify(|r| r.set_anau_gpadc_sel_pch(ch.id));
339
340 GPADC.gpadc_irq().modify(|r| r.set_gpadc_imr(false));
342
343 IRQ_DONE.store(false, Ordering::SeqCst);
345 compiler_fence(Ordering::SeqCst);
346
347 GPADC.ctrl_reg().modify(|r| r.set_adc_start(true));
348 self.wait_for_completion().await;
349
350 let result = GPADC.rdata(0).read().even_slot_rdata();
351
352 self.finish(ch);
353
354 Ok(Sample(result & 0xfff))
355 }
356}
357
358#[allow(private_interfaces)]
359pub(crate) trait SealedInstance: crate::rcc::RccEnableReset + crate::rcc::RccGetFreq {}
360
361#[allow(private_bounds)]
362pub trait Instance: Peripheral<P = Self> + SealedInstance + 'static + Send {
363 type Interrupt: interrupt::typelevel::Interrupt;
365}
366impl SealedInstance for peripherals::GPADC {}
367impl Instance for peripherals::GPADC {
368 type Interrupt = crate::interrupt::typelevel::GPADC;
369}
370
371dma_trait!(Dma, Instance);