aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-mcxa/Cargo.toml2
-rw-r--r--embassy-mcxa/src/adc.rs553
-rw-r--r--embassy-mcxa/src/clocks/mod.rs3
-rw-r--r--embassy-mcxa/src/clocks/periph_helpers.rs1
-rw-r--r--embassy-mcxa/src/interrupt.rs41
-rw-r--r--embassy-mcxa/src/lib.rs6
-rw-r--r--embassy-mcxa/src/pins.rs33
-rw-r--r--examples/mcxa/src/bin/adc_interrupt.rs49
-rw-r--r--examples/mcxa/src/bin/adc_polling.rs32
-rw-r--r--examples/mcxa/src/lib.rs16
10 files changed, 495 insertions, 241 deletions
diff --git a/embassy-mcxa/Cargo.toml b/embassy-mcxa/Cargo.toml
index 8ed842aec..cb985a2e9 100644
--- a/embassy-mcxa/Cargo.toml
+++ b/embassy-mcxa/Cargo.toml
@@ -39,7 +39,7 @@ embedded-hal-nb = { version = "1.0" }
39embedded-io = "0.6" 39embedded-io = "0.6"
40embedded-io-async = { version = "0.6.1" } 40embedded-io-async = { version = "0.6.1" }
41heapless = "0.8" 41heapless = "0.8"
42mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "e7dfed8740b449b6ac646bab8ac6776a3c099267" } 42mcxa-pac = { git = "https://github.com/OpenDevicePartnership/mcxa-pac", features = ["rt", "critical-section"], version = "0.1.0", rev = "02bd04a21ef8f8f67f88239ff5df765bb7e60fd8" }
43nb = "1.1.0" 43nb = "1.1.0"
44paste = "1.0.15" 44paste = "1.0.15"
45maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] } 45maitake-sync = { version = "0.2.2", default-features = false, features = ["critical-section", "no-cache-pad"] }
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs
index 7475299ba..d7d17cf5f 100644
--- a/embassy-mcxa/src/adc.rs
+++ b/embassy-mcxa/src/adc.rs
@@ -1,42 +1,24 @@
1//! ADC driver 1//! ADC driver
2use core::sync::atomic::{AtomicBool, Ordering}; 2use core::marker::PhantomData;
3 3
4use embassy_hal_internal::{Peri, PeripheralType}; 4use embassy_hal_internal::{Peri, PeripheralType};
5use maitake_sync::WaitCell;
6use paste::paste;
5 7
6use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4}; 8use crate::clocks::periph_helpers::{AdcClockSel, AdcConfig, Div4};
7use crate::clocks::{Gate, PoweredClock, enable_and_reset}; 9use crate::clocks::{ClockError, Gate, PoweredClock, enable_and_reset};
10use crate::gpio::{GpioPin, SealedPin};
11use crate::interrupt::typelevel::{Handler, Interrupt};
8use crate::pac; 12use crate::pac;
9use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres}; 13use crate::pac::adc1::cfg::{HptExdi, Pwrsel, Refsel, Tcmdres, Tprictrl, Tres};
10use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts}; 14use crate::pac::adc1::cmdh1::{Avgs, Cmpen, Next, Sts};
11use crate::pac::adc1::cmdl1::{Adch, Ctype, Mode}; 15use crate::pac::adc1::cmdl1::{Adch, Mode};
12use crate::pac::adc1::ctrl::CalAvgs; 16use crate::pac::adc1::ctrl::CalAvgs;
13use crate::pac::adc1::tctrl::{Tcmd, Tpri}; 17use crate::pac::adc1::tctrl::{Tcmd, Tpri};
14 18
15type Regs = pac::adc1::RegisterBlock; 19const G_LPADC_RESULT_SHIFT: u32 = 0;
16
17static INTERRUPT_TRIGGERED: AtomicBool = AtomicBool::new(false);
18// Token-based instance pattern like embassy-imxrt
19pub trait Instance: Gate<MrccPeriphConfig = AdcConfig> + PeripheralType {
20 fn ptr() -> *const Regs;
21}
22
23/// Token for ADC1
24pub type Adc1 = crate::peripherals::ADC1;
25impl 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 20
21/// Trigger priority policy for ADC conversions.
40#[derive(Debug, Clone, Copy, PartialEq, Eq)] 22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41#[repr(u8)] 23#[repr(u8)]
42pub enum TriggerPriorityPolicy { 24pub enum TriggerPriorityPolicy {
@@ -52,20 +34,40 @@ pub enum TriggerPriorityPolicy {
52 TriggerPriorityExceptionDisabled = 16, 34 TriggerPriorityExceptionDisabled = 16,
53} 35}
54 36
37/// Configuration for the LPADC peripheral.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)] 38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub struct LpadcConfig { 39pub struct LpadcConfig {
40 /// Control system transition to Stop and Wait power modes while ADC is converting.
41 /// When enabled in Doze mode, immediate entries to Wait or Stop are allowed.
42 /// 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, 43 pub enable_in_doze_mode: bool,
44 /// Auto-Calibration Averages.
58 pub conversion_average_mode: CalAvgs, 45 pub conversion_average_mode: CalAvgs,
46 /// 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, 47 pub enable_analog_preliminary: bool,
48 /// Power-up delay value (in ADC clock cycles)
60 pub power_up_delay: u8, 49 pub power_up_delay: u8,
50 /// Reference voltage source selection
61 pub reference_voltage_source: Refsel, 51 pub reference_voltage_source: Refsel,
52 /// Power configuration selection.
62 pub power_level_mode: Pwrsel, 53 pub power_level_mode: Pwrsel,
54 /// Trigger priority policy for handling multiple triggers
63 pub trigger_priority_policy: TriggerPriorityPolicy, 55 pub trigger_priority_policy: TriggerPriorityPolicy,
56 /// Enables the ADC pausing function. When enabled, a programmable delay is inserted during command execution sequencing between LOOP iterations,
57 /// between commands in a sequence, and between conversions when command is executing in "Compare Until True" configuration.
64 pub enable_conv_pause: bool, 58 pub enable_conv_pause: bool,
59 /// 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.
65 pub conv_pause_delay: u16, 61 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.
66 pub fifo_watermark: u8, 65 pub fifo_watermark: u8,
66 /// Power configuration (normal/deep sleep behavior)
67 pub power: PoweredClock, 67 pub power: PoweredClock,
68 /// ADC clock source selection
68 pub source: AdcClockSel, 69 pub source: AdcClockSel,
70 /// Clock divider for ADC clock
69 pub div: Div4, 71 pub div: Div4,
70} 72}
71 73
@@ -89,9 +91,11 @@ impl Default for LpadcConfig {
89 } 91 }
90} 92}
91 93
94/// Configuration for a conversion command.
95///
96/// Defines the parameters for a single ADC conversion operation.
92#[derive(Debug, Clone, Copy, PartialEq, Eq)] 97#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93pub struct ConvCommandConfig { 98pub struct ConvCommandConfig {
94 pub sample_channel_mode: Ctype,
95 pub channel_number: Adch, 99 pub channel_number: Adch,
96 pub chained_next_command_number: Next, 100 pub chained_next_command_number: Next,
97 pub enable_auto_channel_increment: bool, 101 pub enable_auto_channel_increment: bool,
@@ -105,6 +109,9 @@ pub struct ConvCommandConfig {
105 pub enable_wait_trigger: bool, 109 pub enable_wait_trigger: bool,
106} 110}
107 111
112/// Configuration for a conversion trigger.
113///
114/// Defines how a trigger initiates ADC conversions.
108#[derive(Debug, Clone, Copy, PartialEq, Eq)] 115#[derive(Debug, Clone, Copy, PartialEq, Eq)]
109pub struct ConvTriggerConfig { 116pub struct ConvTriggerConfig {
110 pub target_command_id: Tcmd, 117 pub target_command_id: Tcmd,
@@ -113,32 +120,117 @@ pub struct ConvTriggerConfig {
113 pub enable_hardware_trigger: bool, 120 pub enable_hardware_trigger: bool,
114} 121}
115 122
123/// Shorthand for `Result<T>`.
124pub type Result<T> = core::result::Result<T, Error>;
125
126/// ADC Error types
127#[derive(Debug, Clone, Copy, PartialEq, Eq)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub enum Error {
130 /// FIFO is empty, no conversion result available
131 FifoEmpty,
132 /// Invalid configuration
133 InvalidConfig,
134 /// Clock configuration error.
135 ClockSetup(ClockError),
136}
137
138/// Result of an ADC conversion.
139///
140/// Contains the conversion value and metadata about the conversion.
116#[derive(Debug, Clone, Copy, PartialEq, Eq)] 141#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub struct ConvResult { 142pub struct ConvResult {
118 pub command_id_source: u32, 143 pub command_id_source: u8,
119 pub loop_count_index: u32, 144 pub loop_count_index: u8,
120 pub trigger_id_source: u32, 145 pub trigger_id_source: u8,
121 pub conv_value: u16, 146 pub conv_value: u16,
122} 147}
123 148
124pub struct Adc<'a, I: Instance> { 149/// ADC interrupt handler.
125 _inst: core::marker::PhantomData<&'a mut I>, 150pub struct InterruptHandler<I: Instance> {
151 _phantom: PhantomData<I>,
152}
153
154/// ADC driver instance.
155pub struct Adc<'a, I: Instance, M: ModeAdc> {
156 _inst: PhantomData<&'a mut I>,
157 _phantom: PhantomData<M>,
158}
159
160impl<'a, I: Instance> Adc<'a, I, Blocking> {
161 /// Create a new blocking instance of the ADC driver.
162 /// # Arguments
163 /// * `_inst` - ADC peripheral instance
164 /// * `pin` - GPIO pin to use for ADC
165 /// * `config` - ADC configuration
166 pub fn new_blocking(_inst: Peri<'a, I>, pin: Peri<'a, impl AdcPin<I>>, config: LpadcConfig) -> Result<Self> {
167 Self::new_inner(_inst, pin, config)
168 }
126} 169}
127 170
128impl<'a, I: Instance> Adc<'a, I> { 171impl<'a, I: Instance> Adc<'a, I, Async> {
129 /// initialize ADC 172 /// Initialize ADC with interrupt support.
130 pub fn new(_inst: Peri<'a, I>, config: LpadcConfig) -> Self { 173 ///
131 let adc = unsafe { &*I::ptr() }; 174 /// # Arguments
175 /// * `_inst` - ADC peripheral instance
176 /// * `pin` - GPIO pin to use for ADC
177 /// * `_irq` - Interrupt binding for this ADC instance
178 /// * `config` - ADC configuration
179 pub fn new_async(
180 _inst: Peri<'a, I>,
181 pin: Peri<'a, impl AdcPin<I>>,
182 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a,
183 config: LpadcConfig,
184 ) -> Result<Self> {
185 let adc = Self::new_inner(_inst, pin, config);
186
187 I::Interrupt::unpend();
188 unsafe { I::Interrupt::enable() };
189
190 adc
191 }
132 192
133 let _clock_freq = unsafe { 193 /// Read ADC value asynchronously.
194 ///
195 /// Performs a single ADC conversion and returns the result when the ADC interrupt is triggered.
196 ///
197 /// The function:
198 /// 1. Enables the FIFO watermark interrupt
199 /// 2. Triggers a software conversion on trigger 0
200 /// 3. Waits for the conversion to complete
201 /// 4. Returns the conversion result
202 ///
203 /// # Returns
204 /// 16-bit ADC conversion value
205 pub async fn read(&mut self) -> Result<u16> {
206 let wait = I::wait_cell().subscribe().await;
207
208 Adc::<'a, I, Async>::enable_interrupt(self, 0x1);
209 Adc::<'a, I, Async>::do_software_trigger(self, 1);
210
211 let _ = wait.await;
212
213 let result = Adc::<'a, I, Async>::get_conv_result(self).unwrap().conv_value >> G_LPADC_RESULT_SHIFT;
214 Ok(result)
215 }
216}
217
218impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
219 /// 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> {
221 let adc = I::ptr();
222
223 _ = unsafe {
134 enable_and_reset::<I>(&AdcConfig { 224 enable_and_reset::<I>(&AdcConfig {
135 power: config.power, 225 power: config.power,
136 source: config.source, 226 source: config.source,
137 div: config.div, 227 div: config.div,
138 }) 228 })
139 .expect("Adc Init should not fail") 229 .map_err(Error::ClockSetup)?
140 }; 230 };
141 231
232 pin.mux();
233
142 /* Reset the module. */ 234 /* Reset the module. */
143 adc.ctrl().modify(|_, w| w.rst().held_in_reset()); 235 adc.ctrl().modify(|_, w| w.rst().held_in_reset());
144 adc.ctrl().modify(|_, w| w.rst().released_from_reset()); 236 adc.ctrl().modify(|_, w| w.rst().released_from_reset());
@@ -220,18 +312,22 @@ impl<'a, I: Instance> Adc<'a, I> {
220 // Enable ADC 312 // Enable ADC
221 adc.ctrl().modify(|_, w| w.adcen().enabled()); 313 adc.ctrl().modify(|_, w| w.adcen().enabled());
222 314
223 Self { 315 Ok(Self {
224 _inst: core::marker::PhantomData, 316 _inst: PhantomData,
225 } 317 _phantom: PhantomData,
318 })
226 } 319 }
227 320
321 /// Deinitialize the ADC peripheral.
228 pub fn deinit(&self) { 322 pub fn deinit(&self) {
229 let adc = unsafe { &*I::ptr() }; 323 let adc = I::ptr();
230 adc.ctrl().modify(|_, w| w.adcen().disabled()); 324 adc.ctrl().modify(|_, w| w.adcen().disabled());
231 } 325 }
232 326
327 /// Perform offset calibration.
328 /// Waits for calibration to complete before returning.
233 pub fn do_offset_calibration(&self) { 329 pub fn do_offset_calibration(&self) {
234 let adc = unsafe { &*I::ptr() }; 330 let adc = I::ptr();
235 // Enable calibration mode 331 // Enable calibration mode
236 adc.ctrl() 332 adc.ctrl()
237 .modify(|_, w| w.calofs().offset_calibration_request_pending()); 333 .modify(|_, w| w.calofs().offset_calibration_request_pending());
@@ -240,6 +336,13 @@ impl<'a, I: Instance> Adc<'a, I> {
240 while adc.stat().read().cal_rdy().is_not_set() {} 336 while adc.stat().read().cal_rdy().is_not_set() {}
241 } 337 }
242 338
339 /// Calculate gain conversion result from gain adjustment factor.
340 ///
341 /// # Arguments
342 /// * `gain_adjustment` - Gain adjustment factor
343 ///
344 /// # Returns
345 /// Gain calibration register value
243 pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 { 346 pub fn get_gain_conv_result(&self, mut gain_adjustment: f32) -> u32 {
244 let mut gcra_array = [0u32; 17]; 347 let mut gcra_array = [0u32; 17];
245 let mut gcalr: u32 = 0; 348 let mut gcalr: u32 = 0;
@@ -258,8 +361,9 @@ impl<'a, I: Instance> Adc<'a, I> {
258 gcalr 361 gcalr
259 } 362 }
260 363
364 /// Perform automatic gain calibration.
261 pub fn do_auto_calibration(&self) { 365 pub fn do_auto_calibration(&self) {
262 let adc = unsafe { &*I::ptr() }; 366 let adc = I::ptr();
263 adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); 367 adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending());
264 368
265 while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} 369 while adc.gcc0().read().rdy().is_gain_cal_not_valid() {}
@@ -280,14 +384,23 @@ impl<'a, I: Instance> Adc<'a, I> {
280 while adc.stat().read().cal_rdy().is_not_set() {} 384 while adc.stat().read().cal_rdy().is_not_set() {}
281 } 385 }
282 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)
283 pub fn do_software_trigger(&self, trigger_id_mask: u32) { 394 pub fn do_software_trigger(&self, trigger_id_mask: u32) {
284 let adc = unsafe { &*I::ptr() }; 395 let adc = I::ptr();
285 adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) }); 396 adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask) });
286 } 397 }
287 398
399 /// Get default conversion command configuration.
400 /// # Returns
401 /// Default conversion command configuration
288 pub fn get_default_conv_command_config(&self) -> ConvCommandConfig { 402 pub fn get_default_conv_command_config(&self) -> ConvCommandConfig {
289 ConvCommandConfig { 403 ConvCommandConfig {
290 sample_channel_mode: Ctype::SingleEndedASideChannel,
291 channel_number: Adch::SelectCh0, 404 channel_number: Adch::SelectCh0,
292 chained_next_command_number: Next::NoNextCmdTerminateOnFinish, 405 chained_next_command_number: Next::NoNextCmdTerminateOnFinish,
293 enable_auto_channel_increment: false, 406 enable_auto_channel_increment: false,
@@ -302,42 +415,72 @@ impl<'a, I: Instance> Adc<'a, I> {
302 } 415 }
303 } 416 }
304 417
305 //TBD Need to add cmdlx and cmdhx with x {2..7} 418 /// Set conversion command configuration.
306 pub fn set_conv_command_config(&self, index: u32, config: &ConvCommandConfig) { 419 ///
307 let adc = unsafe { &*I::ptr() }; 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
437 macro_rules! write_cmd {
438 ($idx:expr) => {{
439 paste! {
440 adc.[<cmdl $idx>]().write(|w| {
441 w.adch()
442 .variant(config.channel_number)
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 }
308 465
309 match index { 466 match index {
310 1 => { 467 1 => write_cmd!(1),
311 adc.cmdl1().write(|w| { 468 2 => write_cmd!(2),
312 w.adch() 469 3 => write_cmd!(3),
313 .variant(config.channel_number) 470 4 => write_cmd!(4),
314 .mode() 471 5 => write_cmd!(5),
315 .variant(config.conversion_resolution_mode) 472 6 => write_cmd!(6),
316 }); 473 7 => write_cmd!(7),
317 adc.cmdh1().write(|w| unsafe { 474 _ => unreachable!(),
318 w.next()
319 .variant(config.chained_next_command_number)
320 .loop_()
321 .bits(config.loop_count)
322 .avgs()
323 .variant(config.hardware_average_mode)
324 .sts()
325 .variant(config.sample_time_mode)
326 .cmpen()
327 .variant(config.hardware_compare_mode);
328 if config.enable_wait_trigger {
329 w.wait_trig().enabled();
330 }
331 if config.enable_auto_channel_increment {
332 w.lwi().enabled();
333 }
334 w
335 });
336 }
337 _ => panic!("Invalid command index: must be between 1 and 7"),
338 } 475 }
476
477 Ok(())
339 } 478 }
340 479
480 /// Get default conversion trigger configuration.
481 ///
482 /// # Returns
483 /// Default conversion trigger configuration
341 pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig { 484 pub fn get_default_conv_trigger_config(&self) -> ConvTriggerConfig {
342 ConvTriggerConfig { 485 ConvTriggerConfig {
343 target_command_id: Tcmd::NotValid, 486 target_command_id: Tcmd::NotValid,
@@ -347,8 +490,16 @@ impl<'a, I: Instance> Adc<'a, I> {
347 } 490 }
348 } 491 }
349 492
493 /// Set conversion trigger configuration.
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
350 pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) { 501 pub fn set_conv_trigger_config(&self, trigger_id: usize, config: &ConvTriggerConfig) {
351 let adc = unsafe { &*I::ptr() }; 502 let adc = I::ptr();
352 let tctrl = &adc.tctrl(trigger_id); 503 let tctrl = &adc.tctrl(trigger_id);
353 504
354 tctrl.write(|w| unsafe { 505 tctrl.write(|w| unsafe {
@@ -363,47 +514,239 @@ impl<'a, I: Instance> Adc<'a, I> {
363 }); 514 });
364 } 515 }
365 516
517 /// Reset the FIFO buffer.
518 ///
519 /// Clears all pending conversion results from the FIFO.
366 pub fn do_reset_fifo(&self) { 520 pub fn do_reset_fifo(&self) {
367 let adc = unsafe { &*I::ptr() }; 521 let adc = I::ptr();
368 adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); 522 adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
369 } 523 }
370 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
371 pub fn enable_interrupt(&self, mask: u32) { 531 pub fn enable_interrupt(&self, mask: u32) {
372 let adc = unsafe { &*I::ptr() }; 532 let adc = I::ptr();
373 adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) }); 533 adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) });
374 INTERRUPT_TRIGGERED.store(false, Ordering::SeqCst);
375 } 534 }
376 535
377 pub fn is_interrupt_triggered(&self) -> bool { 536 /// Disable ADC interrupts.
378 INTERRUPT_TRIGGERED.load(Ordering::Relaxed) 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 }
546
547 /// Get conversion result from FIFO.
548 ///
549 /// Reads and returns the next conversion result from the FIFO.
550 /// Returns `None` if the FIFO is empty.
551 ///
552 /// # Returns
553 /// - `Some(ConvResult)` if a result is available
554 /// - `Err(Error::FifoEmpty)` if the FIFO is empty
555 pub fn get_conv_result(&self) -> Result<ConvResult> {
556 let adc = I::ptr();
557 let fifo = adc.resfifo0().read();
558 if !fifo.valid().is_valid() {
559 return Err(Error::FifoEmpty);
560 }
561
562 Ok(ConvResult {
563 command_id_source: fifo.cmdsrc().bits(),
564 loop_count_index: fifo.loopcnt().bits(),
565 trigger_id_source: fifo.tsrc().bits(),
566 conv_value: fifo.d().bits(),
567 })
379 } 568 }
380} 569}
381 570
382pub fn get_conv_result() -> Option<ConvResult> { 571impl<T: Instance> Handler<T::Interrupt> for InterruptHandler<T> {
383 let adc = unsafe { &*pac::Adc1::ptr() }; 572 unsafe fn on_interrupt() {
384 let fifo = adc.resfifo0().read().bits(); 573 T::ptr().ie().modify(|r, w| w.bits(r.bits() & !0x1));
385 const VALID_MASK: u32 = 1 << 31; 574 T::wait_cell().wake();
386 if fifo & VALID_MASK == 0 {
387 return None;
388 } 575 }
576}
389 577
390 Some(ConvResult { 578mod sealed {
391 command_id_source: (fifo >> 24) & 0x0F, 579 /// Seal a trait
392 loop_count_index: (fifo >> 20) & 0x0F, 580 pub trait Sealed {}
393 trigger_id_source: (fifo >> 16) & 0x0F,
394 conv_value: (fifo & 0xFFFF) as u16,
395 })
396} 581}
397 582
398pub fn on_interrupt() { 583impl<I: GpioPin> sealed::Sealed for I {}
399 if get_conv_result().is_some() { 584
400 INTERRUPT_TRIGGERED.store(true, Ordering::SeqCst); 585trait SealedInstance {
401 } 586 fn ptr() -> &'static pac::adc0::RegisterBlock;
587 fn wait_cell() -> &'static WaitCell;
402} 588}
403 589
404pub struct AdcHandler; 590/// ADC Instance
405impl crate::interrupt::typelevel::Handler<crate::interrupt::typelevel::ADC1> for AdcHandler { 591#[allow(private_bounds)]
406 unsafe fn on_interrupt() { 592pub trait Instance: SealedInstance + PeripheralType + Gate<MrccPeriphConfig = AdcConfig> {
407 on_interrupt(); 593 /// Interrupt for this ADC instance.
408 } 594 type Interrupt: Interrupt;
409} 595}
596
597macro_rules! impl_instance {
598 ($($n:expr),*) => {
599 $(
600 paste!{
601 impl SealedInstance for crate::peripherals::[<ADC $n>] {
602 fn ptr() -> &'static pac::adc0::RegisterBlock {
603 unsafe { &*pac::[<Adc $n>]::ptr() }
604 }
605
606 fn wait_cell() -> &'static WaitCell {
607 static WAIT_CELL: WaitCell = WaitCell::new();
608 &WAIT_CELL
609 }
610
611 }
612
613 impl Instance for crate::peripherals::[<ADC $n>] {
614 type Interrupt = crate::interrupt::typelevel::[<ADC $n>];
615 }
616 }
617 )*
618 };
619}
620
621impl_instance!(0, 1, 2, 3);
622
623pub trait AdcPin<Instance>: GpioPin + sealed::Sealed + PeripheralType {
624 /// Set the given pin to the correct muxing state
625 fn mux(&self);
626}
627
628/// Driver mode.
629#[allow(private_bounds)]
630pub trait ModeAdc: sealed::Sealed {}
631
632/// Blocking mode.
633pub struct Blocking;
634impl sealed::Sealed for Blocking {}
635impl ModeAdc for Blocking {}
636
637/// Async mode.
638pub struct Async;
639impl sealed::Sealed for Async {}
640impl ModeAdc for Async {}
641
642macro_rules! impl_pin {
643 ($pin:ident, $peri:ident, $func:ident, $trait:ident) => {
644 impl $trait<crate::peripherals::$peri> for crate::peripherals::$pin {
645 fn mux(&self) {
646 self.set_pull(crate::gpio::Pull::Disabled);
647 self.set_slew_rate(crate::gpio::SlewRate::Fast.into());
648 self.set_drive_strength(crate::gpio::DriveStrength::Normal.into());
649 self.set_function(crate::pac::port0::pcr0::Mux::$func);
650 }
651 }
652 };
653}
654
655impl_pin!(P2_0, ADC0, Mux0, AdcPin);
656impl_pin!(P2_4, ADC0, Mux0, AdcPin);
657impl_pin!(P2_15, ADC0, Mux0, AdcPin);
658impl_pin!(P2_3, ADC0, Mux0, AdcPin);
659impl_pin!(P2_2, ADC0, Mux0, AdcPin);
660impl_pin!(P2_12, ADC0, Mux0, AdcPin);
661impl_pin!(P2_16, ADC0, Mux0, AdcPin);
662impl_pin!(P2_7, ADC0, Mux0, AdcPin);
663impl_pin!(P0_18, ADC0, Mux0, AdcPin);
664impl_pin!(P0_19, ADC0, Mux0, AdcPin);
665impl_pin!(P0_20, ADC0, Mux0, AdcPin);
666impl_pin!(P0_21, ADC0, Mux0, AdcPin);
667impl_pin!(P0_22, ADC0, Mux0, AdcPin);
668impl_pin!(P0_23, ADC0, Mux0, AdcPin);
669impl_pin!(P0_3, ADC0, Mux0, AdcPin);
670impl_pin!(P0_6, ADC0, Mux0, AdcPin);
671impl_pin!(P1_0, ADC0, Mux0, AdcPin);
672impl_pin!(P1_1, ADC0, Mux0, AdcPin);
673impl_pin!(P1_2, ADC0, Mux0, AdcPin);
674impl_pin!(P1_3, ADC0, Mux0, AdcPin);
675impl_pin!(P1_4, ADC0, Mux0, AdcPin);
676impl_pin!(P1_5, ADC0, Mux0, AdcPin);
677impl_pin!(P1_6, ADC0, Mux0, AdcPin);
678impl_pin!(P1_7, ADC0, Mux0, AdcPin);
679impl_pin!(P1_10, ADC0, Mux0, AdcPin);
680
681impl_pin!(P2_1, ADC1, Mux0, AdcPin);
682impl_pin!(P2_5, ADC1, Mux0, AdcPin);
683impl_pin!(P2_19, ADC1, Mux0, AdcPin);
684impl_pin!(P2_6, ADC1, Mux0, AdcPin);
685impl_pin!(P2_3, ADC1, Mux0, AdcPin);
686impl_pin!(P2_13, ADC1, Mux0, AdcPin);
687impl_pin!(P2_17, ADC1, Mux0, AdcPin);
688impl_pin!(P2_7, ADC1, Mux0, AdcPin);
689impl_pin!(P1_10, ADC1, Mux0, AdcPin);
690impl_pin!(P1_11, ADC1, Mux0, AdcPin);
691impl_pin!(P1_12, ADC1, Mux0, AdcPin);
692impl_pin!(P1_13, ADC1, Mux0, AdcPin);
693impl_pin!(P1_14, ADC1, Mux0, AdcPin);
694impl_pin!(P1_15, ADC1, Mux0, AdcPin);
695impl_pin!(P1_16, ADC1, Mux0, AdcPin);
696impl_pin!(P1_17, ADC1, Mux0, AdcPin);
697impl_pin!(P1_18, ADC1, Mux0, AdcPin);
698impl_pin!(P1_19, ADC1, Mux0, AdcPin);
699impl_pin!(P3_31, ADC1, Mux0, AdcPin);
700impl_pin!(P3_30, ADC1, Mux0, AdcPin);
701impl_pin!(P3_29, ADC1, Mux0, AdcPin);
702
703impl_pin!(P2_4, ADC2, Mux0, AdcPin);
704impl_pin!(P2_10, ADC2, Mux0, AdcPin);
705impl_pin!(P4_4, ADC2, Mux0, AdcPin);
706impl_pin!(P2_24, ADC2, Mux0, AdcPin);
707impl_pin!(P2_16, ADC2, Mux0, AdcPin);
708impl_pin!(P2_12, ADC2, Mux0, AdcPin);
709impl_pin!(P2_20, ADC2, Mux0, AdcPin);
710impl_pin!(P2_7, ADC2, Mux0, AdcPin);
711impl_pin!(P0_2, ADC2, Mux0, AdcPin);
712impl_pin!(P0_4, ADC2, Mux0, AdcPin);
713impl_pin!(P0_5, ADC2, Mux0, AdcPin);
714impl_pin!(P0_6, ADC2, Mux0, AdcPin);
715impl_pin!(P0_7, ADC2, Mux0, AdcPin);
716impl_pin!(P0_12, ADC2, Mux0, AdcPin);
717impl_pin!(P0_13, ADC2, Mux0, AdcPin);
718impl_pin!(P0_14, ADC2, Mux0, AdcPin);
719impl_pin!(P0_15, ADC2, Mux0, AdcPin);
720impl_pin!(P4_0, ADC2, Mux0, AdcPin);
721impl_pin!(P4_1, ADC2, Mux0, AdcPin);
722impl_pin!(P4_2, ADC2, Mux0, AdcPin);
723impl_pin!(P4_3, ADC2, Mux0, AdcPin);
724//impl_pin!(P4_4, ADC2, Mux0, AdcPin); // Conflit with ADC2_A3 and ADC2_A20 using the same pin
725impl_pin!(P4_5, ADC2, Mux0, AdcPin);
726impl_pin!(P4_6, ADC2, Mux0, AdcPin);
727impl_pin!(P4_7, ADC2, Mux0, AdcPin);
728
729impl_pin!(P2_5, ADC3, Mux0, AdcPin);
730impl_pin!(P2_11, ADC3, Mux0, AdcPin);
731impl_pin!(P2_23, ADC3, Mux0, AdcPin);
732impl_pin!(P2_25, ADC3, Mux0, AdcPin);
733impl_pin!(P2_17, ADC3, Mux0, AdcPin);
734impl_pin!(P2_13, ADC3, Mux0, AdcPin);
735impl_pin!(P2_21, ADC3, Mux0, AdcPin);
736impl_pin!(P2_7, ADC3, Mux0, AdcPin);
737impl_pin!(P3_2, ADC3, Mux0, AdcPin);
738impl_pin!(P3_3, ADC3, Mux0, AdcPin);
739impl_pin!(P3_4, ADC3, Mux0, AdcPin);
740impl_pin!(P3_5, ADC3, Mux0, AdcPin);
741impl_pin!(P3_6, ADC3, Mux0, AdcPin);
742impl_pin!(P3_7, ADC3, Mux0, AdcPin);
743impl_pin!(P3_12, ADC3, Mux0, AdcPin);
744impl_pin!(P3_13, ADC3, Mux0, AdcPin);
745impl_pin!(P3_14, ADC3, Mux0, AdcPin);
746impl_pin!(P3_15, ADC3, Mux0, AdcPin);
747impl_pin!(P3_20, ADC3, Mux0, AdcPin);
748impl_pin!(P3_21, ADC3, Mux0, AdcPin);
749impl_pin!(P3_22, ADC3, Mux0, AdcPin);
750impl_pin!(P3_23, ADC3, Mux0, AdcPin);
751impl_pin!(P3_24, ADC3, Mux0, AdcPin);
752impl_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))]
430pub enum AdcClockSel { 431pub 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..725f8d499 100644
--- a/embassy-mcxa/src/interrupt.rs
+++ b/embassy-mcxa/src/interrupt.rs
@@ -9,7 +9,10 @@
9mod generated { 9mod 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,
@@ -280,44 +283,6 @@ impl InterruptExt for Rtc {
280 } 283 }
281} 284}
282 285
283pub struct Adc;
284pub const ADC1: Adc = Adc;
285
286impl InterruptExt for Adc {
287 /// Clear any pending ADC1 in NVIC.
288 #[inline]
289 fn unpend(&self) {
290 cortex_m::peripheral::NVIC::unpend(Interrupt::ADC1);
291 }
292
293 /// Set NVIC priority for ADC1.
294 #[inline]
295 fn set_priority(&self, priority: Priority) {
296 unsafe {
297 let mut nvic = cortex_m::peripheral::Peripherals::steal().NVIC;
298 nvic.set_priority(Interrupt::ADC1, u8::from(priority));
299 }
300 }
301
302 /// Enable ADC1 in NVIC.
303 #[inline]
304 unsafe fn enable(&self) {
305 cortex_m::peripheral::NVIC::unmask(Interrupt::ADC1);
306 }
307
308 /// Disable ADC1 in NVIC.
309 #[inline]
310 unsafe fn disable(&self) {
311 cortex_m::peripheral::NVIC::mask(Interrupt::ADC1);
312 }
313
314 /// Check if ADC1 is pending in NVIC.
315 #[inline]
316 fn is_pending(&self) -> bool {
317 cortex_m::peripheral::NVIC::is_pending(Interrupt::ADC1)
318 }
319}
320
321pub struct Gpio0; 286pub struct Gpio0;
322pub const GPIO0: Gpio0 = Gpio0; 287pub const GPIO0: Gpio0 = Gpio0;
323 288
diff --git a/embassy-mcxa/src/lib.rs b/embassy-mcxa/src/lib.rs
index 1bbdffa06..be279e509 100644
--- a/embassy-mcxa/src/lib.rs
+++ b/embassy-mcxa/src/lib.rs
@@ -8,7 +8,6 @@
8pub mod clocks; // still provide clock helpers 8pub mod clocks; // still provide clock helpers
9pub mod dma; 9pub mod dma;
10pub mod gpio; 10pub mod gpio;
11pub mod pins; // pin mux helpers
12 11
13pub mod adc; 12pub mod adc;
14pub mod clkout; 13pub mod clkout;
@@ -26,6 +25,8 @@ pub use crate::pac::NVIC_PRIO_BITS;
26embassy_hal_internal::peripherals!( 25embassy_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
339pub use adc::Adc1 as Adc1Token;
340pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output}; 340pub use gpio::{AnyPin, Flex, Gpio as GpioToken, Input, Level, Output};
341pub use interrupt::InterruptExt; 341pub use interrupt::InterruptExt;
342#[cfg(feature = "unstable-pac")] 342#[cfg(feature = "unstable-pac")]
@@ -354,8 +354,6 @@ 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::ADC1.set_priority(cfg.adc_interrupt_priority);
358 // Apply user-configured priority early; enabling is left to examples/apps
359 crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority); 357 crate::interrupt::GPIO0.set_priority(cfg.gpio_interrupt_priority);
360 // Apply user-configured priority early; enabling is left to examples/apps 358 // Apply user-configured priority early; enabling is left to examples/apps
361 crate::interrupt::GPIO1.set_priority(cfg.gpio_interrupt_priority); 359 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).
2use crate::pac;
3
4/// Configure pins for ADC usage.
5///
6/// # Safety
7///
8/// Must be called after PORT clocks are enabled.
9pub 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}
diff --git a/examples/mcxa/src/bin/adc_interrupt.rs b/examples/mcxa/src/bin/adc_interrupt.rs
index c88b1fe8d..5876923a1 100644
--- a/examples/mcxa/src/bin/adc_interrupt.rs
+++ b/examples/mcxa/src/bin/adc_interrupt.rs
@@ -2,34 +2,31 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_adc_pins; 5use hal::adc::{Adc, InterruptHandler, LpadcConfig, TriggerPriorityPolicy};
6use hal::adc::{LpadcConfig, TriggerPriorityPolicy}; 6use hal::bind_interrupts;
7use hal::clocks::PoweredClock; 7use hal::clocks::PoweredClock;
8use hal::clocks::config::Div8;
8use hal::clocks::periph_helpers::{AdcClockSel, Div4}; 9use hal::clocks::periph_helpers::{AdcClockSel, Div4};
10use hal::config::Config;
9use hal::pac::adc1::cfg::{Pwrsel, Refsel}; 11use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode}; 12use hal::pac::adc1::cmdl1::{Adch, Mode};
11use hal::pac::adc1::ctrl::CalAvgs; 13use hal::pac::adc1::ctrl::CalAvgs;
12use hal::pac::adc1::tctrl::Tcmd; 14use hal::pac::adc1::tctrl::Tcmd;
13use hal::{InterruptExt, bind_interrupts}; 15use hal::peripherals::ADC1;
14use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 16use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
15 17
16bind_interrupts!(struct Irqs { 18bind_interrupts!(struct Irqs {
17 ADC1 => hal::adc::AdcHandler; 19 ADC1 => InterruptHandler<ADC1>;
18}); 20});
19 21
20#[used]
21#[no_mangle]
22static KEEP_ADC: unsafe extern "C" fn() = ADC1;
23
24#[embassy_executor::main] 22#[embassy_executor::main]
25async fn main(_spawner: Spawner) { 23async fn main(_spawner: Spawner) {
26 let p = hal::init(hal::config::Config::default()); 24 let mut config = Config::default();
25 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
27 26
28 defmt::info!("ADC interrupt Example"); 27 let p = hal::init(config);
29 28
30 unsafe { 29 defmt::info!("ADC interrupt Example");
31 init_adc_pins();
32 }
33 30
34 let adc_config = LpadcConfig { 31 let adc_config = LpadcConfig {
35 enable_in_doze_mode: true, 32 enable_in_doze_mode: true,
@@ -46,7 +43,7 @@ async fn main(_spawner: Spawner) {
46 source: AdcClockSel::FroLfDiv, 43 source: AdcClockSel::FroLfDiv,
47 div: Div4::no_div(), 44 div: Div4::no_div(),
48 }; 45 };
49 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 46 let mut adc = Adc::new_async(p.ADC1, p.P1_10, Irqs, adc_config).unwrap();
50 47
51 adc.do_offset_calibration(); 48 adc.do_offset_calibration();
52 adc.do_auto_calibration(); 49 adc.do_auto_calibration();
@@ -54,7 +51,7 @@ async fn main(_spawner: Spawner) {
54 let mut conv_command_config = adc.get_default_conv_command_config(); 51 let mut conv_command_config = adc.get_default_conv_command_config();
55 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; 52 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
56 conv_command_config.conversion_resolution_mode = Mode::Data16Bits; 53 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
57 adc.set_conv_command_config(1, &conv_command_config); 54 adc.set_conv_command_config(1, &conv_command_config).unwrap();
58 55
59 let mut conv_trigger_config = adc.get_default_conv_trigger_config(); 56 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
60 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; 57 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
@@ -63,22 +60,14 @@ async fn main(_spawner: Spawner) {
63 60
64 defmt::info!("ADC configuration done..."); 61 defmt::info!("ADC configuration done...");
65 62
66 adc.enable_interrupt(0x1);
67
68 unsafe {
69 hal::interrupt::ADC1.enable();
70 }
71
72 unsafe {
73 cortex_m::interrupt::enable();
74 }
75
76 loop { 63 loop {
77 adc.do_software_trigger(1); 64 match adc.read().await {
78 while !adc.is_interrupt_triggered() { 65 Ok(value) => {
79 // Wait until the interrupt is triggered 66 defmt::info!("*** ADC interrupt TRIGGERED! *** -- value: {}", value);
67 }
68 Err(e) => {
69 defmt::error!("ADC read error: {:?}", e);
70 }
80 } 71 }
81 defmt::info!("*** ADC interrupt TRIGGERED! ***");
82 //TBD need to print the value
83 } 72 }
84} 73}
diff --git a/examples/mcxa/src/bin/adc_polling.rs b/examples/mcxa/src/bin/adc_polling.rs
index 07c50f224..d048bb56f 100644
--- a/examples/mcxa/src/bin/adc_polling.rs
+++ b/examples/mcxa/src/bin/adc_polling.rs
@@ -2,10 +2,11 @@
2#![no_main] 2#![no_main]
3 3
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use embassy_mcxa_examples::init_adc_pins; 5use hal::adc::{Adc, LpadcConfig, TriggerPriorityPolicy};
6use hal::adc::{ConvResult, LpadcConfig, TriggerPriorityPolicy};
7use hal::clocks::PoweredClock; 6use hal::clocks::PoweredClock;
7use hal::clocks::config::Div8;
8use hal::clocks::periph_helpers::{AdcClockSel, Div4}; 8use hal::clocks::periph_helpers::{AdcClockSel, Div4};
9use hal::config::Config;
9use hal::pac::adc1::cfg::{Pwrsel, Refsel}; 10use hal::pac::adc1::cfg::{Pwrsel, Refsel};
10use hal::pac::adc1::cmdl1::{Adch, Mode}; 11use hal::pac::adc1::cmdl1::{Adch, Mode};
11use hal::pac::adc1::ctrl::CalAvgs; 12use hal::pac::adc1::ctrl::CalAvgs;
@@ -16,11 +17,10 @@ const G_LPADC_RESULT_SHIFT: u32 = 0;
16 17
17#[embassy_executor::main] 18#[embassy_executor::main]
18async fn main(_spawner: Spawner) { 19async fn main(_spawner: Spawner) {
19 let p = hal::init(hal::config::Config::default()); 20 let mut config = Config::default();
21 config.clock_cfg.sirc.fro_lf_div = Div8::from_divisor(1);
20 22
21 unsafe { 23 let p = hal::init(config);
22 init_adc_pins();
23 }
24 24
25 defmt::info!("=== ADC polling Example ==="); 25 defmt::info!("=== ADC polling Example ===");
26 26
@@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) {
39 source: AdcClockSel::FroLfDiv, 39 source: AdcClockSel::FroLfDiv,
40 div: Div4::no_div(), 40 div: Div4::no_div(),
41 }; 41 };
42 let adc = hal::adc::Adc::<hal::adc::Adc1>::new(p.ADC1, adc_config); 42 let adc = Adc::new_blocking(p.ADC1, p.P1_10, adc_config).unwrap();
43 43
44 adc.do_offset_calibration(); 44 adc.do_offset_calibration();
45 adc.do_auto_calibration(); 45 adc.do_auto_calibration();
@@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) {
47 let mut conv_command_config = adc.get_default_conv_command_config(); 47 let mut conv_command_config = adc.get_default_conv_command_config();
48 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8; 48 conv_command_config.channel_number = Adch::SelectCorrespondingChannel8;
49 conv_command_config.conversion_resolution_mode = Mode::Data16Bits; 49 conv_command_config.conversion_resolution_mode = Mode::Data16Bits;
50 adc.set_conv_command_config(1, &conv_command_config); 50 adc.set_conv_command_config(1, &conv_command_config).unwrap();
51 51
52 let mut conv_trigger_config = adc.get_default_conv_trigger_config(); 52 let mut conv_trigger_config = adc.get_default_conv_trigger_config();
53 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1; 53 conv_trigger_config.target_command_id = Tcmd::ExecuteCmd1;
@@ -58,11 +58,15 @@ async fn main(_spawner: Spawner) {
58 58
59 loop { 59 loop {
60 adc.do_software_trigger(1); 60 adc.do_software_trigger(1);
61 let mut result: Option<ConvResult> = None; 61 let result = loop {
62 while result.is_none() { 62 match adc.get_conv_result() {
63 result = hal::adc::get_conv_result(); 63 Ok(res) => break res,
64 } 64 Err(_) => {
65 let value = result.unwrap().conv_value >> G_LPADC_RESULT_SHIFT; 65 // Conversion not ready, continue polling
66 defmt::info!("value: {=u16}", value); 66 }
67 }
68 };
69 let value = result.conv_value >> G_LPADC_RESULT_SHIFT;
70 defmt::info!("ADC value: {=u16}", value);
67 } 71 }
68} 72}
diff --git a/examples/mcxa/src/lib.rs b/examples/mcxa/src/lib.rs
deleted file mode 100644
index 2573a6adc..000000000
--- a/examples/mcxa/src/lib.rs
+++ /dev/null
@@ -1,16 +0,0 @@
1#![no_std]
2#![allow(clippy::missing_safety_doc)]
3
4//! Shared board-specific helpers for the FRDM-MCXA276 examples.
5//! These live with the examples so the HAL stays generic.
6
7use hal::{clocks, pins};
8use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
9
10/// Initialize clocks and pin muxing for ADC.
11pub unsafe fn init_adc_pins() {
12 // NOTE: Lpuart has been updated to properly enable + reset its own clocks.
13 // GPIO has not.
14 _ = clocks::enable_and_reset::<hal::peripherals::PORT1>(&clocks::periph_helpers::NoConfig);
15 pins::configure_adc_pins();
16}