aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/adc/g4.rs251
-rw-r--r--embassy-stm32/src/adc/injected.rs28
-rw-r--r--examples/stm32g4/.cargo/config.toml20
-rw-r--r--examples/stm32g4/Cargo.toml2
-rw-r--r--examples/stm32g4/src/bin/adc_injected_and_regular.rs17
5 files changed, 191 insertions, 127 deletions
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs
index 5a36b0999..3767820cf 100644
--- a/embassy-stm32/src/adc/g4.rs
+++ b/embassy-stm32/src/adc/g4.rs
@@ -131,7 +131,8 @@ impl Prescaler {
131 } 131 }
132} 132}
133 133
134// Trigger source for ADC conversions 134// Trigger source for ADC conversions¨
135#[derive(Copy, Clone)]
135pub struct ConversionTrigger { 136pub struct ConversionTrigger {
136 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers 137 // See Table 166 and 167 in RM0440 Rev 9 for ADC1/2 External triggers
137 // Note that Injected and Regular channels uses different mappings 138 // Note that Injected and Regular channels uses different mappings
@@ -140,6 +141,7 @@ pub struct ConversionTrigger {
140} 141}
141 142
142// Conversion mode for regular ADC channels 143// Conversion mode for regular ADC channels
144#[derive(Copy, Clone)]
143pub enum RegularConversionMode { 145pub enum RegularConversionMode {
144 // Samples as fast as possible 146 // Samples as fast as possible
145 Continuous, 147 Continuous,
@@ -384,25 +386,23 @@ impl<'d, T: Instance> Adc<'d, T> {
384 self.read_channel(channel) 386 self.read_channel(channel)
385 } 387 }
386 388
389 /// Start regular adc conversion
387 pub(super) fn start() { 390 pub(super) fn start() {
388 // Start adc conversion
389 T::regs().cr().modify(|reg| { 391 T::regs().cr().modify(|reg| {
390 reg.set_adstart(true); 392 reg.set_adstart(true);
391 }); 393 });
392 } 394 }
393 395
396 /// Stop regular conversions
394 pub(super) fn stop() { 397 pub(super) fn stop() {
395 // Stop adc conversion 398 Self::stop_regular_conversions();
396 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
397 T::regs().cr().modify(|reg| {
398 reg.set_adstp(Adstp::STOP);
399 });
400 while T::regs().cr().read().adstart() {}
401 }
402 } 399 }
403 400
401 /// Teardown method for stopping regular ADC conversions
404 pub(super) fn teardown_adc() { 402 pub(super) fn teardown_adc() {
405 //disable dma control 403 Self::stop_regular_conversions();
404
405 // Disable dma control
406 T::regs().cfgr().modify(|reg| { 406 T::regs().cfgr().modify(|reg| {
407 reg.set_dmaen(Dmaen::DISABLE); 407 reg.set_dmaen(Dmaen::DISABLE);
408 }); 408 });
@@ -434,7 +434,8 @@ impl<'d, T: Instance> Adc<'d, T> {
434 /// defmt::info!("measurements: {}", measurements); 434 /// defmt::info!("measurements: {}", measurements);
435 /// ``` 435 /// ```
436 /// 436 ///
437 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. 437 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use
438 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
438 pub async fn read( 439 pub async fn read(
439 &mut self, 440 &mut self,
440 rx_dma: Peri<'_, impl RxDma<T>>, 441 rx_dma: Peri<'_, impl RxDma<T>>,
@@ -452,7 +453,7 @@ impl<'d, T: Instance> Adc<'d, T> {
452 ); 453 );
453 454
454 // Ensure no conversions are ongoing and ADC is enabled. 455 // Ensure no conversions are ongoing and ADC is enabled.
455 Self::cancel_conversions(); 456 Self::stop_regular_conversions();
456 self.enable(); 457 self.enable();
457 458
458 // Set sequence length 459 // Set sequence length
@@ -520,7 +521,7 @@ impl<'d, T: Instance> Adc<'d, T> {
520 transfer.await; 521 transfer.await;
521 522
522 // Ensure conversions are finished. 523 // Ensure conversions are finished.
523 Self::cancel_conversions(); 524 Self::stop_regular_conversions();
524 525
525 // Reset configuration. 526 // Reset configuration.
526 T::regs().cfgr().modify(|reg| { 527 T::regs().cfgr().modify(|reg| {
@@ -529,7 +530,7 @@ impl<'d, T: Instance> Adc<'d, T> {
529 } 530 }
530 531
531 /// Set external trigger for regular conversion sequence 532 /// Set external trigger for regular conversion sequence
532 pub fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) { 533 fn set_regular_conversion_trigger(&mut self, trigger: ConversionTrigger) {
533 T::regs().cfgr().modify(|r| { 534 T::regs().cfgr().modify(|r| {
534 r.set_extsel(trigger.channel); 535 r.set_extsel(trigger.channel);
535 r.set_exten(trigger.edge); 536 r.set_exten(trigger.edge);
@@ -547,21 +548,30 @@ impl<'d, T: Instance> Adc<'d, T> {
547 548
548 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. 549 /// Configures the ADC to use a DMA ring buffer for continuous data acquisition.
549 /// 550 ///
550 /// The `dma_buf` should be large enough to prevent DMA buffer overrun. 551 /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer
551 /// The length of the `dma_buf` should be a multiple of the ADC channel count. 552 /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended
552 /// For example, if 3 channels are measured, its length can be 3 * 40 = 120 measurements. 553 /// to configure `dma_buf` as a double buffer so that one half can be read while the other half
554 /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively
555 /// defines the period at which the buffer should be read.
556 ///
557 /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent
558 /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured.
559 /// For example, if 3 channels are measured and you want to store 40 samples per channel,
560 /// the buffer length should be `3 * 40 = 120`.
553 /// 561 ///
554 /// `read` method is used to read out measurements from the DMA ring buffer, and its buffer 562 /// # Parameters
555 /// should be exactly half of the `dma_buf` length. It is critical to call `read` frequently to 563 /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer.
556 /// prevent DMA buffer overrun. Or configure a software trigger for the regular ADC conversions 564 /// - `dma_buf`: The buffer where DMA stores ADC samples.
557 /// at a fixed interval. 565 /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions.
566 /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered).
558 /// 567 ///
559 /// [`read`]: #method.read 568 /// # Returns
569 /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling.
560 pub fn into_ring_buffered<'a>( 570 pub fn into_ring_buffered<'a>(
561 mut self, 571 mut self,
562 dma: Peri<'a, impl RxDma<T>>, 572 dma: Peri<'a, impl RxDma<T>>,
563 dma_buf: &'a mut [u16], 573 dma_buf: &'a mut [u16],
564 sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>, 574 sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
565 mode: RegularConversionMode, 575 mode: RegularConversionMode,
566 ) -> RingBufferedAdc<'a, T> { 576 ) -> RingBufferedAdc<'a, T> {
567 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); 577 assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF);
@@ -571,7 +581,7 @@ impl<'d, T: Instance> Adc<'d, T> {
571 "Asynchronous read sequence cannot be more than 16 in length" 581 "Asynchronous read sequence cannot be more than 16 in length"
572 ); 582 );
573 // reset conversions and enable the adc 583 // reset conversions and enable the adc
574 Self::cancel_conversions(); 584 Self::stop_regular_conversions();
575 self.enable(); 585 self.enable();
576 586
577 //adc side setup 587 //adc side setup
@@ -582,8 +592,8 @@ impl<'d, T: Instance> Adc<'d, T> {
582 }); 592 });
583 593
584 // Configure channels and ranks 594 // Configure channels and ranks
585 for (_i, (channel, sample_time)) in sequence.enumerate() { 595 for (_i, (mut channel, sample_time)) in sequence.enumerate() {
586 Self::configure_channel(channel, sample_time); 596 Self::configure_channel(&mut channel, sample_time);
587 597
588 match _i { 598 match _i {
589 0..=3 => { 599 0..=3 => {
@@ -640,79 +650,107 @@ impl<'d, T: Instance> Adc<'d, T> {
640 RingBufferedAdc::new(dma, dma_buf) 650 RingBufferedAdc::new(dma, dma_buf)
641 } 651 }
642 652
643 /// Configure a sequence of injected channels 653 /// Configures the ADC for injected conversions.
644 pub fn configure_injected_sequence<'a>( 654 ///
655 /// Injected conversions are separate from the regular conversion sequence and are typically
656 /// triggered by software or an external event. This method sets up a fixed-length sequence of
657 /// injected channels with specified sample times, the trigger source, and whether the end-of-sequence
658 /// interrupt should be enabled.
659 ///
660 /// # Parameters
661 /// - `sequence`: An array of tuples containing the ADC channels and their sample times. The length
662 /// `N` determines the number of injected ranks to configure (maximum 4 for STM32).
663 /// - `trigger`: The trigger source that starts the injected conversion sequence.
664 /// - `interrupt`: If `true`, enables the end-of-sequence (JEOS) interrupt for injected conversions.
665 ///
666 /// # Returns
667 /// An `InjectedAdc<T, N>` instance that represents the configured injected sequence. The returned
668 /// type encodes the sequence length `N` in its type, ensuring that reads return exactly `N` samples.
669 ///
670 /// # Panics
671 /// This function will panic if:
672 /// - `sequence` is empty.
673 /// - `sequence` length exceeds the maximum number of injected ranks (`NR_INJECTED_RANKS`).
674 ///
675 /// # Notes
676 /// - Injected conversions can run independently of regular ADC conversions.
677 /// - The order of channels in `sequence` determines the rank order in the injected sequence.
678 /// - Accessing samples beyond `N` will result in a panic; use the returned type
679 /// `InjectedAdc<T, N>` to enforce bounds at compile time.
680 pub fn setup_injected_conversions<'a, const N: usize>(
645 mut self, 681 mut self,
646 sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>, 682 sequence: [(AnyAdcChannel<T>, SampleTime); N],
647 trigger: ConversionTrigger, 683 trigger: ConversionTrigger,
648 ) -> InjectedAdc<T> { 684 interrupt: bool,
649 assert!(sequence.len() != 0, "Read sequence cannot be empty"); 685 ) -> InjectedAdc<T, N> {
686 assert!(N != 0, "Read sequence cannot be empty");
650 assert!( 687 assert!(
651 sequence.len() <= NR_INJECTED_RANKS, 688 N <= NR_INJECTED_RANKS,
652 "Read sequence cannot be more than 4 in length" 689 "Read sequence cannot be more than {} in length",
690 NR_INJECTED_RANKS
653 ); 691 );
654 692
655 // Ensure no conversions are ongoing and ADC is enabled. 693 Self::stop_regular_conversions();
656 Self::cancel_conversions();
657 self.enable(); 694 self.enable();
658 695
659 // Set sequence length 696 T::regs().jsqr().modify(|w| w.set_jl(N as u8 - 1));
660 T::regs().jsqr().modify(|w| {
661 w.set_jl(sequence.len() as u8 - 1);
662 });
663 697
664 // Configure channels and ranks 698 for (n, (mut channel, sample_time)) in sequence.into_iter().enumerate() {
665 for (n, (channel, sample_time)) in sequence.enumerate() { 699 Self::configure_channel(&mut channel, sample_time);
666 Self::configure_channel(channel, sample_time);
667 700
668 match n { 701 let idx = match n {
669 0..=3 => { 702 0..=3 => n,
670 T::regs().jsqr().modify(|w| { 703 4..=8 => n - 4,
671 w.set_jsq(n, channel.channel()); 704 9..=13 => n - 9,
672 }); 705 14..=15 => n - 14,
673 }
674 4..=8 => {
675 T::regs().jsqr().modify(|w| {
676 w.set_jsq(n - 4, channel.channel());
677 });
678 }
679 9..=13 => {
680 T::regs().jsqr().modify(|w| {
681 w.set_jsq(n - 9, channel.channel());
682 });
683 }
684 14..=15 => {
685 T::regs().jsqr().modify(|w| {
686 w.set_jsq(n - 14, channel.channel());
687 });
688 }
689 _ => unreachable!(), 706 _ => unreachable!(),
690 } 707 };
708
709 T::regs().jsqr().modify(|w| w.set_jsq(idx, channel.channel()));
691 } 710 }
692 711
693 T::regs().cfgr().modify(|reg| { 712 T::regs().cfgr().modify(|reg| reg.set_jdiscen(false));
694 reg.set_jdiscen(false); // Will convert all channels for each trigger
695 });
696 713
697 self.set_injected_conversion_trigger(trigger); 714 self.set_injected_conversion_trigger(trigger);
698 self.enable_injected_eos_interrupt(true); 715 self.enable_injected_eos_interrupt(interrupt);
699 716 Self::start_injected_conversions();
700 self.start_injected_conversion();
701
702 mem::forget(self);
703 717
704 InjectedAdc::new() 718 InjectedAdc::new(sequence) // InjectedAdc<'a, T, N> now borrows the channels
705 } 719 }
706 720
707 pub fn into_ring_buffered_and_injected<'a>( 721 /// Configures ADC for both regular conversions with a ring-buffered DMA and injected conversions.
722 ///
723 /// # Parameters
724 /// - `dma`: The DMA peripheral to use for the ring-buffered ADC transfers.
725 /// - `dma_buf`: The buffer to store DMA-transferred samples for regular conversions.
726 /// - `regular_sequence`: The sequence of channels and their sample times for regular conversions.
727 /// - `regular_conversion_mode`: The mode for regular conversions (e.g., continuous or triggered).
728 /// - `injected_sequence`: An array of channels and sample times for injected conversions (length `N`).
729 /// - `injected_trigger`: The trigger source for injected conversions.
730 /// - `injected_interrupt`: Whether to enable the end-of-sequence interrupt for injected conversions.
731 ///
732 /// Injected conversions are typically used with interrupts. If ADC1 and ADC2 are used in dual mode,
733 /// it is recommended to enable interrupts only for the ADC whose sequence takes the longest to complete.
734 ///
735 /// # Returns
736 /// A tuple containing:
737 /// 1. `RingBufferedAdc<'a, T>` — the configured ADC for regular conversions using DMA.
738 /// 2. `InjectedAdc<T, N>` — the configured ADC for injected conversions.
739 ///
740 /// # Safety
741 /// This function is `unsafe` because it clones the ADC peripheral handle unchecked. Both the
742 /// `RingBufferedAdc` and `InjectedAdc` take ownership of the handle and drop it independently.
743 /// Ensure no other code concurrently accesses the same ADC instance in a conflicting way.
744 pub fn into_ring_buffered_and_injected<'a, const N: usize>(
708 self, 745 self,
709 dma: Peri<'a, impl RxDma<T>>, 746 dma: Peri<'a, impl RxDma<T>>,
710 dma_buf: &'a mut [u16], 747 dma_buf: &'a mut [u16],
711 regular_sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>, 748 regular_sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<T>, SampleTime)>,
712 regular_conversion_mode: RegularConversionMode, 749 regular_conversion_mode: RegularConversionMode,
713 injected_sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<T>, SampleTime)>, 750 injected_sequence: [(AnyAdcChannel<T>, SampleTime); N],
714 injected_trigger: ConversionTrigger, 751 injected_trigger: ConversionTrigger,
715 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T>) { 752 injected_interrupt: bool,
753 ) -> (RingBufferedAdc<'a, T>, InjectedAdc<T, N>) {
716 unsafe { 754 unsafe {
717 ( 755 (
718 Self { 756 Self {
@@ -724,13 +762,25 @@ impl<'d, T: Instance> Adc<'d, T> {
724 adc: self.adc.clone_unchecked(), 762 adc: self.adc.clone_unchecked(),
725 sample_time: self.sample_time, 763 sample_time: self.sample_time,
726 } 764 }
727 .configure_injected_sequence(injected_sequence, injected_trigger), 765 .setup_injected_conversions(injected_sequence, injected_trigger, injected_interrupt),
728 ) 766 )
729 } 767 }
730 } 768 }
731 769
770 /// Stop injected conversions
771 pub(super) fn stop_injected_conversions() {
772 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
773 T::regs().cr().modify(|reg| {
774 reg.set_jadstp(Adstp::STOP);
775 });
776 // The software must poll JADSTART until the bit is reset before assuming the
777 // ADC is completely stopped
778 while T::regs().cr().read().jadstart() {}
779 }
780 }
781
732 /// Start injected ADC conversion 782 /// Start injected ADC conversion
733 pub fn start_injected_conversion(&mut self) { 783 pub(super) fn start_injected_conversions() {
734 T::regs().cr().modify(|reg| { 784 T::regs().cr().modify(|reg| {
735 reg.set_jadstart(true); 785 reg.set_jadstart(true);
736 }); 786 });
@@ -738,7 +788,7 @@ impl<'d, T: Instance> Adc<'d, T> {
738 788
739 /// Set external trigger for injected conversion sequence 789 /// Set external trigger for injected conversion sequence
740 /// Possible trigger values are seen in Table 167 in RM0440 Rev 9 790 /// Possible trigger values are seen in Table 167 in RM0440 Rev 9
741 pub fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) { 791 fn set_injected_conversion_trigger(&mut self, trigger: ConversionTrigger) {
742 T::regs().jsqr().modify(|r| { 792 T::regs().jsqr().modify(|r| {
743 r.set_jextsel(trigger.channel); 793 r.set_jextsel(trigger.channel);
744 r.set_jexten(trigger.edge); 794 r.set_jexten(trigger.edge);
@@ -746,23 +796,10 @@ impl<'d, T: Instance> Adc<'d, T> {
746 } 796 }
747 797
748 /// Enable end of injected sequence interrupt 798 /// Enable end of injected sequence interrupt
749 pub fn enable_injected_eos_interrupt(&mut self, enable: bool) { 799 fn enable_injected_eos_interrupt(&mut self, enable: bool) {
750 T::regs().ier().modify(|r| r.set_jeosie(enable)); 800 T::regs().ier().modify(|r| r.set_jeosie(enable));
751 } 801 }
752 802
753 /// Read sampled data from all injected ADC injected ranks
754 /// Clear the JEOS flag to allow a new injected sequence
755 pub(super) fn read_injected_samples() -> [u16; NR_INJECTED_RANKS] {
756 let mut data = [0u16; NR_INJECTED_RANKS];
757 for i in 0..NR_INJECTED_RANKS {
758 data[i] = T::regs().jdr(i).read().jdata();
759 }
760
761 // Clear JEOS by writing 1
762 T::regs().isr().modify(|r| r.set_jeos(true));
763 data
764 }
765
766 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 803 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
767 // Configure channel 804 // Configure channel
768 Self::set_channel_sample_time(channel.channel(), sample_time); 805 Self::set_channel_sample_time(channel.channel(), sample_time);
@@ -795,25 +832,31 @@ impl<'d, T: Instance> Adc<'d, T> {
795 } 832 }
796 } 833 }
797 834
798 fn cancel_conversions() { 835 // Stop regular conversions
799 // Cancel regular conversions 836 fn stop_regular_conversions() {
800 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 837 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
801 T::regs().cr().modify(|reg| { 838 T::regs().cr().modify(|reg| {
802 reg.set_adstp(Adstp::STOP); 839 reg.set_adstp(Adstp::STOP);
803 }); 840 });
841 // The software must poll ADSTART until the bit is reset before assuming the
842 // ADC is completely stopped
804 while T::regs().cr().read().adstart() {} 843 while T::regs().cr().read().adstart() {}
805 } 844 }
806 } 845 }
846}
807 847
808 #[allow(dead_code)] 848impl<T: Instance, const N: usize> InjectedAdc<T, N> {
809 pub(super) fn stop_injected_conversions() { 849 /// Read sampled data from all injected ADC injected ranks
810 // Cancel injected conversions 850 /// Clear the JEOS flag to allow a new injected sequence
811 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { 851 pub(super) fn read_injected_data() -> [u16; N] {
812 T::regs().cr().modify(|reg| { 852 let mut data = [0u16; N];
813 reg.set_jadstp(Adstp::STOP); 853 for i in 0..N {
814 }); 854 data[i] = T::regs().jdr(i).read().jdata();
815 while T::regs().cr().read().jadstart() {}
816 } 855 }
856
857 // Clear JEOS by writing 1
858 T::regs().isr().modify(|r| r.set_jeos(true));
859 data
817 } 860 }
818} 861}
819 862
diff --git a/embassy-stm32/src/adc/injected.rs b/embassy-stm32/src/adc/injected.rs
index 0efc47759..30a7cacc5 100644
--- a/embassy-stm32/src/adc/injected.rs
+++ b/embassy-stm32/src/adc/injected.rs
@@ -1,6 +1,7 @@
1use core::marker::PhantomData; 1use core::marker::PhantomData;
2use core::sync::atomic::{Ordering, compiler_fence}; 2use core::sync::atomic::{Ordering, compiler_fence};
3 3
4use super::{AnyAdcChannel, SampleTime};
4#[allow(unused_imports)] 5#[allow(unused_imports)]
5use embassy_hal_internal::Peri; 6use embassy_hal_internal::Peri;
6 7
@@ -8,29 +9,36 @@ use crate::adc::Adc;
8#[allow(unused_imports)] 9#[allow(unused_imports)]
9use crate::adc::Instance; 10use crate::adc::Instance;
10 11
11const NR_INJECTED_RANKS: usize = 4; 12/// Injected ADC sequence with owned channels.
12 13pub struct InjectedAdc<T: Instance, const N: usize> {
13pub struct InjectedAdc<T: Instance> { 14 _channels: [(AnyAdcChannel<T>, SampleTime); N],
14 _phantom: PhantomData<T>, 15 _phantom: PhantomData<T>,
15} 16}
16 17
17impl<T: Instance> InjectedAdc<T> { 18impl<T: Instance, const N: usize> InjectedAdc<T, N> {
18 pub(crate) fn new() -> Self { 19 pub(crate) fn new(channels: [(AnyAdcChannel<T>, SampleTime); N]) -> Self {
19 Self { 20 Self {
21 _channels: channels,
20 _phantom: PhantomData, 22 _phantom: PhantomData,
21 } 23 }
22 } 24 }
23 25
24 pub fn read_injected_samples(&mut self) -> [u16; NR_INJECTED_RANKS] { 26 pub fn stop_injected_conversions(&mut self) {
25 Adc::<T>::read_injected_samples() 27 Adc::<T>::stop_injected_conversions()
26 } 28 }
27}
28 29
30 pub fn start_injected_conversions(&mut self) {
31 Adc::<T>::start_injected_conversions()
32 }
29 33
30impl<T: Instance> Drop for InjectedAdc<T> { 34 pub fn read_injected_samples(&mut self) -> [u16; N] {
35 InjectedAdc::<T, N>::read_injected_data()
36 }
37}
38
39impl<T: Instance, const N: usize> Drop for InjectedAdc<T, N> {
31 fn drop(&mut self) { 40 fn drop(&mut self) {
32 Adc::<T>::teardown_adc(); 41 Adc::<T>::teardown_adc();
33
34 compiler_fence(Ordering::SeqCst); 42 compiler_fence(Ordering::SeqCst);
35 } 43 }
36} 44}
diff --git a/examples/stm32g4/.cargo/config.toml b/examples/stm32g4/.cargo/config.toml
index de3e5718e..52b5a7bc8 100644
--- a/examples/stm32g4/.cargo/config.toml
+++ b/examples/stm32g4/.cargo/config.toml
@@ -1,9 +1,21 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace STM32G071C8Rx with your chip as listed in `probe-rs chip list` 2# Change this runner as required for your MCU.
3runner = "probe-rs run --chip STM32G484VETx" 3runner = [
4 "probe-rs",
5 "run",
6 "--chip",
7 "STM32G431VBTx",
8 "--speed",
9 "5000",
10 "--preverify",
11 "--log-format",
12 "{t} [{L}] {s}",
13]
14
4 15
5[build] 16[build]
6target = "thumbv7em-none-eabi" 17target = "thumbv7em-none-eabihf"
7 18
8[env] 19[env]
9DEFMT_LOG = "trace" \ No newline at end of file 20DEFMT_LOG = "info"
21DEFMT_RTT_BUFFER_SIZE = "4096"
diff --git a/examples/stm32g4/Cargo.toml b/examples/stm32g4/Cargo.toml
index 8bbeb594c..9089ec0d5 100644
--- a/examples/stm32g4/Cargo.toml
+++ b/examples/stm32g4/Cargo.toml
@@ -7,7 +7,7 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9# Change stm32g491re to your chip name, if necessary. 9# Change stm32g491re to your chip name, if necessary.
10embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g491re", "memory-x", "unstable-pac", "exti"] } 10embassy-stm32 = { path = "../../embassy-stm32", features = [ "defmt", "time-driver-any", "stm32g431vb", "memory-x", "unstable-pac", "exti"] }
11embassy-sync = { path = "../../embassy-sync", features = ["defmt"] } 11embassy-sync = { path = "../../embassy-sync", features = ["defmt"] }
12embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] } 12embassy-executor = { path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt"] }
13embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 13embassy-time = { path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
diff --git a/examples/stm32g4/src/bin/adc_injected_and_regular.rs b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
index d0c577b4b..c929ca3bf 100644
--- a/examples/stm32g4/src/bin/adc_injected_and_regular.rs
+++ b/examples/stm32g4/src/bin/adc_injected_and_regular.rs
@@ -18,9 +18,9 @@ use embassy_stm32::timer::complementary_pwm::{ComplementaryPwm, Mms2};
18use embassy_stm32::timer::low_level::CountingMode; 18use embassy_stm32::timer::low_level::CountingMode;
19use embassy_stm32::{Config, interrupt}; 19use embassy_stm32::{Config, interrupt};
20use embassy_sync::blocking_mutex::CriticalSectionMutex; 20use embassy_sync::blocking_mutex::CriticalSectionMutex;
21use {critical_section, defmt_rtt as _, panic_probe as _}; 21use {defmt_rtt as _, panic_probe as _};
22 22
23static ADC1_HANDLE: CriticalSectionMutex<RefCell<Option<InjectedAdc<ADC1>>>> = 23static ADC1_HANDLE: CriticalSectionMutex<RefCell<Option<InjectedAdc<ADC1, 1>>>> =
24 CriticalSectionMutex::new(RefCell::new(None)); 24 CriticalSectionMutex::new(RefCell::new(None));
25 25
26/// This example showcases how to use both regular ADC conversions with DMA and injected ADC 26/// This example showcases how to use both regular ADC conversions with DMA and injected ADC
@@ -78,17 +78,17 @@ async fn main(_spawner: embassy_executor::Spawner) {
78 // Configure regular conversions with DMA 78 // Configure regular conversions with DMA
79 let adc1 = Adc::new(p.ADC1); 79 let adc1 = Adc::new(p.ADC1);
80 80
81 let mut vrefint_channel = adc1.enable_vrefint().degrade_adc(); 81 let vrefint_channel = adc1.enable_vrefint().degrade_adc();
82 let mut pa0 = p.PC1.degrade_adc(); 82 let pa0 = p.PC1.degrade_adc();
83 let regular_sequence = [ 83 let regular_sequence = [
84 (&mut vrefint_channel, SampleTime::CYCLES247_5), 84 (vrefint_channel, SampleTime::CYCLES247_5),
85 (&mut pa0, SampleTime::CYCLES247_5), 85 (pa0, SampleTime::CYCLES247_5),
86 ] 86 ]
87 .into_iter(); 87 .into_iter();
88 88
89 // Configurations of Injected ADC measurements 89 // Configurations of Injected ADC measurements
90 let mut pa2 = p.PA2.degrade_adc(); 90 let pa2 = p.PA2.degrade_adc();
91 let injected_sequence = [(&mut pa2, SampleTime::CYCLES247_5)].into_iter(); 91 let injected_sequence = [(pa2, SampleTime::CYCLES247_5)];
92 92
93 // Configure DMA for retrieving regular ADC measurements 93 // Configure DMA for retrieving regular ADC measurements
94 let dma1_ch1 = p.DMA1_CH1; 94 let dma1_ch1 = p.DMA1_CH1;
@@ -111,6 +111,7 @@ async fn main(_spawner: embassy_executor::Spawner) {
111 RegularConversionMode::Triggered(regular_trigger), 111 RegularConversionMode::Triggered(regular_trigger),
112 injected_sequence, 112 injected_sequence,
113 injected_trigger, 113 injected_trigger,
114 true,
114 ); 115 );
115 116
116 // Store ADC globally to allow access from ADC interrupt 117 // Store ADC globally to allow access from ADC interrupt