diff options
| author | James Munns <[email protected]> | 2025-12-11 16:52:13 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-12-11 16:52:13 +0000 |
| commit | 0301bdf2c09854f9f3bc864f666608cef295373b (patch) | |
| tree | 7c11403b9ab76f425a9145fb0b764dfe063a4472 | |
| parent | 802dfbb9f8a3de42f132a3e95682552aefcd50c0 (diff) | |
| parent | 5c09b36a7ffbab31c97230baf0de39920e12d175 (diff) | |
Merge pull request #5037 from jamesmunns/james/retouch-adc
[MCXA]: Refactor the ADC API
| -rw-r--r-- | embassy-mcxa/src/adc.rs | 703 | ||||
| -rw-r--r-- | examples/mcxa/src/bin/adc_interrupt.rs | 20 | ||||
| -rw-r--r-- | examples/mcxa/src/bin/adc_polling.rs | 26 |
3 files changed, 422 insertions, 327 deletions
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index d7d17cf5f..f88bb6b37 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs | |||
| @@ -1,4 +1,5 @@ | |||
| 1 | //! ADC driver | 1 | //! ADC driver |
| 2 | use core::future::Future; | ||
| 2 | use core::marker::PhantomData; | 3 | use core::marker::PhantomData; |
| 3 | 4 | ||
| 4 | use embassy_hal_internal::{Peri, PeripheralType}; | 5 | use embassy_hal_internal::{Peri, PeripheralType}; |
| @@ -12,12 +13,10 @@ use crate::interrupt::typelevel::{Handler, Interrupt}; | |||
| 12 | use crate::pac; | 13 | use crate::pac; |
| 13 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; | 14 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; |
| 14 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; | 15 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; |
| 15 | use crate::pac::adc1::cmdl1::{Adch, Mode}; | 16 | use crate::pac::adc1::cmdl1::Mode; |
| 16 | use crate::pac::adc1::ctrl::CalAvgs; | 17 | use crate::pac::adc1::ctrl::CalAvgs; |
| 17 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; | 18 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; |
| 18 | 19 | ||
| 19 | const G_LPADC_RESULT_SHIFT: u32 = 0; | ||
| 20 | |||
| 21 | /// Trigger priority policy for ADC conversions. | 20 | /// Trigger priority policy for ADC conversions. |
| 22 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 21 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 23 | #[repr(u8)] | 22 | #[repr(u8)] |
| @@ -59,10 +58,6 @@ pub struct LpadcConfig { | |||
| 59 | /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. | 58 | /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. |
| 60 | /// Only available when ADC pausing function is enabled. The available value range is in 9-bit. | 59 | /// Only available when ADC pausing function is enabled. The available value range is in 9-bit. |
| 61 | pub conv_pause_delay: u16, | 60 | pub conv_pause_delay: u16, |
| 62 | /// FIFO watermark level for interrupt generation. | ||
| 63 | /// When the number of datawords stored in the ADC Result FIFO is greater than the value in this field, | ||
| 64 | /// the ready flag would be asserted to indicate stored data has reached the programmable threshold. | ||
| 65 | pub fifo_watermark: u8, | ||
| 66 | /// Power configuration (normal/deep sleep behavior) | 61 | /// Power configuration (normal/deep sleep behavior) |
| 67 | pub power: PoweredClock, | 62 | pub power: PoweredClock, |
| 68 | /// ADC clock source selection | 63 | /// ADC clock source selection |
| @@ -83,7 +78,6 @@ impl Default for LpadcConfig { | |||
| 83 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | 78 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, |
| 84 | enable_conv_pause: false, | 79 | enable_conv_pause: false, |
| 85 | conv_pause_delay: 0, | 80 | conv_pause_delay: 0, |
| 86 | fifo_watermark: 0, | ||
| 87 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | 81 | power: PoweredClock::NormalEnabledDeepSleepDisabled, |
| 88 | source: AdcClockSel::FroLfDiv, | 82 | source: AdcClockSel::FroLfDiv, |
| 89 | div: Div4::no_div(), | 83 | div: Div4::no_div(), |
| @@ -96,7 +90,6 @@ impl Default for LpadcConfig { | |||
| 96 | /// Defines the parameters for a single ADC conversion operation. | 90 | /// Defines the parameters for a single ADC conversion operation. |
| 97 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 91 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 98 | pub struct ConvCommandConfig { | 92 | pub struct ConvCommandConfig { |
| 99 | pub channel_number: Adch, | ||
| 100 | pub chained_next_command_number: Next, | 93 | pub chained_next_command_number: Next, |
| 101 | pub enable_auto_channel_increment: bool, | 94 | pub enable_auto_channel_increment: bool, |
| 102 | pub loop_count: u8, | 95 | pub loop_count: u8, |
| @@ -109,6 +102,23 @@ pub struct ConvCommandConfig { | |||
| 109 | pub enable_wait_trigger: bool, | 102 | pub enable_wait_trigger: bool, |
| 110 | } | 103 | } |
| 111 | 104 | ||
| 105 | impl Default for ConvCommandConfig { | ||
| 106 | fn default() -> Self { | ||
| 107 | ConvCommandConfig { | ||
| 108 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | ||
| 109 | enable_auto_channel_increment: false, | ||
| 110 | loop_count: 0, | ||
| 111 | hardware_average_mode: Avgs::NoAverage, | ||
| 112 | sample_time_mode: Sts::Sample3p5, | ||
| 113 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 114 | hardware_compare_value_high: 0, | ||
| 115 | hardware_compare_value_low: 0, | ||
| 116 | conversion_resolution_mode: Mode::Data12Bits, | ||
| 117 | enable_wait_trigger: false, | ||
| 118 | } | ||
| 119 | } | ||
| 120 | } | ||
| 121 | |||
| 112 | /// Configuration for a conversion trigger. | 122 | /// Configuration for a conversion trigger. |
| 113 | /// | 123 | /// |
| 114 | /// Defines how a trigger initiates ADC conversions. | 124 | /// Defines how a trigger initiates ADC conversions. |
| @@ -120,6 +130,17 @@ pub struct ConvTriggerConfig { | |||
| 120 | pub enable_hardware_trigger: bool, | 130 | pub enable_hardware_trigger: bool, |
| 121 | } | 131 | } |
| 122 | 132 | ||
| 133 | impl Default for ConvTriggerConfig { | ||
| 134 | fn default() -> Self { | ||
| 135 | ConvTriggerConfig { | ||
| 136 | target_command_id: Tcmd::NotValid, | ||
| 137 | delay_power: 0, | ||
| 138 | priority: Tpri::HighestPriority, | ||
| 139 | enable_hardware_trigger: false, | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
| 143 | |||
| 123 | /// Shorthand for `Result<T>`. | 144 | /// Shorthand for `Result<T>`. |
| 124 | pub type Result<T> = core::result::Result<T, Error>; | 145 | pub type Result<T> = core::result::Result<T, Error>; |
| 125 | 146 | ||
| @@ -152,23 +173,127 @@ pub struct InterruptHandler<I: Instance> { | |||
| 152 | } | 173 | } |
| 153 | 174 | ||
| 154 | /// ADC driver instance. | 175 | /// ADC driver instance. |
| 155 | pub struct Adc<'a, I: Instance, M: ModeAdc> { | 176 | pub struct Adc<'a, M: ModeAdc> { |
| 156 | _inst: PhantomData<&'a mut I>, | 177 | _inst: PhantomData<&'a mut ()>, |
| 157 | _phantom: PhantomData<M>, | 178 | mode: M, |
| 179 | |||
| 180 | // The channel index of the pin used to create our ADC instance | ||
| 181 | channel_idx: u8, | ||
| 182 | |||
| 183 | // The register block of the ADC instance | ||
| 184 | info: &'static pac::adc0::RegisterBlock, | ||
| 158 | } | 185 | } |
| 159 | 186 | ||
| 160 | impl<'a, I: Instance> Adc<'a, I, Blocking> { | 187 | impl<'a> Adc<'a, Blocking> { |
| 161 | /// Create a new blocking instance of the ADC driver. | 188 | /// Create a new blocking instance of the ADC driver. |
| 162 | /// # Arguments | 189 | /// # Arguments |
| 163 | /// * `_inst` - ADC peripheral instance | 190 | /// * `_inst` - ADC peripheral instance |
| 164 | /// * `pin` - GPIO pin to use for ADC | 191 | /// * `pin` - GPIO pin to use for ADC |
| 165 | /// * `config` - ADC configuration | 192 | /// * `config` - ADC configuration |
| 166 | pub fn new_blocking(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin<I>>, config: LpadcConfig) -> Result<Self> { | 193 | pub fn new_blocking<I: Instance>( |
| 167 | Self::new_inner(_inst, pin, config) | 194 | _inst: Peri<'a, I>, |
| 195 | pin: Peri<'a, impl AdcPin<I>>, | ||
| 196 | config: LpadcConfig, | ||
| 197 | ) -> Result<Self> { | ||
| 198 | Self::new_inner(_inst, pin, config, Blocking) | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Enable ADC interrupts. | ||
| 202 | /// | ||
| 203 | /// Enables the interrupt sources specified in the bitmask. | ||
| 204 | /// | ||
| 205 | /// # Arguments | ||
| 206 | /// * `mask` - Bitmask of interrupt sources to enable | ||
| 207 | pub fn enable_interrupt(&mut self, mask: u32) { | ||
| 208 | self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Disable ADC interrupts. | ||
| 212 | /// | ||
| 213 | /// Disables the interrupt sources specified in the bitmask. | ||
| 214 | /// | ||
| 215 | /// # Arguments | ||
| 216 | /// * `mask` - Bitmask of interrupt sources to disable | ||
| 217 | pub fn disable_interrupt(&mut self, mask: u32) { | ||
| 218 | self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); | ||
| 219 | } | ||
| 220 | |||
| 221 | pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> { | ||
| 222 | if watermark > 0b111 { | ||
| 223 | return Err(Error::InvalidConfig); | ||
| 224 | } | ||
| 225 | self.info.fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) }); | ||
| 226 | Ok(()) | ||
| 227 | } | ||
| 228 | |||
| 229 | /// Trigger ADC conversion(s) via software. | ||
| 230 | /// | ||
| 231 | /// Initiates conversion(s) for the trigger(s) specified in the bitmask. | ||
| 232 | /// Each bit in the mask corresponds to a trigger ID (bit 0 = trigger 0, etc.). | ||
| 233 | /// | ||
| 234 | /// # Arguments | ||
| 235 | /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N) | ||
| 236 | /// | ||
| 237 | /// # Returns | ||
| 238 | /// * `Ok(())` if the triger mask was valid | ||
| 239 | /// * `Err(Error::InvalidConfig)` if the mask was greater than `0b1111` | ||
| 240 | pub fn do_software_trigger(&self, trigger_id_mask: u8) -> Result<()> { | ||
| 241 | if trigger_id_mask > 0b1111 { | ||
| 242 | return Err(Error::InvalidConfig); | ||
| 243 | } | ||
| 244 | self.info.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) }); | ||
| 245 | Ok(()) | ||
| 246 | } | ||
| 247 | |||
| 248 | /// Set conversion command configuration. | ||
| 249 | /// | ||
| 250 | /// Configures a conversion command slot with the specified parameters. | ||
| 251 | /// Commands define how conversions are performed (channel, resolution, etc.). | ||
| 252 | /// | ||
| 253 | /// # Arguments | ||
| 254 | /// * `index` - Command index (Must be in range 1..=7) | ||
| 255 | /// * `config` - Command configuration | ||
| 256 | /// | ||
| 257 | /// # Returns | ||
| 258 | /// * `Ok(())` if the command was configured successfully | ||
| 259 | /// * `Err(Error::InvalidConfig)` if the index is out of range | ||
| 260 | pub fn set_conv_command_config(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { | ||
| 261 | self.set_conv_command_config_inner(index, config) | ||
| 262 | } | ||
| 263 | |||
| 264 | /// Set conversion trigger configuration. | ||
| 265 | /// | ||
| 266 | /// Configures a trigger to initiate conversions. Triggers can be | ||
| 267 | /// activated by software or hardware signals. | ||
| 268 | /// | ||
| 269 | /// # Arguments | ||
| 270 | /// * `trigger_id` - Trigger index (0..=3) | ||
| 271 | /// * `config` - Trigger configuration | ||
| 272 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { | ||
| 273 | self.set_conv_trigger_config_inner(trigger_id, config) | ||
| 274 | } | ||
| 275 | |||
| 276 | /// Reset the FIFO buffer. | ||
| 277 | /// | ||
| 278 | /// Clears all pending conversion results from the FIFO. | ||
| 279 | pub fn do_reset_fifo(&self) { | ||
| 280 | self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 281 | } | ||
| 282 | |||
| 283 | /// Get conversion result from FIFO. | ||
| 284 | /// | ||
| 285 | /// Reads and returns the next conversion result from the FIFO. | ||
| 286 | /// Returns `None` if the FIFO is empty. | ||
| 287 | /// | ||
| 288 | /// # Returns | ||
| 289 | /// - `Some(ConvResult)` if a result is available | ||
| 290 | /// - `Err(Error::FifoEmpty)` if the FIFO is empty | ||
| 291 | pub fn get_conv_result(&self) -> Result<ConvResult> { | ||
| 292 | self.get_conv_result_inner() | ||
| 168 | } | 293 | } |
| 169 | } | 294 | } |
| 170 | 295 | ||
| 171 | impl<'a, I: Instance> Adc<'a, I, Async> { | 296 | impl<'a> Adc<'a, Async> { |
| 172 | /// Initialize ADC with interrupt support. | 297 | /// Initialize ADC with interrupt support. |
| 173 | /// | 298 | /// |
| 174 | /// # Arguments | 299 | /// # Arguments |
| @@ -176,18 +301,73 @@ impl<'a, I: Instance> Adc<'a, I, Async> { | |||
| 176 | /// * `pin` - GPIO pin to use for ADC | 301 | /// * `pin` - GPIO pin to use for ADC |
| 177 | /// * `_irq` - Interrupt binding for this ADC instance | 302 | /// * `_irq` - Interrupt binding for this ADC instance |
| 178 | /// * `config` - ADC configuration | 303 | /// * `config` - ADC configuration |
| 179 | pub fn new_async( | 304 | pub fn new_async<I: Instance>( |
| 180 | _inst: Peri<'a, I>, | 305 | _inst: Peri<'a, I>, |
| 181 | pin: Peri<'a, impl AdcPin<I>>, | 306 | pin: Peri<'a, impl AdcPin<I>>, |
| 182 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, | 307 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, |
| 183 | config: LpadcConfig, | 308 | config: LpadcConfig, |
| 184 | ) -> Result<Self> { | 309 | ) -> Result<Self> { |
| 185 | let adc = Self::new_inner(_inst, pin, config); | 310 | let adc = Self::new_inner(_inst, pin, config, Async { waiter: I::wait_cell() })?; |
| 186 | 311 | ||
| 187 | I::Interrupt::unpend(); | 312 | I::Interrupt::unpend(); |
| 188 | unsafe { I::Interrupt::enable() }; | 313 | unsafe { I::Interrupt::enable() }; |
| 189 | 314 | ||
| 190 | adc | 315 | let cfg = ConvCommandConfig { |
| 316 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | ||
| 317 | enable_auto_channel_increment: false, | ||
| 318 | loop_count: 0, | ||
| 319 | hardware_average_mode: Avgs::NoAverage, | ||
| 320 | sample_time_mode: Sts::Sample3p5, | ||
| 321 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 322 | hardware_compare_value_high: 0, | ||
| 323 | hardware_compare_value_low: 0, | ||
| 324 | conversion_resolution_mode: Mode::Data16Bits, | ||
| 325 | enable_wait_trigger: false, | ||
| 326 | }; | ||
| 327 | |||
| 328 | // We always use command 1, so this cannot fail | ||
| 329 | _ = adc.set_conv_command_config_inner(1, &cfg); | ||
| 330 | |||
| 331 | let cfg = ConvTriggerConfig { | ||
| 332 | target_command_id: Tcmd::ExecuteCmd1, | ||
| 333 | delay_power: 0, | ||
| 334 | priority: Tpri::HighestPriority, | ||
| 335 | enable_hardware_trigger: false, | ||
| 336 | }; | ||
| 337 | |||
| 338 | // We always use trigger 0, so this cannot fail | ||
| 339 | _ = adc.set_conv_trigger_config_inner(0, &cfg); | ||
| 340 | |||
| 341 | // We always set the watermark to 0 (trigger when 1 is available) | ||
| 342 | I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(0) }); | ||
| 343 | |||
| 344 | Ok(adc) | ||
| 345 | } | ||
| 346 | |||
| 347 | /// Set the number of averages | ||
| 348 | pub fn set_averages(&mut self, avgs: Avgs) { | ||
| 349 | // TODO: we should probably return a result or wait for idle? | ||
| 350 | // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." | ||
| 351 | self.info.cmdh1().modify(|_r, w| w.avgs().variant(avgs)); | ||
| 352 | } | ||
| 353 | |||
| 354 | /// Set the sample time | ||
| 355 | pub fn set_sample_time(&mut self, st: Sts) { | ||
| 356 | // TODO: we should probably return a result or wait for idle? | ||
| 357 | // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." | ||
| 358 | self.info.cmdh1().modify(|_r, w| w.sts().variant(st)); | ||
| 359 | } | ||
| 360 | |||
| 361 | pub fn set_resolution(&mut self, mode: Mode) { | ||
| 362 | // TODO: we should probably return a result or wait for idle? | ||
| 363 | // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." | ||
| 364 | self.info.cmdl1().modify(|_r, w| w.mode().variant(mode)); | ||
| 365 | } | ||
| 366 | |||
| 367 | fn wait_idle(&mut self) -> impl Future<Output = core::result::Result<(), maitake_sync::Closed>> + use<'_> { | ||
| 368 | self.mode | ||
| 369 | .waiter | ||
| 370 | .wait_for(|| self.info.ie().read().fwmie0().bit_is_clear()) | ||
| 191 | } | 371 | } |
| 192 | 372 | ||
| 193 | /// Read ADC value asynchronously. | 373 | /// Read ADC value asynchronously. |
| @@ -203,21 +383,32 @@ impl<'a, I: Instance> Adc<'a, I, Async> { | |||
| 203 | /// # Returns | 383 | /// # Returns |
| 204 | /// 16-bit ADC conversion value | 384 | /// 16-bit ADC conversion value |
| 205 | pub async fn read(&mut self) -> Result<u16> { | 385 | pub async fn read(&mut self) -> Result<u16> { |
| 206 | let wait = I::wait_cell().subscribe().await; | 386 | // If we cancelled a previous read, we might still be busy, wait |
| 387 | // until the interrupt is cleared (done by the interrupt) | ||
| 388 | _ = self.wait_idle().await; | ||
| 389 | |||
| 390 | // Clear the fifo | ||
| 391 | self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 207 | 392 | ||
| 208 | Adc::<'a, I, Async>::enable_interrupt(self, 0x1); | 393 | // Trigger a new conversion |
| 209 | Adc::<'a, I, Async>::do_software_trigger(self, 1); | 394 | self.info.ie().modify(|_r, w| w.fwmie0().set_bit()); |
| 395 | self.info.swtrig().write(|w| w.swt0().set_bit()); | ||
| 210 | 396 | ||
| 211 | let _ = wait.await; | 397 | // Wait for completion |
| 398 | _ = self.wait_idle().await; | ||
| 212 | 399 | ||
| 213 | let result = Adc::<'a, I, Async>::get_conv_result(self).unwrap().conv_value >> G_LPADC_RESULT_SHIFT; | 400 | self.get_conv_result_inner().map(|r| r.conv_value) |
| 214 | Ok(result) | ||
| 215 | } | 401 | } |
| 216 | } | 402 | } |
| 217 | 403 | ||
| 218 | impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | 404 | impl<'a, M: ModeAdc> Adc<'a, M> { |
| 219 | /// Internal initialization function shared by `new_async` and `new_blocking`. | 405 | /// Internal initialization function shared by `new_async` and `new_blocking`. |
| 220 | fn new_inner(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin<I>>, config: LpadcConfig) -> Result<Self> { | 406 | fn new_inner<I: Instance, P: AdcPin<I>>( |
| 407 | _inst: Peri<'a, I>, | ||
| 408 | pin: Peri<'a, P>, | ||
| 409 | config: LpadcConfig, | ||
| 410 | mode: M, | ||
| 411 | ) -> Result<Self> { | ||
| 221 | let adc = I::ptr(); | 412 | let adc = I::ptr(); |
| 222 | 413 | ||
| 223 | _ = unsafe { | 414 | _ = unsafe { |
| @@ -241,22 +432,14 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | |||
| 241 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | 432 | adc.ctrl().modify(|_, w| w.adcen().disabled()); |
| 242 | 433 | ||
| 243 | /* Configure the module generally. */ | 434 | /* Configure the module generally. */ |
| 244 | if config.enable_in_doze_mode { | 435 | adc.ctrl().modify(|_, w| w.dozen().bit(config.enable_in_doze_mode)); |
| 245 | adc.ctrl().modify(|_, w| w.dozen().enabled()); | ||
| 246 | } else { | ||
| 247 | adc.ctrl().modify(|_, w| w.dozen().disabled()); | ||
| 248 | } | ||
| 249 | 436 | ||
| 250 | /* Set calibration average mode. */ | 437 | /* Set calibration average mode. */ |
| 251 | adc.ctrl() | 438 | adc.ctrl() |
| 252 | .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); | 439 | .modify(|_, w| w.cal_avgs().variant(config.conversion_average_mode)); |
| 253 | 440 | ||
| 254 | adc.cfg().write(|w| unsafe { | 441 | adc.cfg().write(|w| unsafe { |
| 255 | let w = if config.enable_analog_preliminary { | 442 | w.pwren().bit(config.enable_analog_preliminary); |
| 256 | w.pwren().pre_enabled() | ||
| 257 | } else { | ||
| 258 | w | ||
| 259 | }; | ||
| 260 | 443 | ||
| 261 | w.pudly() | 444 | w.pudly() |
| 262 | .bits(config.power_up_delay) | 445 | .bits(config.power_up_delay) |
| @@ -306,34 +489,29 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | |||
| 306 | adc.pause().write(|w| unsafe { w.bits(0) }); | 489 | adc.pause().write(|w| unsafe { w.bits(0) }); |
| 307 | } | 490 | } |
| 308 | 491 | ||
| 309 | adc.fctrl0() | 492 | adc.fctrl0().write(|w| unsafe { w.fwmark().bits(0) }); |
| 310 | .write(|w| unsafe { w.fwmark().bits(config.fifo_watermark) }); | ||
| 311 | 493 | ||
| 312 | // Enable ADC | 494 | // Enable ADC |
| 313 | adc.ctrl().modify(|_, w| w.adcen().enabled()); | 495 | adc.ctrl().modify(|_, w| w.adcen().enabled()); |
| 314 | 496 | ||
| 315 | Ok(Self { | 497 | Ok(Self { |
| 316 | _inst: PhantomData, | 498 | _inst: PhantomData, |
| 317 | _phantom: PhantomData, | 499 | mode, |
| 500 | channel_idx: P::CHANNEL, | ||
| 501 | info: adc, | ||
| 318 | }) | 502 | }) |
| 319 | } | 503 | } |
| 320 | 504 | ||
| 321 | /// Deinitialize the ADC peripheral. | ||
| 322 | pub fn deinit(&self) { | ||
| 323 | let adc = I::ptr(); | ||
| 324 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | ||
| 325 | } | ||
| 326 | |||
| 327 | /// Perform offset calibration. | 505 | /// Perform offset calibration. |
| 328 | /// Waits for calibration to complete before returning. | 506 | /// Waits for calibration to complete before returning. |
| 329 | pub fn do_offset_calibration(&self) { | 507 | pub fn do_offset_calibration(&self) { |
| 330 | let adc = I::ptr(); | ||
| 331 | // Enable calibration mode | 508 | // Enable calibration mode |
| 332 | adc.ctrl() | 509 | self.info |
| 510 | .ctrl() | ||
| 333 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); | 511 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); |
| 334 | 512 | ||
| 335 | // Wait for calibration to complete (polling status register) | 513 | // Wait for calibration to complete (polling status register) |
| 336 | while adc.stat().read().cal_rdy().is_not_set() {} | 514 | while self.info.stat().read().cal_rdy().is_not_set() {} |
| 337 | } | 515 | } |
| 338 | 516 | ||
| 339 | /// Calculate gain conversion result from gain adjustment factor. | 517 | /// Calculate gain conversion result from gain adjustment factor. |
| @@ -363,148 +541,78 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | |||
| 363 | 541 | ||
| 364 | /// Perform automatic gain calibration. | 542 | /// Perform automatic gain calibration. |
| 365 | pub fn do_auto_calibration(&self) { | 543 | pub fn do_auto_calibration(&self) { |
| 366 | let adc = I::ptr(); | 544 | self.info |
| 367 | adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); | 545 | .ctrl() |
| 546 | .modify(|_, w| w.cal_req().calibration_request_pending()); | ||
| 368 | 547 | ||
| 369 | while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} | 548 | while self.info.gcc0().read().rdy().is_gain_cal_not_valid() {} |
| 370 | 549 | ||
| 371 | let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; | 550 | let mut gcca = self.info.gcc0().read().gain_cal().bits() as u32; |
| 372 | if gcca & ((0xFFFF + 1) >> 1) != 0 { | 551 | if gcca & 0x8000 != 0 { |
| 373 | gcca |= !0xFFFF; | 552 | gcca |= !0xFFFF; |
| 374 | } | 553 | } |
| 375 | 554 | ||
| 376 | let gcra = 131072.0 / (131072.0 - gcca as f32); | 555 | let gcra = 131072.0 / (131072.0 - gcca as f32); |
| 377 | 556 | ||
| 378 | // Write to GCR0 | 557 | // Write to GCR0 |
| 379 | adc.gcr0().write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); | 558 | self.info |
| 559 | .gcr0() | ||
| 560 | .write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); | ||
| 380 | 561 | ||
| 381 | adc.gcr0().modify(|_, w| w.rdy().set_bit()); | 562 | self.info.gcr0().modify(|_, w| w.rdy().set_bit()); |
| 382 | 563 | ||
| 383 | // Wait for calibration to complete (polling status register) | 564 | // Wait for calibration to complete (polling status register) |
| 384 | while adc.stat().read().cal_rdy().is_not_set() {} | 565 | while self.info.stat().read().cal_rdy().is_not_set() {} |
| 385 | } | ||
| 386 | |||
| 387 | /// Trigger ADC conversion(s) via software. | ||
| 388 | /// | ||
| 389 | /// Initiates conversion(s) for the trigger(s) specified in the bitmask. | ||
| 390 | /// Each bit in the mask corresponds to a trigger ID (bit 0 = trigger 0, etc.). | ||
| 391 | /// | ||
| 392 | /// # Arguments | ||
| 393 | /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N) | ||
| 394 | pub fn do_software_trigger(&self, trigger_id_mask: u32) { | ||
| 395 | let adc = I::ptr(); | ||
| 396 | adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); | ||
| 397 | } | 566 | } |
| 398 | 567 | ||
| 399 | /// Get default conversion command configuration. | 568 | fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { |
| 400 | /// # Returns | 569 | let (cmdl, cmdh) = match index { |
| 401 | /// Default conversion command configuration | 570 | 1 => (self.info.cmdl1(), self.info.cmdh1()), |
| 402 | pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { | 571 | 2 => (self.info.cmdl2(), self.info.cmdh2()), |
| 403 | ConvCommandConfig { | 572 | 3 => (self.info.cmdl3(), self.info.cmdh3()), |
| 404 | channel_number: Adch::SelectCh0, | 573 | 4 => (self.info.cmdl4(), self.info.cmdh4()), |
| 405 | chained_next_command_number: Next::NoNextCmdTerminateOnFinish, | 574 | 5 => (self.info.cmdl5(), self.info.cmdh5()), |
| 406 | enable_auto_channel_increment: false, | 575 | 6 => (self.info.cmdl6(), self.info.cmdh6()), |
| 407 | loop_count: 0, | 576 | 7 => (self.info.cmdl7(), self.info.cmdh7()), |
| 408 | hardware_average_mode: Avgs::NoAverage, | 577 | _ => return Err(Error::InvalidConfig), |
| 409 | sample_time_mode: Sts::Sample3p5, | 578 | }; |
| 410 | hardware_compare_mode: Cmpen::DisabledAlwaysStoreResult, | ||
| 411 | hardware_compare_value_high: 0, | ||
| 412 | hardware_compare_value_low: 0, | ||
| 413 | conversion_resolution_mode: Mode::Data12Bits, | ||
| 414 | enable_wait_trigger: false, | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | /// Set conversion command configuration. | ||
| 419 | /// | ||
| 420 | /// Configures a conversion command slot with the specified parameters. | ||
| 421 | /// Commands define how conversions are performed (channel, resolution, etc.). | ||
| 422 | /// | ||
| 423 | /// # Arguments | ||
| 424 | /// * `index` - Command index | ||
| 425 | /// * `config` - Command configuration | ||
| 426 | /// | ||
| 427 | /// # Returns | ||
| 428 | /// * `Ok(())` if the command was configured successfully | ||
| 429 | /// * `Err(Error::InvalidConfig)` if the index is out of range | ||
| 430 | pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) -> Result<()> { | ||
| 431 | let adc = I::ptr(); | ||
| 432 | |||
| 433 | if index < 1 || index > 7 { | ||
| 434 | return Err(Error::InvalidConfig); | ||
| 435 | } | ||
| 436 | 579 | ||
| 437 | macro_rules! write_cmd { | 580 | cmdl.write(|w| { |
| 438 | ($idx:expr) => {{ | 581 | unsafe { |
| 439 | paste! { | 582 | w.adch().bits(self.channel_idx); |
| 440 | adc.[<cmdl $idx>]().write(|w| { | 583 | } |
| 441 | w.adch() | 584 | w.mode().variant(config.conversion_resolution_mode) |
| 442 | .variant(config.channel_number) | 585 | }); |
| 443 | .mode() | ||
| 444 | .variant(config.conversion_resolution_mode) | ||
| 445 | }); | ||
| 446 | adc.[<cmdh $idx>]().write(|w| unsafe { | ||
| 447 | w.next() | ||
| 448 | .variant(config.chained_next_command_number) | ||
| 449 | .loop_() | ||
| 450 | .bits(config.loop_count) | ||
| 451 | .avgs() | ||
| 452 | .variant(config.hardware_average_mode) | ||
| 453 | .sts() | ||
| 454 | .variant(config.sample_time_mode) | ||
| 455 | .cmpen() | ||
| 456 | .variant(config.hardware_compare_mode) | ||
| 457 | .wait_trig() | ||
| 458 | .bit(config.enable_wait_trigger) | ||
| 459 | .lwi() | ||
| 460 | .bit(config.enable_auto_channel_increment) | ||
| 461 | }); | ||
| 462 | } | ||
| 463 | }}; | ||
| 464 | } | ||
| 465 | 586 | ||
| 466 | match index { | 587 | cmdh.write(|w| { |
| 467 | 1 => write_cmd!(1), | 588 | w.next().variant(config.chained_next_command_number); |
| 468 | 2 => write_cmd!(2), | 589 | unsafe { |
| 469 | 3 => write_cmd!(3), | 590 | w.loop_().bits(config.loop_count); |
| 470 | 4 => write_cmd!(4), | 591 | } |
| 471 | 5 => write_cmd!(5), | 592 | w.avgs().variant(config.hardware_average_mode); |
| 472 | 6 => write_cmd!(6), | 593 | w.sts().variant(config.sample_time_mode); |
| 473 | 7 => write_cmd!(7), | 594 | w.cmpen().variant(config.hardware_compare_mode); |
| 474 | _ => unreachable!(), | 595 | w.wait_trig().bit(config.enable_wait_trigger); |
| 475 | } | 596 | w.lwi().bit(config.enable_auto_channel_increment); |
| 597 | w | ||
| 598 | }); | ||
| 476 | 599 | ||
| 477 | Ok(()) | 600 | Ok(()) |
| 478 | } | 601 | } |
| 479 | 602 | ||
| 480 | /// Get default conversion trigger configuration. | 603 | fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { |
| 481 | /// | 604 | // 0..4 are valid |
| 482 | /// # Returns | 605 | if trigger_id >= 4 { |
| 483 | /// Default conversion trigger configuration | 606 | return Err(Error::InvalidConfig); |
| 484 | pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { | ||
| 485 | ConvTriggerConfig { | ||
| 486 | target_command_id: Tcmd::NotValid, | ||
| 487 | delay_power: 0, | ||
| 488 | priority: Tpri::HighestPriority, | ||
| 489 | enable_hardware_trigger: false, | ||
| 490 | } | 607 | } |
| 491 | } | ||
| 492 | 608 | ||
| 493 | /// Set conversion trigger configuration. | 609 | let tctrl = &self.info.tctrl(trigger_id); |
| 494 | /// | ||
| 495 | /// Configures a trigger to initiate conversions. Triggers can be | ||
| 496 | /// activated by software or hardware signals. | ||
| 497 | /// | ||
| 498 | /// # Arguments | ||
| 499 | /// * `trigger_id` - Trigger index (0-15) | ||
| 500 | /// * `config` - Trigger configuration | ||
| 501 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { | ||
| 502 | let adc = I::ptr(); | ||
| 503 | let tctrl = &adc.tctrl(trigger_id); | ||
| 504 | 610 | ||
| 505 | tctrl.write(|w| unsafe { | 611 | tctrl.write(|w| { |
| 506 | let w = w.tcmd().variant(config.target_command_id); | 612 | w.tcmd().variant(config.target_command_id); |
| 507 | let w = w.tdly().bits(config.delay_power); | 613 | unsafe { |
| 614 | w.tdly().bits(config.delay_power); | ||
| 615 | } | ||
| 508 | w.tpri().variant(config.priority); | 616 | w.tpri().variant(config.priority); |
| 509 | if config.enable_hardware_trigger { | 617 | if config.enable_hardware_trigger { |
| 510 | w.hten().enabled() | 618 | w.hten().enabled() |
| @@ -512,36 +620,8 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | |||
| 512 | w | 620 | w |
| 513 | } | 621 | } |
| 514 | }); | 622 | }); |
| 515 | } | ||
| 516 | 623 | ||
| 517 | /// Reset the FIFO buffer. | 624 | Ok(()) |
| 518 | /// | ||
| 519 | /// Clears all pending conversion results from the FIFO. | ||
| 520 | pub fn do_reset_fifo(&self) { | ||
| 521 | let adc = I::ptr(); | ||
| 522 | adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | ||
| 523 | } | ||
| 524 | |||
| 525 | /// Enable ADC interrupts. | ||
| 526 | /// | ||
| 527 | /// Enables the interrupt sources specified in the bitmask. | ||
| 528 | /// | ||
| 529 | /// # Arguments | ||
| 530 | /// * `mask` - Bitmask of interrupt sources to enable | ||
| 531 | pub fn enable_interrupt(&self, mask: u32) { | ||
| 532 | let adc = I::ptr(); | ||
| 533 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | ||
| 534 | } | ||
| 535 | |||
| 536 | /// Disable ADC interrupts. | ||
| 537 | /// | ||
| 538 | /// Disables the interrupt sources specified in the bitmask. | ||
| 539 | /// | ||
| 540 | /// # Arguments | ||
| 541 | /// * `mask` - Bitmask of interrupt sources to disable | ||
| 542 | pub fn disable_interrupt(&self, mask: u32) { | ||
| 543 | let adc = I::ptr(); | ||
| 544 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); | ||
| 545 | } | 625 | } |
| 546 | 626 | ||
| 547 | /// Get conversion result from FIFO. | 627 | /// Get conversion result from FIFO. |
| @@ -552,9 +632,8 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | |||
| 552 | /// # Returns | 632 | /// # Returns |
| 553 | /// - `Some(ConvResult)` if a result is available | 633 | /// - `Some(ConvResult)` if a result is available |
| 554 | /// - `Err(Error::FifoEmpty)` if the FIFO is empty | 634 | /// - `Err(Error::FifoEmpty)` if the FIFO is empty |
| 555 | pub fn get_conv_result(&self) -> Result<ConvResult> { | 635 | fn get_conv_result_inner(&self) -> Result<ConvResult> { |
| 556 | let adc = I::ptr(); | 636 | let fifo = self.info.resfifo0().read(); |
| 557 | let fifo = adc.resfifo0().read(); | ||
| 558 | if !fifo.valid().is_valid() { | 637 | if !fifo.valid().is_valid() { |
| 559 | return Err(Error::FifoEmpty); | 638 | return Err(Error::FifoEmpty); |
| 560 | } | 639 | } |
| @@ -570,7 +649,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | |||
| 570 | 649 | ||
| 571 | impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { | 650 | impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { |
| 572 | unsafe fn on_interrupt() { | 651 | unsafe fn on_interrupt() { |
| 573 | T::ptr().ie().modify(|r, w| w.bits(r.bits() & !0x1)); | 652 | T::ptr().ie().modify(|_r, w| w.fwmie0().clear_bit()); |
| 574 | T::wait_cell().wake(); | 653 | T::wait_cell().wake(); |
| 575 | } | 654 | } |
| 576 | } | 655 | } |
| @@ -621,6 +700,8 @@ macro_rules! impl_instance { | |||
| 621 | impl_instance!(0, 1, 2, 3); | 700 | impl_instance!(0, 1, 2, 3); |
| 622 | 701 | ||
| 623 | pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | 702 | pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { |
| 703 | const CHANNEL: u8; | ||
| 704 | |||
| 624 | /// Set the given pin to the correct muxing state | 705 | /// Set the given pin to the correct muxing state |
| 625 | fn mux(&self); | 706 | fn mux(&self); |
| 626 | } | 707 | } |
| @@ -635,13 +716,17 @@ impl sealed::Sealed for Blocking {} | |||
| 635 | impl ModeAdc for Blocking {} | 716 | impl ModeAdc for Blocking {} |
| 636 | 717 | ||
| 637 | /// Async mode. | 718 | /// Async mode. |
| 638 | pub struct Async; | 719 | pub struct Async { |
| 720 | waiter: &'static WaitCell, | ||
| 721 | } | ||
| 639 | impl sealed::Sealed for Async {} | 722 | impl sealed::Sealed for Async {} |
| 640 | impl ModeAdc for Async {} | 723 | impl ModeAdc for Async {} |
| 641 | 724 | ||
| 642 | macro_rules! impl_pin { | 725 | macro_rules! impl_pin { |
| 643 | ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { | 726 | ($pin:ident, $peri:ident, $func:ident, $channel:literal) => { |
| 644 | impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin { | 727 | impl AdcPin<crate::peripherals::$peri> for crate::peripherals::$pin { |
| 728 | const CHANNEL: u8 = $channel; | ||
| 729 | |||
| 645 | fn mux(&self) { | 730 | fn mux(&self) { |
| 646 | self.set_pull(crate::gpio::Pull::Disabled); | 731 | self.set_pull(crate::gpio::Pull::Disabled); |
| 647 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | 732 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); |
| @@ -652,101 +737,113 @@ macro_rules! impl_pin { | |||
| 652 | }; | 737 | }; |
| 653 | } | 738 | } |
| 654 | 739 | ||
| 655 | impl_pin!(P2_0, ADC0, Mux0, AdcPin); | 740 | impl_pin!(P2_0, ADC0, Mux0, 0); |
| 656 | impl_pin!(P2_4, ADC0, Mux0, AdcPin); | 741 | impl_pin!(P2_4, ADC0, Mux0, 1); |
| 657 | impl_pin!(P2_15, ADC0, Mux0, AdcPin); | 742 | impl_pin!(P2_15, ADC0, Mux0, 2); |
| 658 | impl_pin!(P2_3, ADC0, Mux0, AdcPin); | 743 | impl_pin!(P2_3, ADC0, Mux0, 3); |
| 659 | impl_pin!(P2_2, ADC0, Mux0, AdcPin); | 744 | impl_pin!(P2_2, ADC0, Mux0, 4); |
| 660 | impl_pin!(P2_12, ADC0, Mux0, AdcPin); | 745 | impl_pin!(P2_12, ADC0, Mux0, 5); |
| 661 | impl_pin!(P2_16, ADC0, Mux0, AdcPin); | 746 | impl_pin!(P2_16, ADC0, Mux0, 6); |
| 662 | impl_pin!(P2_7, ADC0, Mux0, AdcPin); | 747 | impl_pin!(P2_7, ADC0, Mux0, 7); |
| 663 | impl_pin!(P0_18, ADC0, Mux0, AdcPin); | 748 | impl_pin!(P0_18, ADC0, Mux0, 8); |
| 664 | impl_pin!(P0_19, ADC0, Mux0, AdcPin); | 749 | impl_pin!(P0_19, ADC0, Mux0, 9); |
| 665 | impl_pin!(P0_20, ADC0, Mux0, AdcPin); | 750 | impl_pin!(P0_20, ADC0, Mux0, 10); |
| 666 | impl_pin!(P0_21, ADC0, Mux0, AdcPin); | 751 | impl_pin!(P0_21, ADC0, Mux0, 11); |
| 667 | impl_pin!(P0_22, ADC0, Mux0, AdcPin); | 752 | impl_pin!(P0_22, ADC0, Mux0, 12); |
| 668 | impl_pin!(P0_23, ADC0, Mux0, AdcPin); | 753 | impl_pin!(P0_23, ADC0, Mux0, 13); |
| 669 | impl_pin!(P0_3, ADC0, Mux0, AdcPin); | 754 | impl_pin!(P0_3, ADC0, Mux0, 14); |
| 670 | impl_pin!(P0_6, ADC0, Mux0, AdcPin); | 755 | impl_pin!(P0_6, ADC0, Mux0, 15); |
| 671 | impl_pin!(P1_0, ADC0, Mux0, AdcPin); | 756 | impl_pin!(P1_0, ADC0, Mux0, 16); |
| 672 | impl_pin!(P1_1, ADC0, Mux0, AdcPin); | 757 | impl_pin!(P1_1, ADC0, Mux0, 17); |
| 673 | impl_pin!(P1_2, ADC0, Mux0, AdcPin); | 758 | impl_pin!(P1_2, ADC0, Mux0, 18); |
| 674 | impl_pin!(P1_3, ADC0, Mux0, AdcPin); | 759 | impl_pin!(P1_3, ADC0, Mux0, 19); |
| 675 | impl_pin!(P1_4, ADC0, Mux0, AdcPin); | 760 | impl_pin!(P1_4, ADC0, Mux0, 20); |
| 676 | impl_pin!(P1_5, ADC0, Mux0, AdcPin); | 761 | impl_pin!(P1_5, ADC0, Mux0, 21); |
| 677 | impl_pin!(P1_6, ADC0, Mux0, AdcPin); | 762 | impl_pin!(P1_6, ADC0, Mux0, 22); |
| 678 | impl_pin!(P1_7, ADC0, Mux0, AdcPin); | 763 | impl_pin!(P1_7, ADC0, Mux0, 23); |
| 679 | impl_pin!(P1_10, ADC0, Mux0, AdcPin); | 764 | |
| 680 | 765 | // ??? | |
| 681 | impl_pin!(P2_1, ADC1, Mux0, AdcPin); | 766 | // impl_pin!(P1_10, ADC0, Mux0, 255); |
| 682 | impl_pin!(P2_5, ADC1, Mux0, AdcPin); | 767 | |
| 683 | impl_pin!(P2_19, ADC1, Mux0, AdcPin); | 768 | impl_pin!(P2_1, ADC1, Mux0, 0); |
| 684 | impl_pin!(P2_6, ADC1, Mux0, AdcPin); | 769 | impl_pin!(P2_5, ADC1, Mux0, 1); |
| 685 | impl_pin!(P2_3, ADC1, Mux0, AdcPin); | 770 | impl_pin!(P2_19, ADC1, Mux0, 2); |
| 686 | impl_pin!(P2_13, ADC1, Mux0, AdcPin); | 771 | impl_pin!(P2_6, ADC1, Mux0, 3); |
| 687 | impl_pin!(P2_17, ADC1, Mux0, AdcPin); | 772 | impl_pin!(P2_3, ADC1, Mux0, 4); |
| 688 | impl_pin!(P2_7, ADC1, Mux0, AdcPin); | 773 | impl_pin!(P2_13, ADC1, Mux0, 5); |
| 689 | impl_pin!(P1_10, ADC1, Mux0, AdcPin); | 774 | impl_pin!(P2_17, ADC1, Mux0, 6); |
| 690 | impl_pin!(P1_11, ADC1, Mux0, AdcPin); | 775 | impl_pin!(P2_7, ADC1, Mux0, 7); |
| 691 | impl_pin!(P1_12, ADC1, Mux0, AdcPin); | 776 | impl_pin!(P1_10, ADC1, Mux0, 8); |
| 692 | impl_pin!(P1_13, ADC1, Mux0, AdcPin); | 777 | impl_pin!(P1_11, ADC1, Mux0, 9); |
| 693 | impl_pin!(P1_14, ADC1, Mux0, AdcPin); | 778 | impl_pin!(P1_12, ADC1, Mux0, 10); |
| 694 | impl_pin!(P1_15, ADC1, Mux0, AdcPin); | 779 | impl_pin!(P1_13, ADC1, Mux0, 11); |
| 695 | impl_pin!(P1_16, ADC1, Mux0, AdcPin); | 780 | impl_pin!(P1_14, ADC1, Mux0, 12); |
| 696 | impl_pin!(P1_17, ADC1, Mux0, AdcPin); | 781 | impl_pin!(P1_15, ADC1, Mux0, 13); |
| 697 | impl_pin!(P1_18, ADC1, Mux0, AdcPin); | 782 | // ??? |
| 698 | impl_pin!(P1_19, ADC1, Mux0, AdcPin); | 783 | // impl_pin!(P1_16, ADC1, Mux0, 255); |
| 699 | impl_pin!(P3_31, ADC1, Mux0, AdcPin); | 784 | // impl_pin!(P1_17, ADC1, Mux0, 255); |
| 700 | impl_pin!(P3_30, ADC1, Mux0, AdcPin); | 785 | // impl_pin!(P1_18, ADC1, Mux0, 255); |
| 701 | impl_pin!(P3_29, ADC1, Mux0, AdcPin); | 786 | // impl_pin!(P1_19, ADC1, Mux0, 255); |
| 702 | 787 | // ??? | |
| 703 | impl_pin!(P2_4, ADC2, Mux0, AdcPin); | 788 | impl_pin!(P3_31, ADC1, Mux0, 20); |
| 704 | impl_pin!(P2_10, ADC2, Mux0, AdcPin); | 789 | impl_pin!(P3_30, ADC1, Mux0, 21); |
| 705 | impl_pin!(P4_4, ADC2, Mux0, AdcPin); | 790 | impl_pin!(P3_29, ADC1, Mux0, 22); |
| 706 | impl_pin!(P2_24, ADC2, Mux0, AdcPin); | 791 | |
| 707 | impl_pin!(P2_16, ADC2, Mux0, AdcPin); | 792 | impl_pin!(P2_4, ADC2, Mux0, 0); |
| 708 | impl_pin!(P2_12, ADC2, Mux0, AdcPin); | 793 | impl_pin!(P2_10, ADC2, Mux0, 1); |
| 709 | impl_pin!(P2_20, ADC2, Mux0, AdcPin); | 794 | impl_pin!(P4_4, ADC2, Mux0, 2); |
| 710 | impl_pin!(P2_7, ADC2, Mux0, AdcPin); | 795 | // impl_pin!(P2_24, ADC2, Mux0, 255); ??? |
| 711 | impl_pin!(P0_2, ADC2, Mux0, AdcPin); | 796 | impl_pin!(P2_16, ADC2, Mux0, 4); |
| 712 | impl_pin!(P0_4, ADC2, Mux0, AdcPin); | 797 | impl_pin!(P2_12, ADC2, Mux0, 5); |
| 713 | impl_pin!(P0_5, ADC2, Mux0, AdcPin); | 798 | impl_pin!(P2_20, ADC2, Mux0, 6); |
| 714 | impl_pin!(P0_6, ADC2, Mux0, AdcPin); | 799 | impl_pin!(P2_7, ADC2, Mux0, 7); |
| 715 | impl_pin!(P0_7, ADC2, Mux0, AdcPin); | 800 | impl_pin!(P0_2, ADC2, Mux0, 8); |
| 716 | impl_pin!(P0_12, ADC2, Mux0, AdcPin); | 801 | // ??? |
| 717 | impl_pin!(P0_13, ADC2, Mux0, AdcPin); | 802 | // impl_pin!(P0_4, ADC2, Mux0, 255); |
| 718 | impl_pin!(P0_14, ADC2, Mux0, AdcPin); | 803 | // impl_pin!(P0_5, ADC2, Mux0, 255); |
| 719 | impl_pin!(P0_15, ADC2, Mux0, AdcPin); | 804 | // impl_pin!(P0_6, ADC2, Mux0, 255); |
| 720 | impl_pin!(P4_0, ADC2, Mux0, AdcPin); | 805 | // impl_pin!(P0_7, ADC2, Mux0, 255); |
| 721 | impl_pin!(P4_1, ADC2, Mux0, AdcPin); | 806 | // impl_pin!(P0_12, ADC2, Mux0, 255); |
| 722 | impl_pin!(P4_2, ADC2, Mux0, AdcPin); | 807 | // impl_pin!(P0_13, ADC2, Mux0, 255); |
| 723 | impl_pin!(P4_3, ADC2, Mux0, AdcPin); | 808 | // ??? |
| 724 | //impl_pin!(P4_4, ADC2, Mux0, AdcPin); // Conflit with ADC2_A3 and ADC2_A20 using the same pin | 809 | impl_pin!(P0_14, ADC2, Mux0, 14); |
| 725 | impl_pin!(P4_5, ADC2, Mux0, AdcPin); | 810 | impl_pin!(P0_15, ADC2, Mux0, 15); |
| 726 | impl_pin!(P4_6, ADC2, Mux0, AdcPin); | 811 | // ??? |
| 727 | impl_pin!(P4_7, ADC2, Mux0, AdcPin); | 812 | // impl_pin!(P4_0, ADC2, Mux0, 255); |
| 728 | 813 | // impl_pin!(P4_1, ADC2, Mux0, 255); | |
| 729 | impl_pin!(P2_5, ADC3, Mux0, AdcPin); | 814 | // ??? |
| 730 | impl_pin!(P2_11, ADC3, Mux0, AdcPin); | 815 | impl_pin!(P4_2, ADC2, Mux0, 18); |
| 731 | impl_pin!(P2_23, ADC3, Mux0, AdcPin); | 816 | impl_pin!(P4_3, ADC2, Mux0, 19); |
| 732 | impl_pin!(P2_25, ADC3, Mux0, AdcPin); | 817 | //impl_pin!(P4_4, ADC2, Mux0, 20); // Conflit with ADC2_A3 and ADC2_A20 using the same pin |
| 733 | impl_pin!(P2_17, ADC3, Mux0, AdcPin); | 818 | impl_pin!(P4_5, ADC2, Mux0, 21); |
| 734 | impl_pin!(P2_13, ADC3, Mux0, AdcPin); | 819 | impl_pin!(P4_6, ADC2, Mux0, 22); |
| 735 | impl_pin!(P2_21, ADC3, Mux0, AdcPin); | 820 | impl_pin!(P4_7, ADC2, Mux0, 23); |
| 736 | impl_pin!(P2_7, ADC3, Mux0, AdcPin); | 821 | |
| 737 | impl_pin!(P3_2, ADC3, Mux0, AdcPin); | 822 | impl_pin!(P2_5, ADC3, Mux0, 0); |
| 738 | impl_pin!(P3_3, ADC3, Mux0, AdcPin); | 823 | impl_pin!(P2_11, ADC3, Mux0, 1); |
| 739 | impl_pin!(P3_4, ADC3, Mux0, AdcPin); | 824 | impl_pin!(P2_23, ADC3, Mux0, 2); |
| 740 | impl_pin!(P3_5, ADC3, Mux0, AdcPin); | 825 | // impl_pin!(P2_25, ADC3, Mux0, 255); // ??? |
| 741 | impl_pin!(P3_6, ADC3, Mux0, AdcPin); | 826 | impl_pin!(P2_17, ADC3, Mux0, 4); |
| 742 | impl_pin!(P3_7, ADC3, Mux0, AdcPin); | 827 | impl_pin!(P2_13, ADC3, Mux0, 5); |
| 743 | impl_pin!(P3_12, ADC3, Mux0, AdcPin); | 828 | impl_pin!(P2_21, ADC3, Mux0, 6); |
| 744 | impl_pin!(P3_13, ADC3, Mux0, AdcPin); | 829 | impl_pin!(P2_7, ADC3, Mux0, 7); |
| 745 | impl_pin!(P3_14, ADC3, Mux0, AdcPin); | 830 | // ??? |
| 746 | impl_pin!(P3_15, ADC3, Mux0, AdcPin); | 831 | // impl_pin!(P3_2, ADC3, Mux0, 255); |
| 747 | impl_pin!(P3_20, ADC3, Mux0, AdcPin); | 832 | // impl_pin!(P3_3, ADC3, Mux0, 255); |
| 748 | impl_pin!(P3_21, ADC3, Mux0, AdcPin); | 833 | // impl_pin!(P3_4, ADC3, Mux0, 255); |
| 749 | impl_pin!(P3_22, ADC3, Mux0, AdcPin); | 834 | // impl_pin!(P3_5, ADC3, Mux0, 255); |
| 750 | impl_pin!(P3_23, ADC3, Mux0, AdcPin); | 835 | // ??? |
| 751 | impl_pin!(P3_24, ADC3, Mux0, AdcPin); | 836 | impl_pin!(P3_6, ADC3, Mux0, 12); |
| 752 | impl_pin!(P3_25, ADC3, Mux0, AdcPin); | 837 | impl_pin!(P3_7, ADC3, Mux0, 13); |
| 838 | impl_pin!(P3_12, ADC3, Mux0, 14); | ||
| 839 | impl_pin!(P3_13, ADC3, Mux0, 15); | ||
| 840 | impl_pin!(P3_14, ADC3, Mux0, 16); | ||
| 841 | impl_pin!(P3_15, ADC3, Mux0, 17); | ||
| 842 | impl_pin!(P3_20, ADC3, Mux0, 18); | ||
| 843 | impl_pin!(P3_21, ADC3, Mux0, 19); | ||
| 844 | impl_pin!(P3_22, ADC3, Mux0, 20); | ||
| 845 | // ??? | ||
| 846 | // impl_pin!(P3_23, ADC3, Mux0, 255); | ||
| 847 | // impl_pin!(P3_24, ADC3, Mux0, 255); | ||
| 848 | // impl_pin!(P3_25, ADC3, Mux0, 255); | ||
| 849 | // ??? | ||
diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs index 5876923a1..d2cda631c 100644 --- a/examples/mcxa/src/bin/adc_interrupt.rs +++ b/examples/mcxa/src/bin/adc_interrupt.rs | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_time::{Duration, Ticker}; | ||
| 5 | use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy}; | 6 | use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy}; |
| 6 | use hal::bind_interrupts; | 7 | use hal::bind_interrupts; |
| 7 | use hal::clocks::PoweredClock; | 8 | use hal::clocks::PoweredClock; |
| @@ -9,9 +10,8 @@ use hal::clocks::config::Div8; | |||
| 9 | use hal::clocks::periph_helpers::{AdcClockSel, Div4}; | 10 | use hal::clocks::periph_helpers::{AdcClockSel, Div4}; |
| 10 | use hal::config::Config; | 11 | use hal::config::Config; |
| 11 | use hal::pac::adc1::cfg::{Pwrsel, Refsel}; | 12 | use hal::pac::adc1::cfg::{Pwrsel, Refsel}; |
| 12 | use hal::pac::adc1::cmdl1::{Adch, Mode}; | 13 | use hal::pac::adc1::cmdl1::Mode; |
| 13 | use hal::pac::adc1::ctrl::CalAvgs; | 14 | use hal::pac::adc1::ctrl::CalAvgs; |
| 14 | use hal::pac::adc1::tctrl::Tcmd; | ||
| 15 | use hal::peripherals::ADC1; | 15 | use hal::peripherals::ADC1; |
| 16 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | 16 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; |
| 17 | 17 | ||
| @@ -38,7 +38,6 @@ async fn main(_spawner: Spawner) { | |||
| 38 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | 38 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, |
| 39 | enable_conv_pause: false, | 39 | enable_conv_pause: false, |
| 40 | conv_pause_delay: 0, | 40 | conv_pause_delay: 0, |
| 41 | fifo_watermark: 0, | ||
| 42 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | 41 | power: PoweredClock::NormalEnabledDeepSleepDisabled, |
| 43 | source: AdcClockSel::FroLfDiv, | 42 | source: AdcClockSel::FroLfDiv, |
| 44 | div: Div4::no_div(), | 43 | div: Div4::no_div(), |
| @@ -47,23 +46,16 @@ async fn main(_spawner: Spawner) { | |||
| 47 | 46 | ||
| 48 | adc.do_offset_calibration(); | 47 | adc.do_offset_calibration(); |
| 49 | adc.do_auto_calibration(); | 48 | adc.do_auto_calibration(); |
| 50 | 49 | adc.set_resolution(Mode::Data16Bits); | |
| 51 | let mut conv_command_config = adc.get_default_conv_command_config(); | ||
| 52 | conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; | ||
| 53 | conv_command_config.conversion_resolution_mode = Mode::Data16Bits; | ||
| 54 | adc.set_conv_command_config(1, &conv_command_config).unwrap(); | ||
| 55 | |||
| 56 | let mut conv_trigger_config = adc.get_default_conv_trigger_config(); | ||
| 57 | conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; | ||
| 58 | conv_trigger_config.enable_hardware_trigger = false; | ||
| 59 | adc.set_conv_trigger_config(0, &conv_trigger_config); | ||
| 60 | 50 | ||
| 61 | defmt::info!("ADC configuration done..."); | 51 | defmt::info!("ADC configuration done..."); |
| 52 | let mut ticker = Ticker::every(Duration::from_millis(100)); | ||
| 62 | 53 | ||
| 63 | loop { | 54 | loop { |
| 55 | ticker.next().await; | ||
| 64 | match adc.read().await { | 56 | match adc.read().await { |
| 65 | Ok(value) => { | 57 | Ok(value) => { |
| 66 | defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value); | 58 | defmt::info!("ADC value: {}", value); |
| 67 | } | 59 | } |
| 68 | Err(e) => { | 60 | Err(e) => { |
| 69 | defmt::error!("ADC read error: {:?}", e); | 61 | defmt::error!("ADC read error: {:?}", e); |
diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs index d048bb56f..5c4d5524c 100644 --- a/examples/mcxa/src/bin/adc_polling.rs +++ b/examples/mcxa/src/bin/adc_polling.rs | |||
| @@ -2,13 +2,15 @@ | |||
| 2 | #![no_main] | 2 | #![no_main] |
| 3 | 3 | ||
| 4 | use embassy_executor::Spawner; | 4 | use embassy_executor::Spawner; |
| 5 | use embassy_mcxa::adc::{ConvCommandConfig, ConvTriggerConfig}; | ||
| 6 | use embassy_time::{Duration, Ticker}; | ||
| 5 | use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy}; | 7 | use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy}; |
| 6 | use hal::clocks::PoweredClock; | 8 | use hal::clocks::PoweredClock; |
| 7 | use hal::clocks::config::Div8; | 9 | use hal::clocks::config::Div8; |
| 8 | use hal::clocks::periph_helpers::{AdcClockSel, Div4}; | 10 | use hal::clocks::periph_helpers::{AdcClockSel, Div4}; |
| 9 | use hal::config::Config; | 11 | use hal::config::Config; |
| 10 | use hal::pac::adc1::cfg::{Pwrsel, Refsel}; | 12 | use hal::pac::adc1::cfg::{Pwrsel, Refsel}; |
| 11 | use hal::pac::adc1::cmdl1::{Adch, Mode}; | 13 | use hal::pac::adc1::cmdl1::Mode; |
| 12 | use hal::pac::adc1::ctrl::CalAvgs; | 14 | use hal::pac::adc1::ctrl::CalAvgs; |
| 13 | use hal::pac::adc1::tctrl::Tcmd; | 15 | use hal::pac::adc1::tctrl::Tcmd; |
| 14 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; | 16 | use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; |
| @@ -34,7 +36,6 @@ async fn main(_spawner: Spawner) { | |||
| 34 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, | 36 | trigger_priority_policy: TriggerPriorityPolicy::ConvPreemptImmediatelyNotAutoResumed, |
| 35 | enable_conv_pause: false, | 37 | enable_conv_pause: false, |
| 36 | conv_pause_delay: 0, | 38 | conv_pause_delay: 0, |
| 37 | fifo_watermark: 0, | ||
| 38 | power: PoweredClock::NormalEnabledDeepSleepDisabled, | 39 | power: PoweredClock::NormalEnabledDeepSleepDisabled, |
| 39 | source: AdcClockSel::FroLfDiv, | 40 | source: AdcClockSel::FroLfDiv, |
| 40 | div: Div4::no_div(), | 41 | div: Div4::no_div(), |
| @@ -44,20 +45,25 @@ async fn main(_spawner: Spawner) { | |||
| 44 | adc.do_offset_calibration(); | 45 | adc.do_offset_calibration(); |
| 45 | adc.do_auto_calibration(); | 46 | adc.do_auto_calibration(); |
| 46 | 47 | ||
| 47 | let mut conv_command_config = adc.get_default_conv_command_config(); | 48 | let conv_command_config = ConvCommandConfig { |
| 48 | conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; | 49 | conversion_resolution_mode: Mode::Data16Bits, |
| 49 | conv_command_config.conversion_resolution_mode = Mode::Data16Bits; | 50 | ..ConvCommandConfig::default() |
| 51 | }; | ||
| 50 | adc.set_conv_command_config(1, &conv_command_config).unwrap(); | 52 | adc.set_conv_command_config(1, &conv_command_config).unwrap(); |
| 51 | 53 | ||
| 52 | let mut conv_trigger_config = adc.get_default_conv_trigger_config(); | 54 | let conv_trigger_config = ConvTriggerConfig { |
| 53 | conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; | 55 | target_command_id: Tcmd::ExecuteCmd1, |
| 54 | conv_trigger_config.enable_hardware_trigger = false; | 56 | enable_hardware_trigger: false, |
| 55 | adc.set_conv_trigger_config(0, &conv_trigger_config); | 57 | ..Default::default() |
| 58 | }; | ||
| 59 | adc.set_conv_trigger_config(0, &conv_trigger_config).unwrap(); | ||
| 56 | 60 | ||
| 57 | defmt::info!("=== ADC configuration done... ==="); | 61 | defmt::info!("=== ADC configuration done... ==="); |
| 62 | let mut tick = Ticker::every(Duration::from_millis(100)); | ||
| 58 | 63 | ||
| 59 | loop { | 64 | loop { |
| 60 | adc.do_software_trigger(1); | 65 | tick.next().await; |
| 66 | adc.do_software_trigger(1).unwrap(); | ||
| 61 | let result = loop { | 67 | let result = loop { |
| 62 | match adc.get_conv_result() { | 68 | match adc.get_conv_result() { |
| 63 | Ok(res) => break res, | 69 | Ok(res) => break res, |
