aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa
diff options
context:
space:
mode:
authorMathis Deroo <[email protected]>2025-12-08 15:09:05 -0800
committerMathis Deroo <[email protected]>2025-12-09 10:52:11 -0800
commit759ab109806f447a1193954a453828b860104c3a (patch)
tree29b87b9a86a4c1186da6933863ee824c4d09e902 /embassy-mcxa
parente75e8dddb63f758419ef5d8d7c321c631f5b0a59 (diff)
Add Mode trait for Async and Blocking behavior
Signed-off-by: Mathis Deroo <[email protected]>
Diffstat (limited to 'embassy-mcxa')
-rw-r--r--embassy-mcxa/src/adc.rs131
1 files changed, 83 insertions, 48 deletions
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs
index f7340e8c2..16b40fa45 100644
--- a/embassy-mcxa/src/adc.rs
+++ b/embassy-mcxa/src/adc.rs
@@ -10,11 +10,11 @@ use maitake_sync::WaitCell;
10use paste::paste; 10use paste::paste;
11 11
12use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; 12use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4};
13use crate::clocks::{Gate, PoweredClock, enable_and_reset}; 13use crate::clocks::{Gate, PoweredClock, enable_and_reset, ClockError};
14 14
15use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; 15use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres};
16use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; 16use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts};
17use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; 17use crate::pac::adc1::cmdl1::{Adch, Mode};
18use crate::pac::adc1::ctrl::CalAvgs; 18use crate::pac::adc1::ctrl::CalAvgs;
19use crate::pac::adc1::tctrl::{Tcmd, Tpri}; 19use crate::pac::adc1::tctrl::{Tcmd, Tpri};
20 20
@@ -123,14 +123,19 @@ pub struct ConvTriggerConfig {
123 pub enable_hardware_trigger: bool, 123 pub enable_hardware_trigger: bool,
124} 124}
125 125
126/// Shorthand for `Result<T>`.
127pub type Result<T> = core::result::Result<T, Error>;
128
126/// ADC Error types 129/// ADC Error types
127#[derive(Debug, Clone, Copy, PartialEq, Eq)] 130#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))] 131#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub enum AdcError { 132pub enum Error {
130 /// FIFO is empty, no conversion result available 133 /// FIFO is empty, no conversion result available
131 FifoEmpty, 134 FifoEmpty,
132 /// Invalid configuration 135 /// Invalid configuration
133 InvalidConfig, 136 InvalidConfig,
137 /// Clock configuration error.
138 ClockSetup(ClockError),
134} 139}
135 140
136/// Result of an ADC conversion. 141/// Result of an ADC conversion.
@@ -150,11 +155,28 @@ pub struct InterruptHandler<I: Instance> {
150} 155}
151 156
152/// ADC driver instance. 157/// ADC driver instance.
153pub struct Adc<'a, I: Instance> { 158pub struct Adc<'a, I: Instance, M: ModeAdc> {
154 _inst: PhantomData<&'a mut I>, 159 _inst: PhantomData<&'a mut I>,
160 _phantom: PhantomData<M>,
155} 161}
156 162
157impl<'a, I: Instance> Adc<'a, I> { 163impl<'a, I: Instance> Adc<'a, I, Blocking> {
164 /// Create a new blocking instance of the ADC driver.
165 /// # Arguments
166 /// * `_inst` - ADC peripheral instance
167 /// * `pin` - GPIO pin to use for ADC
168 /// * `config` - ADC configuration
169 pub fn new_blocking(
170 _inst: Peri<'a, I>,
171 pin: Peri<'a,
172 impl AdcPin<I>>,
173 config: LpadcConfig
174 ) -> Result<Self> {
175 Self::new_inner(_inst, pin, config)
176 }
177}
178
179impl<'a, I: Instance> Adc<'a, I, Async> {
158 /// Initialize ADC with interrupt support. 180 /// Initialize ADC with interrupt support.
159 /// 181 ///
160 /// # Arguments 182 /// # Arguments
@@ -162,12 +184,12 @@ impl<'a, I: Instance> Adc<'a, I> {
162 /// * `pin` - GPIO pin to use for ADC 184 /// * `pin` - GPIO pin to use for ADC
163 /// * `_irq` - Interrupt binding for this ADC instance 185 /// * `_irq` - Interrupt binding for this ADC instance
164 /// * `config` - ADC configuration 186 /// * `config` - ADC configuration
165 pub fn new( 187 pub fn new_async(
166 _inst: Peri<'a, I>, 188 _inst: Peri<'a, I>,
167 pin: Peri<'a, impl AdcPin<I>>, 189 pin: Peri<'a, impl AdcPin<I>>,
168 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, 190 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a,
169 config: LpadcConfig, 191 config: LpadcConfig,
170 ) -> Self { 192 ) -> Result<Self> {
171 let adc = Self::new_inner(_inst, pin, config); 193 let adc = Self::new_inner(_inst, pin, config);
172 194
173 I::Interrupt::unpend(); 195 I::Interrupt::unpend();
@@ -176,28 +198,48 @@ impl<'a, I: Instance> Adc<'a, I> {
176 adc 198 adc
177 } 199 }
178 200
179 /// Initialize ADC without interrupt support (for polling mode). 201 /// Read ADC value asynchronously.
180 /// 202 ///
181 /// # Arguments 203 /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered.
182 /// * `_inst` - ADC peripheral instance 204 ///
183 /// * `pin` - GPIO pin to use for ADC input 205 /// The function:
184 /// * `config` - ADC configuration 206 /// 1. Enables the FIFO watermark interrupt
185 pub fn new_polling(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin<I>>, config: LpadcConfig) -> Self { 207 /// 2. Triggers a software conversion on trigger 0
186 Self::new_inner(_inst, pin, config) 208 /// 3. Waits for the conversion to complete
209 /// 4. Returns the conversion result
210 ///
211 /// # Returns
212 /// 16-bit ADC conversion value
213 pub async fn read(&mut self) -> Result<u16> {
214 let wait = I::wait_cell().subscribe().await;
215
216 Adc::<'a, I, Async>::enable_interrupt(self, 0x1);
217 Adc::<'a, I, Async>::do_software_trigger(self, 1);
218
219 let _ = wait.await;
220
221 let result = Adc::<'a, I, Async>::get_conv_result(self).unwrap().conv_value >> G_LPADC_RESULT_SHIFT;
222 Ok(result)
187 } 223 }
224}
188 225
189 /// Internal initialization function shared by `new` and `new_polling`. 226
190 fn new_inner(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin<I>>, config: LpadcConfig) -> Self { 227
228impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
229 /// Internal initialization function shared by `new_async` and `new_blocking`.
230 fn new_inner(
231 _inst: Peri<'a, I>,
232 pin: Peri<'a, impl AdcPin<I>>,
233 config: LpadcConfig
234 ) -> Result<Self> {
191 let adc = I::ptr(); 235 let adc = I::ptr();
192 236
193 let _clock_freq = unsafe { 237 _ = unsafe { enable_and_reset::<I>(&AdcConfig {
194 enable_and_reset::<I>(&AdcConfig {
195 power: config.power, 238 power: config.power,
196 source: config.source, 239 source: config.source,
197 div: config.div, 240 div: config.div,
198 }) 241 })
199 .expect("Adc Init should not fail") 242 .map_err(Error::ClockSetup)? };
200 };
201 243
202 pin.mux(); 244 pin.mux();
203 245
@@ -282,7 +324,10 @@ impl<'a, I: Instance> Adc<'a, I> {
282 // Enable ADC 324 // Enable ADC
283 adc.ctrl().modify(|_, w| w.adcen().enabled()); 325 adc.ctrl().modify(|_, w| w.adcen().enabled());
284 326
285 Self { _inst: PhantomData } 327 Ok(Self {
328 _inst: PhantomData,
329 _phantom: PhantomData,
330 })
286 } 331 }
287 332
288 /// Deinitialize the ADC peripheral. 333 /// Deinitialize the ADC peripheral.
@@ -508,13 +553,13 @@ impl<'a, I: Instance> Adc<'a, I> {
508 /// 553 ///
509 /// # Returns 554 /// # Returns
510 /// - `Some(ConvResult)` if a result is available 555 /// - `Some(ConvResult)` if a result is available
511 /// - `Err(AdcError::FifoEmpty)` if the FIFO is empty 556 /// - `Err(Error::FifoEmpty)` if the FIFO is empty
512 pub fn get_conv_result(&self) -> Result<ConvResult, AdcError> { 557 pub fn get_conv_result(&self) -> Result<ConvResult> {
513 let adc = I::ptr(); 558 let adc = I::ptr();
514 let fifo = adc.resfifo0().read().bits(); 559 let fifo = adc.resfifo0().read().bits();
515 const VALID_MASK: u32 = 1 << 31; 560 const VALID_MASK: u32 = 1 << 31;
516 if fifo & VALID_MASK == 0 { 561 if fifo & VALID_MASK == 0 {
517 return Err(AdcError::FifoEmpty); 562 return Err(Error::FifoEmpty);
518 } 563 }
519 564
520 Ok(ConvResult { 565 Ok(ConvResult {
@@ -524,30 +569,6 @@ impl<'a, I: Instance> Adc<'a, I> {
524 conv_value: (fifo & 0xFFFF) as u16, 569 conv_value: (fifo & 0xFFFF) as u16,
525 }) 570 })
526 } 571 }
527
528 /// Read ADC value asynchronously.
529 ///
530 /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered.
531 ///
532 /// The function:
533 /// 1. Enables the FIFO watermark interrupt
534 /// 2. Triggers a software conversion on trigger 0
535 /// 3. Waits for the conversion to complete
536 /// 4. Returns the conversion result
537 ///
538 /// # Returns
539 /// 16-bit ADC conversion value
540 pub async fn read(&mut self) -> Result<u16, AdcError> {
541 let wait = I::wait_cell().subscribe().await;
542
543 self.enable_interrupt(0x1);
544 self.do_software_trigger(1);
545
546 let _ = wait.await;
547
548 let result = self.get_conv_result().unwrap().conv_value >> G_LPADC_RESULT_SHIFT;
549 Ok(result)
550 }
551} 572}
552 573
553impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { 574impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> {
@@ -607,6 +628,20 @@ pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
607 fn mux(&self); 628 fn mux(&self);
608} 629}
609 630
631/// Driver mode.
632#[allow(private_bounds)]
633pub trait ModeAdc: sealed::Sealed {}
634
635/// Blocking mode.
636pub struct Blocking;
637impl sealed::Sealed for Blocking {}
638impl ModeAdc for Blocking {}
639
640/// Async mode.
641pub struct Async;
642impl sealed::Sealed for Async {}
643impl ModeAdc for Async {}
644
610macro_rules! impl_pin { 645macro_rules! impl_pin {
611 ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { 646 ($pin:ident, $peri:ident, $func:ident, $trait:ident) => {
612 impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin { 647 impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin {