diff options
| author | Mathis Deroo <[email protected]> | 2025-12-05 14:37:19 -0800 |
|---|---|---|
| committer | Mathis Deroo <[email protected]> | 2025-12-09 10:51:55 -0800 |
| commit | 1ccf45058db4e77ac2c59357cab196b659201b63 (patch) | |
| tree | bfe1fa9c96db00b8551e44a67d4ecf65139d7061 /embassy-mcxa | |
| parent | 23623d634b88da7bc398f092ac4ab9e571c6e6e1 (diff) | |
ADC driver improvement
Signed-off-by: Mathis Deroo <[email protected]>
Diffstat (limited to 'embassy-mcxa')
| -rw-r--r-- | embassy-mcxa/src/adc.rs | 429 | ||||
| -rw-r--r-- | embassy-mcxa/src/clocks/mod.rs | 3 | ||||
| -rw-r--r-- | embassy-mcxa/src/clocks/periph_helpers.rs | 1 | ||||
| -rw-r--r-- | embassy-mcxa/src/interrupt.rs | 122 | ||||
| -rw-r--r-- | embassy-mcxa/src/lib.rs | 10 | ||||
| -rw-r--r-- | embassy-mcxa/src/pins.rs | 33 |
6 files changed, 497 insertions, 101 deletions
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs index 7475299ba..2e2fb0342 100644 --- a/embassy-mcxa/src/adc.rs +++ b/embassy-mcxa/src/adc.rs | |||
| @@ -1,42 +1,29 @@ | |||
| 1 | //! ADC driver | 1 | //! ADC driver |
| 2 | use core::sync::atomic::{AtomicBool, Ordering}; | 2 | use core::marker::PhantomData; |
| 3 | 3 | ||
| 4 | use embassy_hal_internal::{Peri, PeripheralType}; | 4 | use embassy_hal_internal::{Peri, PeripheralType}; |
| 5 | 5 | ||
| 6 | use paste::paste; | ||
| 7 | use crate::pac; | ||
| 8 | use crate::interrupt::typelevel::{Handler, Interrupt}; | ||
| 9 | use crate::gpio::{GpioPin, SealedPin}; | ||
| 10 | use maitake_sync::WaitCell; | ||
| 11 | |||
| 6 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; | 12 | use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; |
| 7 | use crate::clocks::{Gate, PoweredClock, enable_and_reset}; | 13 | use crate::clocks::{Gate, PoweredClock, enable_and_reset}; |
| 8 | use crate::pac; | 14 | |
| 9 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; | 15 | use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; |
| 10 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; | 16 | use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; |
| 11 | use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; | 17 | use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; |
| 12 | use crate::pac::adc1::ctrl::CalAvgs; | 18 | use crate::pac::adc1::ctrl::CalAvgs; |
| 13 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; | 19 | use crate::pac::adc1::tctrl::{Tcmd, Tpri}; |
| 14 | 20 | ||
| 15 | type Regs = pac::adc1::RegisterBlock; | 21 | /// Global wait cell for alarm notifications |
| 22 | static WAKER: WaitCell = WaitCell::new(); | ||
| 16 | 23 | ||
| 17 | static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false); | 24 | const G_LPADC_RESULT_SHIFT: u32 = 0; |
| 18 | // Token-based instance pattern like embassy-imxrt | ||
| 19 | pub trait Instance: Gate<MrccPeriphConfig = AdcConfig> + PeripheralType { | ||
| 20 | fn ptr() -> *const Regs; | ||
| 21 | } | ||
| 22 | |||
| 23 | /// Token for ADC1 | ||
| 24 | pub type Adc1 = crate::peripherals::ADC1; | ||
| 25 | impl Instance for crate::peripherals::ADC1 { | ||
| 26 | #[inline(always)] | ||
| 27 | fn ptr() -> *const Regs { | ||
| 28 | pac::Adc1::ptr() | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | // Also implement Instance for the Peri wrapper type | ||
| 33 | // impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::ADC1> { | ||
| 34 | // #[inline(always)] | ||
| 35 | // fn ptr() -> *const Regs { | ||
| 36 | // pac::Adc1::ptr() | ||
| 37 | // } | ||
| 38 | // } | ||
| 39 | 25 | ||
| 26 | /// Trigger priority policy for ADC conversions. | ||
| 40 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 27 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 41 | #[repr(u8)] | 28 | #[repr(u8)] |
| 42 | pub enum TriggerPriorityPolicy { | 29 | pub enum TriggerPriorityPolicy { |
| @@ -52,20 +39,40 @@ pub enum TriggerPriorityPolicy { | |||
| 52 | TriggerPriorityExceptionDisabled = 16, | 39 | TriggerPriorityExceptionDisabled = 16, |
| 53 | } | 40 | } |
| 54 | 41 | ||
| 42 | /// Configuration for the LPADC peripheral. | ||
| 55 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 43 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 56 | pub struct LpadcConfig { | 44 | pub struct LpadcConfig { |
| 45 | /// Control system transition to Stop and Wait power modes while ADC is converting. | ||
| 46 | /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed. | ||
| 47 | /// When disabled, the ADC will wait for the current averaging iteration/FIFO storage to complete before acknowledging stop or wait mode entry. | ||
| 57 | pub enable_in_doze_mode: bool, | 48 | pub enable_in_doze_mode: bool, |
| 49 | /// Auto-Calibration Averages. | ||
| 58 | pub conversion_average_mode: CalAvgs, | 50 | pub conversion_average_mode: CalAvgs, |
| 51 | /// ADC analog circuits are pre-enabled and ready to execute conversions without startup delays(at the cost of higher DC current consumption). | ||
| 59 | pub enable_analog_preliminary: bool, | 52 | pub enable_analog_preliminary: bool, |
| 53 | /// Power-up delay value (in ADC clock cycles) | ||
| 60 | pub power_up_delay: u8, | 54 | pub power_up_delay: u8, |
| 55 | /// Reference voltage source selection | ||
| 61 | pub reference_voltage_source: Refsel, | 56 | pub reference_voltage_source: Refsel, |
| 57 | /// Power configuration selection. | ||
| 62 | pub power_level_mode: Pwrsel, | 58 | pub power_level_mode: Pwrsel, |
| 59 | /// Trigger priority policy for handling multiple triggers | ||
| 63 | pub trigger_priority_policy: TriggerPriorityPolicy, | 60 | pub trigger_priority_policy: TriggerPriorityPolicy, |
| 61 | /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations, | ||
| 62 | /// between commands in a sequence, and between conversions when command is executing in "Compare Until True" configuration. | ||
| 64 | pub enable_conv_pause: bool, | 63 | pub enable_conv_pause: bool, |
| 64 | /// Controls the duration of pausing during command execution sequencing. The pause delay is a count of (convPauseDelay*4) ADCK cycles. | ||
| 65 | /// Only available when ADC pausing function is enabled. The available value range is in 9-bit. | ||
| 65 | pub conv_pause_delay: u16, | 66 | pub conv_pause_delay: u16, |
| 67 | /// FIFO watermark level for interrupt generation. | ||
| 68 | /// When the number of datawords stored in the ADC Result FIFO is greater than the value in this field, | ||
| 69 | /// the ready flag would be asserted to indicate stored data has reached the programmable threshold. | ||
| 66 | pub fifo_watermark: u8, | 70 | pub fifo_watermark: u8, |
| 71 | /// Power configuration (normal/deep sleep behavior) | ||
| 67 | pub power: PoweredClock, | 72 | pub power: PoweredClock, |
| 73 | /// ADC clock source selection | ||
| 68 | pub source: AdcClockSel, | 74 | pub source: AdcClockSel, |
| 75 | /// Clock divider for ADC clock | ||
| 69 | pub div: Div4, | 76 | pub div: Div4, |
| 70 | } | 77 | } |
| 71 | 78 | ||
| @@ -89,6 +96,9 @@ impl Default for LpadcConfig { | |||
| 89 | } | 96 | } |
| 90 | } | 97 | } |
| 91 | 98 | ||
| 99 | /// Configuration for a conversion command. | ||
| 100 | /// | ||
| 101 | /// Defines the parameters for a single ADC conversion operation. | ||
| 92 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 102 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 93 | pub struct ConvCommandConfig { | 103 | pub struct ConvCommandConfig { |
| 94 | pub sample_channel_mode: Ctype, | 104 | pub sample_channel_mode: Ctype, |
| @@ -105,6 +115,10 @@ pub struct ConvCommandConfig { | |||
| 105 | pub enable_wait_trigger: bool, | 115 | pub enable_wait_trigger: bool, |
| 106 | } | 116 | } |
| 107 | 117 | ||
| 118 | |||
| 119 | /// Configuration for a conversion trigger. | ||
| 120 | /// | ||
| 121 | /// Defines how a trigger initiates ADC conversions. | ||
| 108 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 122 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 109 | pub struct ConvTriggerConfig { | 123 | pub struct ConvTriggerConfig { |
| 110 | pub target_command_id: Tcmd, | 124 | pub target_command_id: Tcmd, |
| @@ -113,6 +127,9 @@ pub struct ConvTriggerConfig { | |||
| 113 | pub enable_hardware_trigger: bool, | 127 | pub enable_hardware_trigger: bool, |
| 114 | } | 128 | } |
| 115 | 129 | ||
| 130 | /// Result of an ADC conversion. | ||
| 131 | /// | ||
| 132 | /// Contains the conversion value and metadata about the conversion. | ||
| 116 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 133 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 117 | pub struct ConvResult { | 134 | pub struct ConvResult { |
| 118 | pub command_id_source: u32, | 135 | pub command_id_source: u32, |
| @@ -121,14 +138,59 @@ pub struct ConvResult { | |||
| 121 | pub conv_value: u16, | 138 | pub conv_value: u16, |
| 122 | } | 139 | } |
| 123 | 140 | ||
| 141 | /// ADC interrupt handler. | ||
| 142 | pub struct InterruptHandler<I: Instance> { | ||
| 143 | _phantom: PhantomData<I>, | ||
| 144 | } | ||
| 145 | |||
| 146 | /// ADC driver instance. | ||
| 124 | pub struct Adc<'a, I: Instance> { | 147 | pub struct Adc<'a, I: Instance> { |
| 125 | _inst: core::marker::PhantomData<&'a mut I>, | 148 | _inst: PhantomData<&'a mut I>, |
| 126 | } | 149 | } |
| 127 | 150 | ||
| 128 | impl<'a, I: Instance> Adc<'a, I> { | 151 | impl<'a, I: Instance> Adc<'a, I> { |
| 129 | /// initialize ADC | 152 | /// Initialize ADC with interrupt support. |
| 130 | pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { | 153 | /// |
| 131 | let adc = unsafe { &*I::ptr() }; | 154 | /// # Arguments |
| 155 | /// * `_inst` - ADC peripheral instance | ||
| 156 | /// * `pin` - GPIO pin to use for ADC | ||
| 157 | /// * `_irq` - Interrupt binding for this ADC instance | ||
| 158 | /// * `config` - ADC configuration | ||
| 159 | pub fn new( | ||
| 160 | _inst: Peri<'a, I>, | ||
| 161 | pin: Peri<'a, impl AdcPin<I>>, | ||
| 162 | _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, | ||
| 163 | config: LpadcConfig, | ||
| 164 | ) -> Self { | ||
| 165 | let adc = Self::new_inner(_inst, pin, config); | ||
| 166 | |||
| 167 | I::Interrupt::unpend(); | ||
| 168 | unsafe { I::Interrupt::enable() }; | ||
| 169 | |||
| 170 | adc | ||
| 171 | } | ||
| 172 | |||
| 173 | /// Initialize ADC without interrupt support (for polling mode). | ||
| 174 | /// | ||
| 175 | /// # Arguments | ||
| 176 | /// * `_inst` - ADC peripheral instance | ||
| 177 | /// * `pin` - GPIO pin to use for ADC input | ||
| 178 | /// * `config` - ADC configuration | ||
| 179 | pub fn new_polling( | ||
| 180 | _inst: Peri<'a, I>, | ||
| 181 | pin: Peri<'a, impl AdcPin<I>>, | ||
| 182 | config: LpadcConfig, | ||
| 183 | ) -> Self { | ||
| 184 | Self::new_inner(_inst, pin, config) | ||
| 185 | } | ||
| 186 | |||
| 187 | /// Internal initialization function shared by `new` and `new_polling`. | ||
| 188 | fn new_inner( | ||
| 189 | _inst: Peri<'a, I>, | ||
| 190 | pin: Peri<'a, impl AdcPin<I>>, | ||
| 191 | config: LpadcConfig, | ||
| 192 | ) -> Self { | ||
| 193 | let adc = &*I::ptr(); | ||
| 132 | 194 | ||
| 133 | let _clock_freq = unsafe { | 195 | let _clock_freq = unsafe { |
| 134 | enable_and_reset::<I>(&AdcConfig { | 196 | enable_and_reset::<I>(&AdcConfig { |
| @@ -139,6 +201,8 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 139 | .expect("Adc Init should not fail") | 201 | .expect("Adc Init should not fail") |
| 140 | }; | 202 | }; |
| 141 | 203 | ||
| 204 | pin.mux(); | ||
| 205 | |||
| 142 | /* Reset the module. */ | 206 | /* Reset the module. */ |
| 143 | adc.ctrl().modify(|_, w| w.rst().held_in_reset()); | 207 | adc.ctrl().modify(|_, w| w.rst().held_in_reset()); |
| 144 | adc.ctrl().modify(|_, w| w.rst().released_from_reset()); | 208 | adc.ctrl().modify(|_, w| w.rst().released_from_reset()); |
| @@ -221,17 +285,20 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 221 | adc.ctrl().modify(|_, w| w.adcen().enabled()); | 285 | adc.ctrl().modify(|_, w| w.adcen().enabled()); |
| 222 | 286 | ||
| 223 | Self { | 287 | Self { |
| 224 | _inst: core::marker::PhantomData, | 288 | _inst: PhantomData, |
| 225 | } | 289 | } |
| 226 | } | 290 | } |
| 227 | 291 | ||
| 292 | /// Deinitialize the ADC peripheral. | ||
| 228 | pub fn deinit(&self) { | 293 | pub fn deinit(&self) { |
| 229 | let adc = unsafe { &*I::ptr() }; | 294 | let adc = &*I::ptr(); |
| 230 | adc.ctrl().modify(|_, w| w.adcen().disabled()); | 295 | adc.ctrl().modify(|_, w| w.adcen().disabled()); |
| 231 | } | 296 | } |
| 232 | 297 | ||
| 298 | /// Perform offset calibration. | ||
| 299 | /// Waits for calibration to complete before returning. | ||
| 233 | pub fn do_offset_calibration(&self) { | 300 | pub fn do_offset_calibration(&self) { |
| 234 | let adc = unsafe { &*I::ptr() }; | 301 | let adc = &*I::ptr(); |
| 235 | // Enable calibration mode | 302 | // Enable calibration mode |
| 236 | adc.ctrl() | 303 | adc.ctrl() |
| 237 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); | 304 | .modify(|_, w| w.calofs().offset_calibration_request_pending()); |
| @@ -240,6 +307,13 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 240 | while adc.stat().read().cal_rdy().is_not_set() {} | 307 | while adc.stat().read().cal_rdy().is_not_set() {} |
| 241 | } | 308 | } |
| 242 | 309 | ||
| 310 | /// Calculate gain conversion result from gain adjustment factor. | ||
| 311 | /// | ||
| 312 | /// # Arguments | ||
| 313 | /// * `gain_adjustment` - Gain adjustment factor | ||
| 314 | /// | ||
| 315 | /// # Returns | ||
| 316 | /// Gain calibration register value | ||
| 243 | pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { | 317 | pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { |
| 244 | let mut gcra_array = [0u32; 17]; | 318 | let mut gcra_array = [0u32; 17]; |
| 245 | let mut gcalr: u32 = 0; | 319 | let mut gcalr: u32 = 0; |
| @@ -258,8 +332,9 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 258 | gcalr | 332 | gcalr |
| 259 | } | 333 | } |
| 260 | 334 | ||
| 335 | /// Perform automatic gain calibration. | ||
| 261 | pub fn do_auto_calibration(&self) { | 336 | pub fn do_auto_calibration(&self) { |
| 262 | let adc = unsafe { &*I::ptr() }; | 337 | let adc = &*I::ptr(); |
| 263 | adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); | 338 | adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); |
| 264 | 339 | ||
| 265 | while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} | 340 | while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} |
| @@ -280,11 +355,21 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 280 | while adc.stat().read().cal_rdy().is_not_set() {} | 355 | while adc.stat().read().cal_rdy().is_not_set() {} |
| 281 | } | 356 | } |
| 282 | 357 | ||
| 358 | /// Trigger ADC conversion(s) via software. | ||
| 359 | /// | ||
| 360 | /// Initiates conversion(s) for the trigger(s) specified in the bitmask. | ||
| 361 | /// Each bit in the mask corresponds to a trigger ID (bit 0 = trigger 0, etc.). | ||
| 362 | /// | ||
| 363 | /// # Arguments | ||
| 364 | /// * `trigger_id_mask` - Bitmask of trigger IDs to activate (bit N = trigger N) | ||
| 283 | pub fn do_software_trigger(&self, trigger_id_mask: u32) { | 365 | pub fn do_software_trigger(&self, trigger_id_mask: u32) { |
| 284 | let adc = unsafe { &*I::ptr() }; | 366 | let adc = &*I::ptr(); |
| 285 | adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); | 367 | adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); |
| 286 | } | 368 | } |
| 287 | 369 | ||
| 370 | /// Get default conversion command configuration. | ||
| 371 | /// # Returns | ||
| 372 | /// Default conversion command configuration | ||
| 288 | pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { | 373 | pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { |
| 289 | ConvCommandConfig { | 374 | ConvCommandConfig { |
| 290 | sample_channel_mode: Ctype::SingleEndedASideChannel, | 375 | sample_channel_mode: Ctype::SingleEndedASideChannel, |
| @@ -302,9 +387,17 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 302 | } | 387 | } |
| 303 | } | 388 | } |
| 304 | 389 | ||
| 305 | //TBD Need to add cmdlx and cmdhx with x {2..7} | 390 | /// Set conversion command configuration. |
| 391 | /// | ||
| 392 | /// Configures a conversion command slot with the specified parameters. | ||
| 393 | /// Commands define how conversions are performed (channel, resolution, etc.). | ||
| 394 | /// | ||
| 395 | /// # Arguments | ||
| 396 | /// * `index` - Command index (currently only 1 is supported) | ||
| 397 | /// * `config` - Command configuration | ||
| 398 | ///TBD Need to add cmdlx and cmdhx with x {2..7} | ||
| 306 | pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { | 399 | pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { |
| 307 | let adc = unsafe { &*I::ptr() }; | 400 | let adc = &*I::ptr(); |
| 308 | 401 | ||
| 309 | match index { | 402 | match index { |
| 310 | 1 => { | 403 | 1 => { |
| @@ -338,6 +431,10 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 338 | } | 431 | } |
| 339 | } | 432 | } |
| 340 | 433 | ||
| 434 | /// Get default conversion trigger configuration. | ||
| 435 | /// | ||
| 436 | /// # Returns | ||
| 437 | /// Default conversion trigger configuration | ||
| 341 | pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { | 438 | pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { |
| 342 | ConvTriggerConfig { | 439 | ConvTriggerConfig { |
| 343 | target_command_id: Tcmd::NotValid, | 440 | target_command_id: Tcmd::NotValid, |
| @@ -347,8 +444,16 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 347 | } | 444 | } |
| 348 | } | 445 | } |
| 349 | 446 | ||
| 447 | /// Set conversion trigger configuration. | ||
| 448 | /// | ||
| 449 | /// Configures a trigger to initiate conversions. Triggers can be | ||
| 450 | /// activated by software or hardware signals. | ||
| 451 | /// | ||
| 452 | /// # Arguments | ||
| 453 | /// * `trigger_id` - Trigger index (0-15) | ||
| 454 | /// * `config` - Trigger configuration | ||
| 350 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { | 455 | pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { |
| 351 | let adc = unsafe { &*I::ptr() }; | 456 | let adc = &*I::ptr(); |
| 352 | let tctrl = &adc.tctrl(trigger_id); | 457 | let tctrl = &adc.tctrl(trigger_id); |
| 353 | 458 | ||
| 354 | tctrl.write(|w| unsafe { | 459 | tctrl.write(|w| unsafe { |
| @@ -363,47 +468,245 @@ impl<'a, I: Instance> Adc<'a, I> { | |||
| 363 | }); | 468 | }); |
| 364 | } | 469 | } |
| 365 | 470 | ||
| 471 | /// Reset the FIFO buffer. | ||
| 472 | /// | ||
| 473 | /// Clears all pending conversion results from the FIFO. | ||
| 366 | pub fn do_reset_fifo(&self) { | 474 | pub fn do_reset_fifo(&self) { |
| 367 | let adc = unsafe { &*I::ptr() }; | 475 | let adc = &*I::ptr(); |
| 368 | adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); | 476 | adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); |
| 369 | } | 477 | } |
| 370 | 478 | ||
| 479 | /// Enable ADC interrupts. | ||
| 480 | /// | ||
| 481 | /// Enables the interrupt sources specified in the bitmask. | ||
| 482 | /// | ||
| 483 | /// # Arguments | ||
| 484 | /// * `mask` - Bitmask of interrupt sources to enable | ||
| 371 | pub fn enable_interrupt(&self, mask: u32) { | 485 | pub fn enable_interrupt(&self, mask: u32) { |
| 372 | let adc = unsafe { &*I::ptr() }; | 486 | let adc = &*I::ptr(); |
| 373 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); | 487 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); |
| 374 | INTERRUPT_TRIGGERED.store(false, Ordering::SeqCst); | ||
| 375 | } | 488 | } |
| 376 | 489 | ||
| 377 | pub fn is_interrupt_triggered(&self) -> bool { | 490 | /// Disable ADC interrupts. |
| 378 | INTERRUPT_TRIGGERED.load(Ordering::Relaxed) | 491 | /// |
| 492 | /// Disables the interrupt sources specified in the bitmask. | ||
| 493 | /// | ||
| 494 | /// # Arguments | ||
| 495 | /// * `mask` - Bitmask of interrupt sources to disable | ||
| 496 | pub fn disable_interrupt(&self, mask: u32) { | ||
| 497 | let adc = &*I::ptr(); | ||
| 498 | adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) }); | ||
| 379 | } | 499 | } |
| 380 | } | ||
| 381 | 500 | ||
| 382 | pub fn get_conv_result() -> Option<ConvResult> { | 501 | /// Get conversion result from FIFO. |
| 383 | let adc = unsafe { &*pac::Adc1::ptr() }; | 502 | /// |
| 384 | let fifo = adc.resfifo0().read().bits(); | 503 | /// Reads and returns the next conversion result from the FIFO. |
| 385 | const VALID_MASK: u32 = 1 << 31; | 504 | /// Returns `None` if the FIFO is empty. |
| 386 | if fifo & VALID_MASK == 0 { | 505 | /// |
| 387 | return None; | 506 | /// # Returns |
| 388 | } | 507 | /// - `Some(ConvResult)` if a result is available |
| 508 | /// - `None` if the FIFO is empty | ||
| 509 | pub fn get_conv_result(&self) -> Option<ConvResult> { | ||
| 510 | let adc = &*I::ptr(); | ||
| 511 | let fifo = adc.resfifo0().read().bits(); | ||
| 512 | const VALID_MASK: u32 = 1 << 31; | ||
| 513 | if fifo & VALID_MASK == 0 { | ||
| 514 | return None; | ||
| 515 | } | ||
| 389 | 516 | ||
| 390 | Some(ConvResult { | 517 | Some(ConvResult { |
| 391 | command_id_source: (fifo >> 24) & 0x0F, | 518 | command_id_source: (fifo >> 24) & 0x0F, |
| 392 | loop_count_index: (fifo >> 20) & 0x0F, | 519 | loop_count_index: (fifo >> 20) & 0x0F, |
| 393 | trigger_id_source: (fifo >> 16) & 0x0F, | 520 | trigger_id_source: (fifo >> 16) & 0x0F, |
| 394 | conv_value: (fifo & 0xFFFF) as u16, | 521 | conv_value: (fifo & 0xFFFF) as u16, |
| 395 | }) | 522 | }) |
| 396 | } | 523 | } |
| 397 | 524 | ||
| 398 | pub fn on_interrupt() { | 525 | /// Read ADC value asynchronously. |
| 399 | if get_conv_result().is_some() { | 526 | /// |
| 400 | INTERRUPT_TRIGGERED.store(true, Ordering::SeqCst); | 527 | /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered. |
| 528 | /// | ||
| 529 | /// The function: | ||
| 530 | /// 1. Enables the FIFO watermark interrupt | ||
| 531 | /// 2. Triggers a software conversion on trigger 0 | ||
| 532 | /// 3. Waits for the conversion to complete | ||
| 533 | /// 4. Returns the conversion result | ||
| 534 | /// | ||
| 535 | /// # Returns | ||
| 536 | /// 16-bit ADC conversion value | ||
| 537 | pub async fn read(&mut self) -> u16 { | ||
| 538 | let wait = WAKER.subscribe().await; | ||
| 539 | |||
| 540 | self.enable_interrupt(0x1); | ||
| 541 | self.do_software_trigger(1); | ||
| 542 | |||
| 543 | let _ = wait.await; | ||
| 544 | |||
| 545 | let result = self.get_conv_result(); | ||
| 546 | result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT | ||
| 401 | } | 547 | } |
| 402 | } | 548 | } |
| 403 | 549 | ||
| 404 | pub struct AdcHandler; | 550 | impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> { |
| 405 | impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::ADC1> for AdcHandler { | ||
| 406 | unsafe fn on_interrupt() { | 551 | unsafe fn on_interrupt() { |
| 407 | on_interrupt(); | 552 | T::ptr().ie().modify(|r, w| w.bits(r.bits() & !0x1)); |
| 553 | WAKER.wake(); | ||
| 408 | } | 554 | } |
| 409 | } | 555 | } |
| 556 | |||
| 557 | mod sealed { | ||
| 558 | /// Seal a trait | ||
| 559 | pub trait Sealed {} | ||
| 560 | } | ||
| 561 | |||
| 562 | impl<I: GpioPin> sealed::Sealed for I {} | ||
| 563 | |||
| 564 | trait SealedInstance { | ||
| 565 | fn ptr() -> &'static pac::adc0::RegisterBlock; | ||
| 566 | } | ||
| 567 | |||
| 568 | |||
| 569 | /// ADC Instance | ||
| 570 | #[allow(private_bounds)] | ||
| 571 | pub trait Instance: SealedInstance + PeripheralType + Gate<MrccPeriphConfig = AdcConfig> { | ||
| 572 | /// Interrupt for this ADC instance. | ||
| 573 | type Interrupt: Interrupt; | ||
| 574 | } | ||
| 575 | |||
| 576 | macro_rules! impl_instance { | ||
| 577 | ($($n:expr),*) => { | ||
| 578 | $( | ||
| 579 | paste!{ | ||
| 580 | impl SealedInstance for crate::peripherals::[<ADC $n>] { | ||
| 581 | fn ptr() -> &'static pac::adc0::RegisterBlock { | ||
| 582 | unsafe { &*pac::[<Adc $n>]::ptr() } | ||
| 583 | } | ||
| 584 | |||
| 585 | } | ||
| 586 | |||
| 587 | impl Instance for crate::peripherals::[<ADC $n>] { | ||
| 588 | type Interrupt = crate::interrupt::typelevel::[<ADC $n>]; | ||
| 589 | } | ||
| 590 | } | ||
| 591 | )* | ||
| 592 | }; | ||
| 593 | } | ||
| 594 | |||
| 595 | impl_instance!(0, 1); //ADC2 and ADC3 missing in the PAC ?? | ||
| 596 | |||
| 597 | pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType { | ||
| 598 | /// Set the given pin to the correct muxing state | ||
| 599 | fn mux(&self); | ||
| 600 | } | ||
| 601 | |||
| 602 | macro_rules! impl_pin { | ||
| 603 | ($pin:ident, $peri:ident, $func:ident, $trait:ident) => { | ||
| 604 | impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin { | ||
| 605 | fn mux(&self) { | ||
| 606 | self.set_pull(crate::gpio::Pull::Disabled); | ||
| 607 | self.set_slew_rate(crate::gpio::SlewRate::Fast.into()); | ||
| 608 | self.set_drive_strength(crate::gpio::DriveStrength::Normal.into()); | ||
| 609 | self.set_function(crate::pac::port0::pcr0::Mux::$func); | ||
| 610 | } | ||
| 611 | } | ||
| 612 | }; | ||
| 613 | } | ||
| 614 | |||
| 615 | impl_pin!(P2_0, ADC0, Mux0, AdcPin); | ||
| 616 | impl_pin!(P2_4, ADC0, Mux0, AdcPin); | ||
| 617 | impl_pin!(P2_15, ADC0, Mux0, AdcPin); | ||
| 618 | impl_pin!(P2_3, ADC0, Mux0, AdcPin); | ||
| 619 | impl_pin!(P2_2, ADC0, Mux0, AdcPin); | ||
| 620 | impl_pin!(P2_12, ADC0, Mux0, AdcPin); | ||
| 621 | impl_pin!(P2_16, ADC0, Mux0, AdcPin); | ||
| 622 | impl_pin!(P2_7, ADC0, Mux0, AdcPin); | ||
| 623 | impl_pin!(P0_18, ADC0, Mux0, AdcPin); | ||
| 624 | impl_pin!(P0_19, ADC0, Mux0, AdcPin); | ||
| 625 | impl_pin!(P0_20, ADC0, Mux0, AdcPin); | ||
| 626 | impl_pin!(P0_21, ADC0, Mux0, AdcPin); | ||
| 627 | impl_pin!(P0_22, ADC0, Mux0, AdcPin); | ||
| 628 | impl_pin!(P0_23, ADC0, Mux0, AdcPin); | ||
| 629 | impl_pin!(P0_3, ADC0, Mux0, AdcPin); | ||
| 630 | impl_pin!(P0_6, ADC0, Mux0, AdcPin); | ||
| 631 | impl_pin!(P1_0, ADC0, Mux0, AdcPin); | ||
| 632 | impl_pin!(P1_1, ADC0, Mux0, AdcPin); | ||
| 633 | impl_pin!(P1_2, ADC0, Mux0, AdcPin); | ||
| 634 | impl_pin!(P1_3, ADC0, Mux0, AdcPin); | ||
| 635 | impl_pin!(P1_4, ADC0, Mux0, AdcPin); | ||
| 636 | impl_pin!(P1_5, ADC0, Mux0, AdcPin); | ||
| 637 | impl_pin!(P1_6, ADC0, Mux0, AdcPin); | ||
| 638 | impl_pin!(P1_7, ADC0, Mux0, AdcPin); | ||
| 639 | impl_pin!(P1_10, ADC0, Mux0, AdcPin); | ||
| 640 | |||
| 641 | impl_pin!(P2_1, ADC1, Mux0, AdcPin); | ||
| 642 | impl_pin!(P2_5, ADC1, Mux0, AdcPin); | ||
| 643 | impl_pin!(P2_19, ADC1, Mux0, AdcPin); | ||
| 644 | impl_pin!(P2_6, ADC1, Mux0, AdcPin); | ||
| 645 | impl_pin!(P2_3, ADC1, Mux0, AdcPin); | ||
| 646 | impl_pin!(P2_13, ADC1, Mux0, AdcPin); | ||
| 647 | impl_pin!(P2_17, ADC1, Mux0, AdcPin); | ||
| 648 | impl_pin!(P2_7, ADC1, Mux0, AdcPin); | ||
| 649 | impl_pin!(P1_10, ADC1, Mux0, AdcPin); | ||
| 650 | impl_pin!(P1_11, ADC1, Mux0, AdcPin); | ||
| 651 | impl_pin!(P1_12, ADC1, Mux0, AdcPin); | ||
| 652 | impl_pin!(P1_13, ADC1, Mux0, AdcPin); | ||
| 653 | impl_pin!(P1_14, ADC1, Mux0, AdcPin); | ||
| 654 | impl_pin!(P1_15, ADC1, Mux0, AdcPin); | ||
| 655 | impl_pin!(P1_16, ADC1, Mux0, AdcPin); | ||
| 656 | impl_pin!(P1_17, ADC1, Mux0, AdcPin); | ||
| 657 | impl_pin!(P1_18, ADC1, Mux0, AdcPin); | ||
| 658 | impl_pin!(P1_19, ADC1, Mux0, AdcPin); | ||
| 659 | impl_pin!(P3_31, ADC1, Mux0, AdcPin); | ||
| 660 | impl_pin!(P3_30, ADC1, Mux0, AdcPin); | ||
| 661 | impl_pin!(P3_29, ADC1, Mux0, AdcPin); | ||
| 662 | |||
| 663 | impl_pin!(P2_4, ADC2, Mux0, AdcPin); | ||
| 664 | impl_pin!(P2_10, ADC2, Mux0, AdcPin); | ||
| 665 | impl_pin!(P4_4, ADC2, Mux0, AdcPin); | ||
| 666 | impl_pin!(P2_24, ADC2, Mux0, AdcPin); | ||
| 667 | impl_pin!(P2_16, ADC2, Mux0, AdcPin); | ||
| 668 | impl_pin!(P2_12, ADC2, Mux0, AdcPin); | ||
| 669 | impl_pin!(P2_20, ADC2, Mux0, AdcPin); | ||
| 670 | impl_pin!(P2_7, ADC2, Mux0, AdcPin); | ||
| 671 | impl_pin!(P0_2, ADC2, Mux0, AdcPin); | ||
| 672 | impl_pin!(P0_4, ADC2, Mux0, AdcPin); | ||
| 673 | impl_pin!(P0_5, ADC2, Mux0, AdcPin); | ||
| 674 | impl_pin!(P0_6, ADC2, Mux0, AdcPin); | ||
| 675 | impl_pin!(P0_7, ADC2, Mux0, AdcPin); | ||
| 676 | impl_pin!(P0_12, ADC2, Mux0, AdcPin); | ||
| 677 | impl_pin!(P0_13, ADC2, Mux0, AdcPin); | ||
| 678 | impl_pin!(P0_14, ADC2, Mux0, AdcPin); | ||
| 679 | impl_pin!(P0_15, ADC2, Mux0, AdcPin); | ||
| 680 | impl_pin!(P4_0, ADC2, Mux0, AdcPin); | ||
| 681 | impl_pin!(P4_1, ADC2, Mux0, AdcPin); | ||
| 682 | impl_pin!(P4_2, ADC2, Mux0, AdcPin); | ||
| 683 | impl_pin!(P4_3, ADC2, Mux0, AdcPin); | ||
| 684 | //impl_pin!(P4_4, ADC2, Mux0, AdcPin); // Conflit with ADC2_A3 and ADC2_A20 using the same pin | ||
| 685 | impl_pin!(P4_5, ADC2, Mux0, AdcPin); | ||
| 686 | impl_pin!(P4_6, ADC2, Mux0, AdcPin); | ||
| 687 | impl_pin!(P4_7, ADC2, Mux0, AdcPin); | ||
| 688 | |||
| 689 | impl_pin!(P2_5, ADC3, Mux0, AdcPin); | ||
| 690 | impl_pin!(P2_11, ADC3, Mux0, AdcPin); | ||
| 691 | impl_pin!(P2_23, ADC3, Mux0, AdcPin); | ||
| 692 | impl_pin!(P2_25, ADC3, Mux0, AdcPin); | ||
| 693 | impl_pin!(P2_17, ADC3, Mux0, AdcPin); | ||
| 694 | impl_pin!(P2_13, ADC3, Mux0, AdcPin); | ||
| 695 | impl_pin!(P2_21, ADC3, Mux0, AdcPin); | ||
| 696 | impl_pin!(P2_7, ADC3, Mux0, AdcPin); | ||
| 697 | impl_pin!(P3_2, ADC3, Mux0, AdcPin); | ||
| 698 | impl_pin!(P3_3, ADC3, Mux0, AdcPin); | ||
| 699 | impl_pin!(P3_4, ADC3, Mux0, AdcPin); | ||
| 700 | impl_pin!(P3_5, ADC3, Mux0, AdcPin); | ||
| 701 | impl_pin!(P3_6, ADC3, Mux0, AdcPin); | ||
| 702 | impl_pin!(P3_7, ADC3, Mux0, AdcPin); | ||
| 703 | impl_pin!(P3_12, ADC3, Mux0, AdcPin); | ||
| 704 | impl_pin!(P3_13, ADC3, Mux0, AdcPin); | ||
| 705 | impl_pin!(P3_14, ADC3, Mux0, AdcPin); | ||
| 706 | impl_pin!(P3_15, ADC3, Mux0, AdcPin); | ||
| 707 | impl_pin!(P3_20, ADC3, Mux0, AdcPin); | ||
| 708 | impl_pin!(P3_21, ADC3, Mux0, AdcPin); | ||
| 709 | impl_pin!(P3_22, ADC3, Mux0, AdcPin); | ||
| 710 | impl_pin!(P3_23, ADC3, Mux0, AdcPin); | ||
| 711 | impl_pin!(P3_24, ADC3, Mux0, AdcPin); | ||
| 712 | impl_pin!(P3_25, ADC3, Mux0, AdcPin); | ||
diff --git a/embassy-mcxa/src/clocks/mod.rs b/embassy-mcxa/src/clocks/mod.rs index 014a12519..667d79536 100644 --- a/embassy-mcxa/src/clocks/mod.rs +++ b/embassy-mcxa/src/clocks/mod.rs | |||
| @@ -945,7 +945,10 @@ pub(crate) mod gate { | |||
| 945 | impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); | 945 | impl_cc_gate!(LPUART3, mrcc_glb_cc0, mrcc_glb_rst0, lpuart3, LpuartConfig); |
| 946 | impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); | 946 | impl_cc_gate!(LPUART4, mrcc_glb_cc0, mrcc_glb_rst0, lpuart4, LpuartConfig); |
| 947 | impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); | 947 | impl_cc_gate!(LPUART5, mrcc_glb_cc1, mrcc_glb_rst1, lpuart5, LpuartConfig); |
| 948 | impl_cc_gate!(ADC0, mrcc_glb_cc1, mrcc_glb_rst1, adc0, AdcConfig); | ||
| 948 | impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); | 949 | impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); |
| 950 | impl_cc_gate!(ADC2, mrcc_glb_cc1, mrcc_glb_rst1, adc2, AdcConfig); | ||
| 951 | impl_cc_gate!(ADC3, mrcc_glb_cc1, mrcc_glb_rst1, adc3, AdcConfig); | ||
| 949 | 952 | ||
| 950 | // DMA0 peripheral - uses NoConfig since it has no selectable clock source | 953 | // DMA0 peripheral - uses NoConfig since it has no selectable clock source |
| 951 | impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); | 954 | impl_cc_gate!(DMA0, mrcc_glb_cc0, mrcc_glb_rst0, dma0, NoConfig); |
diff --git a/embassy-mcxa/src/clocks/periph_helpers.rs b/embassy-mcxa/src/clocks/periph_helpers.rs index fed5e558e..f2f51c60c 100644 --- a/embassy-mcxa/src/clocks/periph_helpers.rs +++ b/embassy-mcxa/src/clocks/periph_helpers.rs | |||
| @@ -427,6 +427,7 @@ impl SPConfHelper for OsTimerConfig { | |||
| 427 | 427 | ||
| 428 | /// Selectable clocks for the ADC peripheral | 428 | /// Selectable clocks for the ADC peripheral |
| 429 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] | 429 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 430 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 430 | pub enum AdcClockSel { | 431 | pub enum AdcClockSel { |
| 431 | /// Divided `fro_lf`/`clk_12m`/FRO12M source | 432 | /// Divided `fro_lf`/`clk_12m`/FRO12M source |
| 432 | FroLfDiv, | 433 | FroLfDiv, |
diff --git a/embassy-mcxa/src/interrupt.rs b/embassy-mcxa/src/interrupt.rs index c960af7a2..7eabc6495 100644 --- a/embassy-mcxa/src/interrupt.rs +++ b/embassy-mcxa/src/interrupt.rs | |||
| @@ -9,7 +9,10 @@ | |||
| 9 | mod generated { | 9 | mod generated { |
| 10 | #[rustfmt::skip] | 10 | #[rustfmt::skip] |
| 11 | embassy_hal_internal::interrupt_mod!( | 11 | embassy_hal_internal::interrupt_mod!( |
| 12 | ADC0, | ||
| 12 | ADC1, | 13 | ADC1, |
| 14 | ADC2, | ||
| 15 | ADC3, | ||
| 13 | DMA_CH0, | 16 | DMA_CH0, |
| 14 | DMA_CH1, | 17 | DMA_CH1, |
| 15 | DMA_CH2, | 18 | DMA_CH2, |
| @@ -279,11 +282,48 @@ impl InterruptExt for Rtc { | |||
| 279 | cortex_m::peripheral::NVIC::is_pending(Interrupt::RTC) | 282 | cortex_m::peripheral::NVIC::is_pending(Interrupt::RTC) |
| 280 | } | 283 | } |
| 281 | } | 284 | } |
| 285 | pub struct Adc0; | ||
| 286 | pub const ADC0: Adc0 = Adc0; | ||
| 282 | 287 | ||
| 283 | pub struct Adc; | 288 | impl InterruptExt for Adc0 { |
| 284 | pub const ADC1: Adc = Adc; | 289 | /// Clear any pending ADC0 in NVIC. |
| 290 | #[inline] | ||
| 291 | fn unpend(&self) { | ||
| 292 | cortex_m::peripheral::NVIC::unpend(Interrupt::ADC0); | ||
| 293 | } | ||
| 294 | |||
| 295 | /// Set NVIC priority for ADC0. | ||
| 296 | #[inline] | ||
| 297 | fn set_priority(&self, priority: Priority) { | ||
| 298 | unsafe { | ||
| 299 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 300 | nvic.set_priority(Interrupt::ADC0, u8::from(priority)); | ||
| 301 | } | ||
| 302 | } | ||
| 285 | 303 | ||
| 286 | impl InterruptExt for Adc { | 304 | /// Enable ADC0 in NVIC. |
| 305 | #[inline] | ||
| 306 | unsafe fn enable(&self) { | ||
| 307 | cortex_m::peripheral::NVIC::unmask(Interrupt::ADC0); | ||
| 308 | } | ||
| 309 | |||
| 310 | /// Disable ADC0 in NVIC. | ||
| 311 | #[inline] | ||
| 312 | unsafe fn disable(&self) { | ||
| 313 | cortex_m::peripheral::NVIC::mask(Interrupt::ADC0); | ||
| 314 | } | ||
| 315 | |||
| 316 | /// Check if ADC0 is pending in NVIC. | ||
| 317 | #[inline] | ||
| 318 | fn is_pending(&self) -> bool { | ||
| 319 | cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC0) | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | pub struct Adc1; | ||
| 324 | pub const ADC1: Adc1 = Adc1; | ||
| 325 | |||
| 326 | impl InterruptExt for Adc1 { | ||
| 287 | /// Clear any pending ADC1 in NVIC. | 327 | /// Clear any pending ADC1 in NVIC. |
| 288 | #[inline] | 328 | #[inline] |
| 289 | fn unpend(&self) { | 329 | fn unpend(&self) { |
| @@ -318,6 +358,82 @@ impl InterruptExt for Adc { | |||
| 318 | } | 358 | } |
| 319 | } | 359 | } |
| 320 | 360 | ||
| 361 | pub struct Adc2; | ||
| 362 | pub const ADC2: Adc2 = Adc2; | ||
| 363 | |||
| 364 | impl InterruptExt for Adc2 { | ||
| 365 | /// Clear any pending ADC2 in NVIC. | ||
| 366 | #[inline] | ||
| 367 | fn unpend(&self) { | ||
| 368 | cortex_m::peripheral::NVIC::unpend(Interrupt::ADC2); | ||
| 369 | } | ||
| 370 | |||
| 371 | /// Set NVIC priority for ADC2. | ||
| 372 | #[inline] | ||
| 373 | fn set_priority(&self, priority: Priority) { | ||
| 374 | unsafe { | ||
| 375 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 376 | nvic.set_priority(Interrupt::ADC2, u8::from(priority)); | ||
| 377 | } | ||
| 378 | } | ||
| 379 | |||
| 380 | /// Enable ADC2 in NVIC. | ||
| 381 | #[inline] | ||
| 382 | unsafe fn enable(&self) { | ||
| 383 | cortex_m::peripheral::NVIC::unmask(Interrupt::ADC2); | ||
| 384 | } | ||
| 385 | |||
| 386 | /// Disable ADC2 in NVIC. | ||
| 387 | #[inline] | ||
| 388 | unsafe fn disable(&self) { | ||
| 389 | cortex_m::peripheral::NVIC::mask(Interrupt::ADC2); | ||
| 390 | } | ||
| 391 | |||
| 392 | /// Check if ADC2 is pending in NVIC. | ||
| 393 | #[inline] | ||
| 394 | fn is_pending(&self) -> bool { | ||
| 395 | cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC2) | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | pub struct Adc3; | ||
| 400 | pub const ADC3: Adc3 = Adc3; | ||
| 401 | |||
| 402 | impl InterruptExt for Adc3 { | ||
| 403 | /// Clear any pending ADC3 in NVIC. | ||
| 404 | #[inline] | ||
| 405 | fn unpend(&self) { | ||
| 406 | cortex_m::peripheral::NVIC::unpend(Interrupt::ADC3); | ||
| 407 | } | ||
| 408 | |||
| 409 | /// Set NVIC priority for ADC3. | ||
| 410 | #[inline] | ||
| 411 | fn set_priority(&self, priority: Priority) { | ||
| 412 | unsafe { | ||
| 413 | let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC; | ||
| 414 | nvic.set_priority(Interrupt::ADC3, u8::from(priority)); | ||
| 415 | } | ||
| 416 | } | ||
| 417 | |||
| 418 | /// Enable ADC3 in NVIC. | ||
| 419 | #[inline] | ||
| 420 | unsafe fn enable(&self) { | ||
| 421 | cortex_m::peripheral::NVIC::unmask(Interrupt::ADC3); | ||
| 422 | } | ||
| 423 | |||
| 424 | /// Disable ADC3 in NVIC. | ||
| 425 | #[inline] | ||
| 426 | unsafe fn disable(&self) { | ||
| 427 | cortex_m::peripheral::NVIC::mask(Interrupt::ADC3); | ||
| 428 | } | ||
| 429 | |||
| 430 | /// Check if ADC3 is pending in NVIC. | ||
| 431 | #[inline] | ||
| 432 | fn is_pending(&self) -> bool { | ||
| 433 | cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC3) | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 321 | pub struct Gpio0; | 437 | pub struct Gpio0; |
| 322 | pub const GPIO0: Gpio0 = Gpio0; | 438 | pub const GPIO0: Gpio0 = Gpio0; |
| 323 | 439 | ||
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs index 1bbdffa06..10b6167b6 100644 --- a/embassy-mcxa/src/lib.rs +++ b/embassy-mcxa/src/lib.rs | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | pub mod clocks; // still provide clock helpers | 8 | pub mod clocks; // still provide clock helpers |
| 9 | pub mod dma; | 9 | pub mod dma; |
| 10 | pub mod gpio; | 10 | pub mod gpio; |
| 11 | pub mod pins; // pin mux helpers | ||
| 12 | 11 | ||
| 13 | pub mod adc; | 12 | pub mod adc; |
| 14 | pub mod clkout; | 13 | pub mod clkout; |
| @@ -26,6 +25,8 @@ pub use crate::pac::NVIC_PRIO_BITS; | |||
| 26 | embassy_hal_internal::peripherals!( | 25 | embassy_hal_internal::peripherals!( |
| 27 | ADC0, | 26 | ADC0, |
| 28 | ADC1, | 27 | ADC1, |
| 28 | ADC2, | ||
| 29 | ADC3, | ||
| 29 | 30 | ||
| 30 | AOI0, | 31 | AOI0, |
| 31 | AOI1, | 32 | AOI1, |
| @@ -336,7 +337,6 @@ embassy_hal_internal::peripherals!( | |||
| 336 | // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. | 337 | // Use cortex-m-rt's #[interrupt] attribute directly; PAC does not re-export it. |
| 337 | 338 | ||
| 338 | // Re-export interrupt traits and types | 339 | // Re-export interrupt traits and types |
| 339 | pub use adc::Adc1 as Adc1Token; | ||
| 340 | pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; | 340 | pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; |
| 341 | pub use interrupt::InterruptExt; | 341 | pub use interrupt::InterruptExt; |
| 342 | #[cfg(feature = "unstable-pac")] | 342 | #[cfg(feature = "unstable-pac")] |
| @@ -354,8 +354,14 @@ pub fn init(cfg: crate::config::Config) -> Peripherals { | |||
| 354 | // Apply user-configured priority early; enabling is left to examples/apps | 354 | // Apply user-configured priority early; enabling is left to examples/apps |
| 355 | crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); | 355 | crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); |
| 356 | // Apply user-configured priority early; enabling is left to examples/apps | 356 | // Apply user-configured priority early; enabling is left to examples/apps |
| 357 | crate::interrupt::ADC0.set_priority(cfg.adc_interrupt_priority); | ||
| 358 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 357 | crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); | 359 | crate::interrupt::ADC1.set_priority(cfg.adc_interrupt_priority); |
| 358 | // Apply user-configured priority early; enabling is left to examples/apps | 360 | // Apply user-configured priority early; enabling is left to examples/apps |
| 361 | crate::interrupt::ADC2.set_priority(cfg.adc_interrupt_priority); | ||
| 362 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 363 | crate::interrupt::ADC3.set_priority(cfg.adc_interrupt_priority); | ||
| 364 | // Apply user-configured priority early; enabling is left to examples/apps | ||
| 359 | crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); | 365 | crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); |
| 360 | // Apply user-configured priority early; enabling is left to examples/apps | 366 | // Apply user-configured priority early; enabling is left to examples/apps |
| 361 | crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); | 367 | crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); |
diff --git a/embassy-mcxa/src/pins.rs b/embassy-mcxa/src/pins.rs deleted file mode 100644 index 9adbe64c8..000000000 --- a/embassy-mcxa/src/pins.rs +++ /dev/null | |||
| @@ -1,33 +0,0 @@ | |||
| 1 | //! Pin configuration helpers (separate from peripheral drivers). | ||
| 2 | use crate::pac; | ||
| 3 | |||
| 4 | /// Configure pins for ADC usage. | ||
| 5 | /// | ||
| 6 | /// # Safety | ||
| 7 | /// | ||
| 8 | /// Must be called after PORT clocks are enabled. | ||
| 9 | pub unsafe fn configure_adc_pins() { | ||
| 10 | // P1_10 = ADC1_A8 | ||
| 11 | let port1 = &*pac::Port1::ptr(); | ||
| 12 | port1.pcr10().write(|w| { | ||
| 13 | w.ps() | ||
| 14 | .ps0() | ||
| 15 | .pe() | ||
| 16 | .pe0() | ||
| 17 | .sre() | ||
| 18 | .sre0() | ||
| 19 | .ode() | ||
| 20 | .ode0() | ||
| 21 | .dse() | ||
| 22 | .dse0() | ||
| 23 | .mux() | ||
| 24 | .mux0() | ||
| 25 | .ibe() | ||
| 26 | .ibe0() | ||
| 27 | .inv() | ||
| 28 | .inv0() | ||
| 29 | .lk() | ||
| 30 | .lk0() | ||
| 31 | }); | ||
| 32 | core::arch::asm!("dsb sy; isb sy"); | ||
| 33 | } | ||
