diff options
| author | Mathis Deroo <[email protected]> | 2025-12-08 15:09:05 -0800 |
|---|---|---|
| committer | Mathis Deroo <[email protected]> | 2025-12-09 10:52:11 -0800 |
| commit | 759ab109806f447a1193954a453828b860104c3a (patch) | |
| tree | 29b87b9a86a4c1186da6933863ee824c4d09e902 /embassy-mcxa/src | |
| parent | e75e8dddb63f758419ef5d8d7c321c631f5b0a59 (diff) | |
Add Mode trait for Async and Blocking behavior
Signed-off-by: Mathis Deroo <[email protected]>
Diffstat (limited to 'embassy-mcxa/src')
| -rw-r--r-- | embassy-mcxa/src/adc.rs | 131 |
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; | |||
| 10 | use paste::paste; | 10 | use paste::paste; |
| 11 | 11 | ||
| 12 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; | 12 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; |
| 13 | use crate::clocks::{Gate, PoweredClock, enable_and_reset}; | 13 | use crate::clocks::{Gate, PoweredClock, enable_and_reset, ClockError}; |
| 14 | 14 | ||
| 15 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; | 15 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; |
| 16 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; | 16 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; |
| 17 | use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; | 17 | use crate::pac::adc1::cmdl1::{Adch, Mode}; |
| 18 | use crate::pac::adc1::ctrl::CalAvgs; | 18 | use crate::pac::adc1::ctrl::CalAvgs; |
| 19 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; | 19 | use 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>`. | ||
| 127 | pub 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))] |
| 129 | pub enum AdcError { | 132 | pub 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. |
| 153 | pub struct Adc<'a, I: Instance> { | 158 | pub 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 | ||
| 157 | impl<'a, I: Instance> Adc<'a, I> { | 163 | impl<'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 | |||
| 179 | impl<'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 | |
| 228 | impl<'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 | ||
| 553 | impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { | 574 | impl<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)] | ||
| 633 | pub trait ModeAdc: sealed::Sealed {} | ||
| 634 | |||
| 635 | /// Blocking mode. | ||
| 636 | pub struct Blocking; | ||
| 637 | impl sealed::Sealed for Blocking {} | ||
| 638 | impl ModeAdc for Blocking {} | ||
| 639 | |||
| 640 | /// Async mode. | ||
| 641 | pub struct Async; | ||
| 642 | impl sealed::Sealed for Async {} | ||
| 643 | impl ModeAdc for Async {} | ||
| 644 | |||
| 610 | macro_rules! impl_pin { | 645 | macro_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 { |
