diff options
Diffstat (limited to 'embassy-mcxa/src')
| -rw-r--r-- | embassy-mcxa/src/adc.rs | 129 |
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. |
| 176 | pub struct Adc<'a, I: Instance, M: ModeAdc> { | 176 | pub 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 | ||
| 182 | impl<'a, I: Instance> Adc<'a, I, Blocking> { | 187 | impl<'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 | ||
| 291 | impl<'a, I: Instance> Adc<'a, I, Async> { | 296 | impl<'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 | ||
| 399 | impl<'a, I: Instance, M: ModeAdc> Adc<'a, I, M> { | 404 | impl<'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 {} | |||
| 709 | impl ModeAdc for Blocking {} | 718 | impl ModeAdc for Blocking {} |
| 710 | 719 | ||
| 711 | /// Async mode. | 720 | /// Async mode. |
| 712 | pub struct Async; | 721 | pub struct Async { |
| 722 | waiter: &'static WaitCell, | ||
| 723 | } | ||
| 713 | impl sealed::Sealed for Async {} | 724 | impl sealed::Sealed for Async {} |
| 714 | impl ModeAdc for Async {} | 725 | impl ModeAdc for Async {} |
| 715 | 726 | ||
