aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormaor malka <[email protected]>2025-08-26 22:15:34 -0400
committermaor malka <[email protected]>2025-08-26 22:15:34 -0400
commit6b8d375813116fba0e04aa28e23ded8ab077729a (patch)
treee852447c4507dc11938a5f94fcecf6e94e537dfa
parent75484f4f51847a92e2df1e8319debec61cd7aca2 (diff)
stm32/adc/v3: moved ringbuffered to seperate file
-rw-r--r--embassy-stm32/src/adc/ringbuffered_v3.rs181
-rw-r--r--embassy-stm32/src/adc/v3.rs182
2 files changed, 189 insertions, 174 deletions
diff --git a/embassy-stm32/src/adc/ringbuffered_v3.rs b/embassy-stm32/src/adc/ringbuffered_v3.rs
new file mode 100644
index 000000000..655ae712f
--- /dev/null
+++ b/embassy-stm32/src/adc/ringbuffered_v3.rs
@@ -0,0 +1,181 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{compiler_fence, Ordering};
3use embassy_hal_internal::Peri;
4
5use crate::dma::{ReadableRingBuffer, TransferOptions};
6
7use crate::adc::Instance;
8use crate::adc::RxDma;
9use crate::rcc;
10
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub struct OverrunError;
13
14pub struct RingBufferedAdc<'d, T: Instance> {
15 pub _phantom: PhantomData<T>,
16 pub ring_buf: ReadableRingBuffer<'d, u16>,
17}
18
19impl<'d, T: Instance> RingBufferedAdc<'d, T> {
20 pub fn new(dma: Peri<'d, impl RxDma<T>>, dma_buf: &'d mut [u16]) -> Self {
21 //dma side setup
22 let opts = TransferOptions {
23 half_transfer_ir: true,
24 circular: true,
25 ..Default::default()
26 };
27
28 // Safety: we forget the struct before this function returns.
29 let request = dma.request();
30
31 let ring_buf =
32 unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) };
33
34 Self {
35 _phantom: PhantomData,
36 ring_buf,
37 }
38 }
39
40 #[inline]
41 fn start_continous_sampling(&mut self) {
42 // Start adc conversion
43 T::regs().cr().modify(|reg| {
44 reg.set_adstart(true);
45 });
46 self.ring_buf.start();
47 }
48
49 #[inline]
50 pub fn stop_continous_sampling(&mut self) {
51 // Stop adc conversion
52 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
53 T::regs().cr().modify(|reg| {
54 reg.set_adstp(true);
55 });
56 while T::regs().cr().read().adstart() {}
57 }
58 }
59 pub fn disable_adc(&mut self) {
60 self.stop_continous_sampling();
61 self.ring_buf.clear();
62 self.ring_buf.request_pause();
63 }
64
65 pub fn teardown_adc(&mut self) {
66 self.disable_adc();
67
68 //disable dma control
69 #[cfg(not(any(adc_g0, adc_u0)))]
70 T::regs().cfgr().modify(|reg| {
71 reg.set_dmaen(false);
72 });
73 #[cfg(any(adc_g0, adc_u0))]
74 T::regs().cfgr1().modify(|reg| {
75 reg.set_dmaen(false);
76 });
77
78 //TODO: do we need to cleanup the DMA request here?
79
80 compiler_fence(Ordering::SeqCst);
81 }
82
83 /// Reads measurements from the DMA ring buffer.
84 ///
85 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
86 /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
87 ///
88 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `sequence`.
89 /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
90 /// For example if 2 channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
91 ///
92 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly running tasks
93 /// Otherwise, you'll see constant Overrun errors occuring, this means that you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
94 /// Example:
95 /// ```rust,ignore
96 /// const DMA_BUF_LEN: usize = 120;
97 /// use embassy_stm32::adc::{Adc, AdcChannel}
98 ///
99 /// let mut adc = Adc::new(p.ADC1);
100 /// let mut adc_pin0 = p.PA0.degrade_adc();
101 /// let mut adc_pin1 = p.PA1.degrade_adc();
102 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
103 ///
104 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
105 /// p.DMA2_CH0,
106 /// adc_dma_buf, [
107 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
108 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
109 /// ].into_iter());
110 ///
111 ///
112 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
113 /// loop {
114 /// match ring_buffered_adc.read(&mut measurements).await {
115 /// Ok(_) => {
116 /// defmt::info!("adc1: {}", measurements);
117 /// }
118 /// Err(e) => {
119 /// defmt::warn!("Error: {:?}", e);
120 /// }
121 /// }
122 /// }
123 /// ```
124 ///
125 ///
126 /// [`teardown_adc`]: #method.teardown_adc
127 /// [`start_continous_sampling`]: #method.start_continous_sampling
128 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
129 assert_eq!(
130 self.ring_buf.capacity() / 2,
131 measurements.len(),
132 "Buffer size must be half the size of the ring buffer"
133 );
134
135 let r = T::regs();
136
137 // Start background receive if it was not already started
138 if !r.cr().read().adstart() {
139 self.start_continous_sampling();
140 }
141
142 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
143 }
144
145 /// Read bytes that are readily available in the ring buffer.
146 /// If no bytes are currently available in the buffer the call waits until the some
147 /// bytes are available (at least one byte and at most half the buffer size)
148 ///
149 /// Background receive is started if `start_continous_sampling()` has not been previously called.
150 ///
151 /// Receive in the background is terminated if an error is returned.
152 /// It must then manually be started again by calling `start_continous_sampling()` or by re-calling `blocking_read()`.
153 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
154 let r = T::regs();
155
156 // Start background receive if it was not already started
157 if !r.cr().read().adstart() {
158 self.start_continous_sampling();
159 }
160
161 loop {
162 match self.ring_buf.read(buf) {
163 Ok((0, _)) => {}
164 Ok((len, _)) => {
165 return Ok(len);
166 }
167 Err(_) => {
168 self.stop_continous_sampling();
169 return Err(OverrunError);
170 }
171 }
172 }
173 }
174}
175
176impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
177 fn drop(&mut self) {
178 self.teardown_adc();
179 rcc::disable::<T>();
180 }
181}
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs
index a52141a34..30b04fc81 100644
--- a/embassy-stm32/src/adc/v3.rs
+++ b/embassy-stm32/src/adc/v3.rs
@@ -1,6 +1,3 @@
1use core::marker::PhantomData;
2use core::sync::atomic::{compiler_fence, Ordering};
3
4use cfg_if::cfg_if; 1use cfg_if::cfg_if;
5use pac::adc::vals::Dmacfg; 2use pac::adc::vals::Dmacfg;
6#[cfg(adc_v3)] 3#[cfg(adc_v3)]
@@ -9,8 +6,14 @@ use pac::adc::vals::{OversamplingRatio, OversamplingShift, Rovsm, Trovs};
9use super::{ 6use super::{
10 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, 7 blocking_delay_us, Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel,
11}; 8};
9
12#[cfg(adc_v3)] 10#[cfg(adc_v3)]
13use crate::dma::{ReadableRingBuffer, Transfer, TransferOptions}; 11mod ringbuffered_v3;
12
13#[cfg(adc_v3)]
14use ringbuffered_v3::RingBufferedAdc;
15
16use crate::dma::Transfer;
14use crate::{pac, rcc, Peri}; 17use crate::{pac, rcc, Peri};
15 18
16/// Default VREF voltage used for sample conversion to millivolts. 19/// Default VREF voltage used for sample conversion to millivolts.
@@ -112,14 +115,6 @@ pub enum Averaging {
112 Samples256, 115 Samples256,
113} 116}
114 117
115#[cfg_attr(feature = "defmt", derive(defmt::Format))]
116pub struct OverrunError;
117
118pub struct RingBufferedAdc<'d, T: Instance> {
119 _phantom: PhantomData<T>,
120 ring_buf: ReadableRingBuffer<'d, u16>,
121}
122
123impl<'d, T: Instance> Adc<'d, T> { 118impl<'d, T: Instance> Adc<'d, T> {
124 pub fn new(adc: Peri<'d, T>) -> Self { 119 pub fn new(adc: Peri<'d, T>) -> Self {
125 rcc::enable_and_reset::<T>(); 120 rcc::enable_and_reset::<T>();
@@ -531,19 +526,6 @@ impl<'d, T: Instance> Adc<'d, T> {
531 } 526 }
532 } 527 }
533 528
534 //dma side setup
535 let opts = TransferOptions {
536 half_transfer_ir: true,
537 circular: true,
538 ..Default::default()
539 };
540
541 // Safety: we forget the struct before this function returns.
542 let request = dma.request();
543
544 let ring_buf =
545 unsafe { ReadableRingBuffer::new(dma, request, T::regs().dr().as_ptr() as *mut u16, dma_buf, opts) };
546
547 // On G0 and U0 enabled channels are sampled from 0 to last channel. 529 // On G0 and U0 enabled channels are sampled from 0 to last channel.
548 // It is possible to add up to 8 sequences if CHSELRMOD = 1. 530 // It is possible to add up to 8 sequences if CHSELRMOD = 1.
549 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used. 531 // However for supporting more than 8 channels alternative CHSELRMOD = 0 approach is used.
@@ -573,10 +555,7 @@ impl<'d, T: Instance> Adc<'d, T> {
573 reg.set_dmaen(true); 555 reg.set_dmaen(true);
574 }); 556 });
575 557
576 RingBufferedAdc { 558 RingBufferedAdc::new(dma, dma_buf)
577 _phantom: PhantomData,
578 ring_buf,
579 }
580 } 559 }
581 560
582 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) { 561 fn configure_channel(channel: &mut impl AdcChannel<T>, sample_time: SampleTime) {
@@ -683,148 +662,3 @@ impl<'d, T: Instance> Adc<'d, T> {
683 } 662 }
684 } 663 }
685} 664}
686
687#[cfg(adc_v3)]
688impl<'d, T: Instance> RingBufferedAdc<'d, T> {
689 #[inline]
690 fn start_continous_sampling(&mut self) {
691 // Start adc conversion
692 T::regs().cr().modify(|reg| {
693 reg.set_adstart(true);
694 });
695 self.ring_buf.start();
696 }
697
698 #[inline]
699 pub fn stop_continous_sampling(&mut self) {
700 // Stop adc conversion
701 if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() {
702 T::regs().cr().modify(|reg| {
703 reg.set_adstp(true);
704 });
705 while T::regs().cr().read().adstart() {}
706 }
707 }
708 pub fn disable_adc(&mut self) {
709 self.stop_continous_sampling();
710 self.ring_buf.clear();
711 self.ring_buf.request_pause();
712 }
713
714 pub fn teardown_adc(&mut self) {
715 self.disable_adc();
716
717 //disable dma control
718 #[cfg(not(any(adc_g0, adc_u0)))]
719 T::regs().cfgr().modify(|reg| {
720 reg.set_dmaen(false);
721 });
722 #[cfg(any(adc_g0, adc_u0))]
723 T::regs().cfgr1().modify(|reg| {
724 reg.set_dmaen(false);
725 });
726
727 //TODO: do we need to cleanup the DMA request here?
728
729 compiler_fence(Ordering::SeqCst);
730 }
731
732 /// Reads measurements from the DMA ring buffer.
733 ///
734 /// This method fills the provided `measurements` array with ADC readings from the DMA buffer.
735 /// The length of the `measurements` array should be exactly half of the DMA buffer length. Because interrupts are only generated if half or full DMA transfer completes.
736 ///
737 /// Each call to `read` will populate the `measurements` array in the same order as the channels defined with `sequence`.
738 /// There will be many sequences worth of measurements in this array because it only returns if at least half of the DMA buffer is filled.
739 /// For example if 2 channels are sampled `measurements` contain: `[sq0 sq1 sq0 sq1 sq0 sq1 ..]`.
740 ///
741 /// Note that the ADC Datarate can be very fast, it is suggested to use DMA mode inside tightly running tasks
742 /// Otherwise, you'll see constant Overrun errors occuring, this means that you're sampling too quickly for the task to handle, and you may need to increase the buffer size.
743 /// Example:
744 /// ```rust,ignore
745 /// const DMA_BUF_LEN: usize = 120;
746 /// use embassy_stm32::adc::{Adc, AdcChannel}
747 ///
748 /// let mut adc = Adc::new(p.ADC1);
749 /// let mut adc_pin0 = p.PA0.degrade_adc();
750 /// let mut adc_pin1 = p.PA1.degrade_adc();
751 /// let adc_dma_buf = [0u16; DMA_BUF_LEN];
752 ///
753 /// let mut ring_buffered_adc: RingBufferedAdc<embassy_stm32::peripherals::ADC1> = adc.into_ring_buffered(
754 /// p.DMA2_CH0,
755 /// adc_dma_buf, [
756 /// (&mut *adc_pin0, SampleTime::CYCLES160_5),
757 /// (&mut *adc_pin1, SampleTime::CYCLES160_5),
758 /// ].into_iter());
759 ///
760 ///
761 /// let mut measurements = [0u16; DMA_BUF_LEN / 2];
762 /// loop {
763 /// match ring_buffered_adc.read(&mut measurements).await {
764 /// Ok(_) => {
765 /// defmt::info!("adc1: {}", measurements);
766 /// }
767 /// Err(e) => {
768 /// defmt::warn!("Error: {:?}", e);
769 /// }
770 /// }
771 /// }
772 /// ```
773 ///
774 ///
775 /// [`teardown_adc`]: #method.teardown_adc
776 /// [`start_continous_sampling`]: #method.start_continous_sampling
777 pub async fn read(&mut self, measurements: &mut [u16]) -> Result<usize, OverrunError> {
778 assert_eq!(
779 self.ring_buf.capacity() / 2,
780 measurements.len(),
781 "Buffer size must be half the size of the ring buffer"
782 );
783
784 let r = T::regs();
785
786 // Start background receive if it was not already started
787 if !r.cr().read().adstart() {
788 self.start_continous_sampling();
789 }
790
791 self.ring_buf.read_exact(measurements).await.map_err(|_| OverrunError)
792 }
793
794 /// Read bytes that are readily available in the ring buffer.
795 /// If no bytes are currently available in the buffer the call waits until the some
796 /// bytes are available (at least one byte and at most half the buffer size)
797 ///
798 /// Background receive is started if `start_continous_sampling()` has not been previously called.
799 ///
800 /// Receive in the background is terminated if an error is returned.
801 /// It must then manually be started again by calling `start_continous_sampling()` or by re-calling `blocking_read()`.
802 pub fn blocking_read(&mut self, buf: &mut [u16]) -> Result<usize, OverrunError> {
803 let r = T::regs();
804
805 // Start background receive if it was not already started
806 if !r.cr().read().adstart() {
807 self.start_continous_sampling();
808 }
809
810 loop {
811 match self.ring_buf.read(buf) {
812 Ok((0, _)) => {}
813 Ok((len, _)) => {
814 return Ok(len);
815 }
816 Err(_) => {
817 self.stop_continous_sampling();
818 return Err(OverrunError);
819 }
820 }
821 }
822 }
823}
824
825impl<T: Instance> Drop for RingBufferedAdc<'_, T> {
826 fn drop(&mut self) {
827 self.teardown_adc();
828 rcc::disable::<T>();
829 }
830}