aboutsummaryrefslogtreecommitdiff
path: root/embassy-mcxa/src/adc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-mcxa/src/adc.rs')
-rw-r--r--embassy-mcxa/src/adc.rs129
1 files changed, 70 insertions, 59 deletions
diff --git a/embassy-mcxa/src/adc.rs b/embassy-mcxa/src/adc.rs
index e4b24cffa..c19f02431 100644
--- a/embassy-mcxa/src/adc.rs
+++ b/embassy-mcxa/src/adc.rs
@@ -173,20 +173,29 @@ pub struct InterruptHandler<I: Instance> {
173} 173}
174 174
175/// ADC driver instance. 175/// ADC driver instance.
176pub struct Adc<'a, I: Instance, M: ModeAdc> { 176pub struct Adc<'a, M: ModeAdc> {
177 _inst: PhantomData<&'a mut I>, 177 _inst: PhantomData<&'a mut ()>,
178 _phantom: PhantomData<M>, 178 mode: M,
179 index: u8, 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,
180} 185}
181 186
182impl<'a, I: Instance> Adc<'a, I, Blocking> { 187impl<'a> Adc<'a, Blocking> {
183 /// Create a new blocking instance of the ADC driver. 188 /// Create a new blocking instance of the ADC driver.
184 /// # Arguments 189 /// # Arguments
185 /// * `_inst` - ADC peripheral instance 190 /// * `_inst` - ADC peripheral instance
186 /// * `pin` - GPIO pin to use for ADC 191 /// * `pin` - GPIO pin to use for ADC
187 /// * `config` - ADC configuration 192 /// * `config` - ADC configuration
188 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>(
189 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)
190 } 199 }
191 200
192 /// Enable ADC interrupts. 201 /// Enable ADC interrupts.
@@ -196,8 +205,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> {
196 /// # Arguments 205 /// # Arguments
197 /// * `mask` - Bitmask of interrupt sources to enable 206 /// * `mask` - Bitmask of interrupt sources to enable
198 pub fn enable_interrupt(&mut self, mask: u32) { 207 pub fn enable_interrupt(&mut self, mask: u32) {
199 let adc = I::ptr(); 208 self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) });
200 adc.ie().modify(|r, w| unsafe { w.bits(r.bits() | mask) });
201 } 209 }
202 210
203 /// Disable ADC interrupts. 211 /// Disable ADC interrupts.
@@ -207,15 +215,14 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> {
207 /// # Arguments 215 /// # Arguments
208 /// * `mask` - Bitmask of interrupt sources to disable 216 /// * `mask` - Bitmask of interrupt sources to disable
209 pub fn disable_interrupt(&mut self, mask: u32) { 217 pub fn disable_interrupt(&mut self, mask: u32) {
210 let adc = I::ptr(); 218 self.info.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) });
211 adc.ie().modify(|r, w| unsafe { w.bits(r.bits() & !mask) });
212 } 219 }
213 220
214 pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> { 221 pub fn set_fifo_watermark(&mut self, watermark: u8) -> Result<()> {
215 if watermark > 0b111 { 222 if watermark > 0b111 {
216 return Err(Error::InvalidConfig); 223 return Err(Error::InvalidConfig);
217 } 224 }
218 I::ptr().fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) }); 225 self.info.fctrl0().modify(|_r, w| unsafe { w.fwmark().bits(watermark) });
219 Ok(()) 226 Ok(())
220 } 227 }
221 228
@@ -234,8 +241,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> {
234 if trigger_id_mask > 0b1111 { 241 if trigger_id_mask > 0b1111 {
235 return Err(Error::InvalidConfig); 242 return Err(Error::InvalidConfig);
236 } 243 }
237 let adc = I::ptr(); 244 self.info.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) });
238 adc.swtrig().write(|w| unsafe { w.bits(trigger_id_mask as u32) });
239 Ok(()) 245 Ok(())
240 } 246 }
241 247
@@ -271,8 +277,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> {
271 /// 277 ///
272 /// Clears all pending conversion results from the FIFO. 278 /// Clears all pending conversion results from the FIFO.
273 pub fn do_reset_fifo(&self) { 279 pub fn do_reset_fifo(&self) {
274 let adc = I::ptr(); 280 self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
275 adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
276 } 281 }
277 282
278 /// Get conversion result from FIFO. 283 /// Get conversion result from FIFO.
@@ -288,7 +293,7 @@ impl<'a, I: Instance> Adc<'a, I, Blocking> {
288 } 293 }
289} 294}
290 295
291impl<'a, I: Instance> Adc<'a, I, Async> { 296impl<'a> Adc<'a, Async> {
292 /// Initialize ADC with interrupt support. 297 /// Initialize ADC with interrupt support.
293 /// 298 ///
294 /// # Arguments 299 /// # Arguments
@@ -296,13 +301,13 @@ impl<'a, I: Instance> Adc<'a, I, Async> {
296 /// * `pin` - GPIO pin to use for ADC 301 /// * `pin` - GPIO pin to use for ADC
297 /// * `_irq` - Interrupt binding for this ADC instance 302 /// * `_irq` - Interrupt binding for this ADC instance
298 /// * `config` - ADC configuration 303 /// * `config` - ADC configuration
299 pub fn new_async( 304 pub fn new_async<I: Instance>(
300 _inst: Peri<'a, I>, 305 _inst: Peri<'a, I>,
301 pin: Peri<'a, impl AdcPin<I>>, 306 pin: Peri<'a, impl AdcPin<I>>,
302 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a, 307 _irq: impl crate::interrupt::typelevel::Binding<I::Interrupt, InterruptHandler<I>> + 'a,
303 config: LpadcConfig, 308 config: LpadcConfig,
304 ) -> Result<Self> { 309 ) -> Result<Self> {
305 let adc = Self::new_inner(_inst, pin, config)?; 310 let adc = Self::new_inner(_inst, pin, config, Async { waiter: I::wait_cell() })?;
306 311
307 I::Interrupt::unpend(); 312 I::Interrupt::unpend();
308 unsafe { I::Interrupt::enable() }; 313 unsafe { I::Interrupt::enable() };
@@ -343,24 +348,26 @@ impl<'a, I: Instance> Adc<'a, I, Async> {
343 pub fn set_averages(&mut self, avgs: Avgs) { 348 pub fn set_averages(&mut self, avgs: Avgs) {
344 // TODO: we should probably return a result or wait for idle? 349 // TODO: we should probably return a result or wait for idle?
345 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." 350 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior."
346 I::ptr().cmdh1().modify(|_r, w| w.avgs().variant(avgs)); 351 self.info.cmdh1().modify(|_r, w| w.avgs().variant(avgs));
347 } 352 }
348 353
349 /// Set the sample time 354 /// Set the sample time
350 pub fn set_sample_time(&mut self, st: Sts) { 355 pub fn set_sample_time(&mut self, st: Sts) {
351 // TODO: we should probably return a result or wait for idle? 356 // TODO: we should probably return a result or wait for idle?
352 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." 357 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior."
353 I::ptr().cmdh1().modify(|_r, w| w.sts().variant(st)); 358 self.info.cmdh1().modify(|_r, w| w.sts().variant(st));
354 } 359 }
355 360
356 pub fn set_resolution(&mut self, mode: Mode) { 361 pub fn set_resolution(&mut self, mode: Mode) {
357 // TODO: we should probably return a result or wait for idle? 362 // TODO: we should probably return a result or wait for idle?
358 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior." 363 // "A write to a CMD buffer while that CMD buffer is controlling the ADC operation may cause unpredictable behavior."
359 I::ptr().cmdl1().modify(|_r, w| w.mode().variant(mode)); 364 self.info.cmdl1().modify(|_r, w| w.mode().variant(mode));
360 } 365 }
361 366
362 fn wait_idle(&mut self) -> impl Future<Output = core::result::Result<(), maitake_sync::Closed>> + use<'_, I> { 367 fn wait_idle(&mut self) -> impl Future<Output = core::result::Result<(), maitake_sync::Closed>> + use<'_> {
363 I::wait_cell().wait_for(|| I::ptr().ie().read().fwmie0().bit_is_clear()) 368 self.mode
369 .waiter
370 .wait_for(|| self.info.ie().read().fwmie0().bit_is_clear())
364 } 371 }
365 372
366 /// Read ADC value asynchronously. 373 /// Read ADC value asynchronously.
@@ -376,18 +383,16 @@ impl<'a, I: Instance> Adc<'a, I, Async> {
376 /// # Returns 383 /// # Returns
377 /// 16-bit ADC conversion value 384 /// 16-bit ADC conversion value
378 pub async fn read(&mut self) -> Result<u16> { 385 pub async fn read(&mut self) -> Result<u16> {
379 let adc = I::ptr();
380
381 // If we cancelled a previous read, we might still be busy, wait 386 // If we cancelled a previous read, we might still be busy, wait
382 // until the interrupt is cleared (done by the interrupt) 387 // until the interrupt is cleared (done by the interrupt)
383 _ = self.wait_idle().await; 388 _ = self.wait_idle().await;
384 389
385 // Clear the fifo 390 // Clear the fifo
386 adc.ctrl().modify(|_, w| w.rstfifo0().trigger_reset()); 391 self.info.ctrl().modify(|_, w| w.rstfifo0().trigger_reset());
387 392
388 // Trigger a new conversion 393 // Trigger a new conversion
389 adc.ie().modify(|_r, w| w.fwmie0().set_bit()); 394 self.info.ie().modify(|_r, w| w.fwmie0().set_bit());
390 adc.swtrig().write(|w| w.swt0().set_bit()); 395 self.info.swtrig().write(|w| w.swt0().set_bit());
391 396
392 // Wait for completion 397 // Wait for completion
393 _ = self.wait_idle().await; 398 _ = self.wait_idle().await;
@@ -396,9 +401,14 @@ impl<'a, I: Instance> Adc<'a, I, Async> {
396 } 401 }
397} 402}
398 403
399impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { 404impl<'a, M: ModeAdc> Adc<'a, M> {
400 /// Internal initialization function shared by `new_async` and `new_blocking`. 405 /// Internal initialization function shared by `new_async` and `new_blocking`.
401 fn new_inner<P: AdcPin<I>>(_inst: Peri<'a, I>, pin: Peri<'a, P>, 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> {
402 let adc = I::ptr(); 412 let adc = I::ptr();
403 413
404 _ = unsafe { 414 _ = unsafe {
@@ -488,21 +498,22 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
488 498
489 Ok(Self { 499 Ok(Self {
490 _inst: PhantomData, 500 _inst: PhantomData,
491 _phantom: PhantomData, 501 mode,
492 index: P::CHANNEL, 502 channel_idx: P::CHANNEL,
503 info: adc,
493 }) 504 })
494 } 505 }
495 506
496 /// Perform offset calibration. 507 /// Perform offset calibration.
497 /// Waits for calibration to complete before returning. 508 /// Waits for calibration to complete before returning.
498 pub fn do_offset_calibration(&self) { 509 pub fn do_offset_calibration(&self) {
499 let adc = I::ptr();
500 // Enable calibration mode 510 // Enable calibration mode
501 adc.ctrl() 511 self.info
512 .ctrl()
502 .modify(|_, w| w.calofs().offset_calibration_request_pending()); 513 .modify(|_, w| w.calofs().offset_calibration_request_pending());
503 514
504 // Wait for calibration to complete (polling status register) 515 // Wait for calibration to complete (polling status register)
505 while adc.stat().read().cal_rdy().is_not_set() {} 516 while self.info.stat().read().cal_rdy().is_not_set() {}
506 } 517 }
507 518
508 /// Calculate gain conversion result from gain adjustment factor. 519 /// Calculate gain conversion result from gain adjustment factor.
@@ -532,12 +543,13 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
532 543
533 /// Perform automatic gain calibration. 544 /// Perform automatic gain calibration.
534 pub fn do_auto_calibration(&self) { 545 pub fn do_auto_calibration(&self) {
535 let adc = I::ptr(); 546 self.info
536 adc.ctrl().modify(|_, w| w.cal_req().calibration_request_pending()); 547 .ctrl()
548 .modify(|_, w| w.cal_req().calibration_request_pending());
537 549
538 while adc.gcc0().read().rdy().is_gain_cal_not_valid() {} 550 while self.info.gcc0().read().rdy().is_gain_cal_not_valid() {}
539 551
540 let mut gcca = adc.gcc0().read().gain_cal().bits() as u32; 552 let mut gcca = self.info.gcc0().read().gain_cal().bits() as u32;
541 if gcca & 0x8000 != 0 { 553 if gcca & 0x8000 != 0 {
542 gcca |= !0xFFFF; 554 gcca |= !0xFFFF;
543 } 555 }
@@ -545,31 +557,31 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
545 let gcra = 131072.0 / (131072.0 - gcca as f32); 557 let gcra = 131072.0 / (131072.0 - gcca as f32);
546 558
547 // Write to GCR0 559 // Write to GCR0
548 adc.gcr0().write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) }); 560 self.info
561 .gcr0()
562 .write(|w| unsafe { w.bits(self.get_gain_conv_result(gcra)) });
549 563
550 adc.gcr0().modify(|_, w| w.rdy().set_bit()); 564 self.info.gcr0().modify(|_, w| w.rdy().set_bit());
551 565
552 // Wait for calibration to complete (polling status register) 566 // Wait for calibration to complete (polling status register)
553 while adc.stat().read().cal_rdy().is_not_set() {} 567 while self.info.stat().read().cal_rdy().is_not_set() {}
554 } 568 }
555 569
556 fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> { 570 fn set_conv_command_config_inner(&self, index: usize, config: &ConvCommandConfig) -> Result<()> {
557 let adc = I::ptr();
558
559 let (cmdl, cmdh) = match index { 571 let (cmdl, cmdh) = match index {
560 1 => (adc.cmdl1(), adc.cmdh1()), 572 1 => (self.info.cmdl1(), self.info.cmdh1()),
561 2 => (adc.cmdl2(), adc.cmdh2()), 573 2 => (self.info.cmdl2(), self.info.cmdh2()),
562 3 => (adc.cmdl3(), adc.cmdh3()), 574 3 => (self.info.cmdl3(), self.info.cmdh3()),
563 4 => (adc.cmdl4(), adc.cmdh4()), 575 4 => (self.info.cmdl4(), self.info.cmdh4()),
564 5 => (adc.cmdl5(), adc.cmdh5()), 576 5 => (self.info.cmdl5(), self.info.cmdh5()),
565 6 => (adc.cmdl6(), adc.cmdh6()), 577 6 => (self.info.cmdl6(), self.info.cmdh6()),
566 7 => (adc.cmdl7(), adc.cmdh7()), 578 7 => (self.info.cmdl7(), self.info.cmdh7()),
567 _ => return Err(Error::InvalidConfig), 579 _ => return Err(Error::InvalidConfig),
568 }; 580 };
569 581
570 cmdl.write(|w| { 582 cmdl.write(|w| {
571 unsafe { 583 unsafe {
572 w.adch().bits(self.index); 584 w.adch().bits(self.channel_idx);
573 } 585 }
574 w.mode().variant(config.conversion_resolution_mode) 586 w.mode().variant(config.conversion_resolution_mode)
575 }); 587 });
@@ -591,14 +603,12 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
591 } 603 }
592 604
593 fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> { 605 fn set_conv_trigger_config_inner(&self, trigger_id: usize, config: &ConvTriggerConfig) -> Result<()> {
594 let adc = I::ptr();
595
596 // 0..4 are valid 606 // 0..4 are valid
597 if trigger_id >= 4 { 607 if trigger_id >= 4 {
598 return Err(Error::InvalidConfig); 608 return Err(Error::InvalidConfig);
599 } 609 }
600 610
601 let tctrl = &adc.tctrl(trigger_id); 611 let tctrl = &self.info.tctrl(trigger_id);
602 612
603 tctrl.write(|w| { 613 tctrl.write(|w| {
604 w.tcmd().variant(config.target_command_id); 614 w.tcmd().variant(config.target_command_id);
@@ -625,8 +635,7 @@ impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> {
625 /// - `Some(ConvResult)` if a result is available 635 /// - `Some(ConvResult)` if a result is available
626 /// - `Err(Error::FifoEmpty)` if the FIFO is empty 636 /// - `Err(Error::FifoEmpty)` if the FIFO is empty
627 fn get_conv_result_inner(&self) -> Result<ConvResult> { 637 fn get_conv_result_inner(&self) -> Result<ConvResult> {
628 let adc = I::ptr(); 638 let fifo = self.info.resfifo0().read();
629 let fifo = adc.resfifo0().read();
630 if !fifo.valid().is_valid() { 639 if !fifo.valid().is_valid() {
631 return Err(Error::FifoEmpty); 640 return Err(Error::FifoEmpty);
632 } 641 }
@@ -709,7 +718,9 @@ impl sealed::Sealed for Blocking {}
709impl ModeAdc for Blocking {} 718impl ModeAdc for Blocking {}
710 719
711/// Async mode. 720/// Async mode.
712pub struct Async; 721pub struct Async {
722 waiter: &'static WaitCell,
723}
713impl sealed::Sealed for Async {} 724impl sealed::Sealed for Async {}
714impl ModeAdc for Async {} 725impl ModeAdc for Async {}
715 726