diff options
Diffstat (limited to 'embassy-stm32/src/adc/mod.rs')
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 467 |
1 files changed, 424 insertions, 43 deletions
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index ea986f4cf..da432f6ce 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -17,38 +17,44 @@ | |||
| 17 | #[cfg_attr(adc_c0, path = "c0.rs")] | 17 | #[cfg_attr(adc_c0, path = "c0.rs")] |
| 18 | mod _version; | 18 | mod _version; |
| 19 | 19 | ||
| 20 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 21 | mod ringbuffered; | ||
| 22 | |||
| 20 | use core::marker::PhantomData; | 23 | use core::marker::PhantomData; |
| 21 | 24 | ||
| 22 | #[allow(unused)] | 25 | #[allow(unused)] |
| 23 | #[cfg(not(any(adc_f3v3, adc_wba)))] | 26 | #[cfg(not(any(adc_f3v3, adc_wba)))] |
| 24 | pub use _version::*; | 27 | pub use _version::*; |
| 25 | use embassy_hal_internal::{impl_peripheral, PeripheralType}; | 28 | #[allow(unused)] |
| 29 | use embassy_hal_internal::PeripheralType; | ||
| 26 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] | 30 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| 27 | use embassy_sync::waitqueue::AtomicWaker; | 31 | use embassy_sync::waitqueue::AtomicWaker; |
| 32 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 33 | pub use ringbuffered::RingBufferedAdc; | ||
| 34 | |||
| 35 | #[cfg(adc_u5)] | ||
| 36 | use crate::pac::adc::vals::Adc4SampleTime; | ||
| 37 | #[cfg(adc_wba)] | ||
| 38 | use crate::pac::adc::vals::SampleTime as Adc4SampleTime; | ||
| 28 | 39 | ||
| 29 | #[cfg(any(adc_u5, adc_wba))] | 40 | #[cfg(any(adc_u5, adc_wba))] |
| 30 | #[path = "adc4.rs"] | 41 | #[path = "adc4.rs"] |
| 31 | pub mod adc4; | 42 | pub mod adc4; |
| 32 | 43 | ||
| 44 | #[allow(unused)] | ||
| 45 | pub(self) use crate::block_for_us as blocking_delay_us; | ||
| 33 | pub use crate::pac::adc::vals; | 46 | pub use crate::pac::adc::vals; |
| 34 | #[cfg(not(any(adc_f1, adc_f3v3)))] | 47 | #[cfg(not(any(adc_f1, adc_f3v3)))] |
| 35 | pub use crate::pac::adc::vals::Res as Resolution; | 48 | pub use crate::pac::adc::vals::Res as Resolution; |
| 36 | pub use crate::pac::adc::vals::SampleTime; | 49 | pub use crate::pac::adc::vals::SampleTime; |
| 37 | use crate::peripherals; | 50 | use crate::peripherals; |
| 38 | 51 | ||
| 39 | #[cfg(not(adc_wba))] | ||
| 40 | dma_trait!(RxDma, Instance); | 52 | dma_trait!(RxDma, Instance); |
| 41 | #[cfg(adc_u5)] | ||
| 42 | dma_trait!(RxDma4, adc4::Instance); | ||
| 43 | #[cfg(adc_wba)] | ||
| 44 | dma_trait!(RxDma4, adc4::Instance); | ||
| 45 | 53 | ||
| 46 | /// Analog to Digital driver. | 54 | /// Analog to Digital driver. |
| 47 | pub struct Adc<'d, T: Instance> { | 55 | pub struct Adc<'d, T: Instance> { |
| 48 | #[allow(unused)] | 56 | #[allow(unused)] |
| 49 | adc: crate::Peri<'d, T>, | 57 | adc: crate::Peri<'d, T>, |
| 50 | #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))] | ||
| 51 | sample_time: SampleTime, | ||
| 52 | } | 58 | } |
| 53 | 59 | ||
| 54 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] | 60 | #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] |
| @@ -65,10 +71,53 @@ impl State { | |||
| 65 | } | 71 | } |
| 66 | } | 72 | } |
| 67 | 73 | ||
| 68 | trait SealedInstance { | 74 | #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] |
| 69 | #[cfg(not(adc_wba))] | 75 | trait_set::trait_set! { |
| 70 | #[allow(unused)] | 76 | pub trait DefaultInstance = Instance; |
| 77 | } | ||
| 78 | |||
| 79 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_g4, adc_c0))] | ||
| 80 | trait_set::trait_set! { | ||
| 81 | pub trait DefaultInstance = Instance<Regs = crate::pac::adc::Adc>; | ||
| 82 | } | ||
| 83 | |||
| 84 | #[cfg(adc_wba)] | ||
| 85 | trait_set::trait_set! { | ||
| 86 | pub trait DefaultInstance = Instance<Regs = crate::pac::adc::Adc4>; | ||
| 87 | } | ||
| 88 | |||
| 89 | pub trait BasicAdcRegs { | ||
| 90 | type SampleTime; | ||
| 91 | } | ||
| 92 | |||
| 93 | #[cfg(any( | ||
| 94 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 95 | ))] | ||
| 96 | trait AdcRegs: BasicAdcRegs { | ||
| 97 | fn enable(&self); | ||
| 98 | fn start(&self); | ||
| 99 | fn stop(&self); | ||
| 100 | fn convert(&self); | ||
| 101 | fn configure_dma(&self, conversion_mode: ConversionMode); | ||
| 102 | fn configure_sequence(&self, sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); | ||
| 103 | fn data(&self) -> *mut u16; | ||
| 104 | } | ||
| 105 | |||
| 106 | #[allow(private_bounds)] | ||
| 107 | pub trait BasicInstance { | ||
| 108 | #[cfg(any( | ||
| 109 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 110 | ))] | ||
| 111 | type Regs: AdcRegs; | ||
| 112 | } | ||
| 113 | |||
| 114 | trait SealedInstance: BasicInstance { | ||
| 115 | #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] | ||
| 71 | fn regs() -> crate::pac::adc::Adc; | 116 | fn regs() -> crate::pac::adc::Adc; |
| 117 | #[cfg(any( | ||
| 118 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 119 | ))] | ||
| 120 | fn regs() -> Self::Regs; | ||
| 72 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] | 121 | #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] |
| 73 | #[allow(unused)] | 122 | #[allow(unused)] |
| 74 | fn common_regs() -> crate::pac::adccommon::AdcCommon; | 123 | fn common_regs() -> crate::pac::adccommon::AdcCommon; |
| @@ -77,27 +126,278 @@ trait SealedInstance { | |||
| 77 | } | 126 | } |
| 78 | 127 | ||
| 79 | pub(crate) trait SealedAdcChannel<T> { | 128 | pub(crate) trait SealedAdcChannel<T> { |
| 80 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 129 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] |
| 81 | fn setup(&mut self) {} | 130 | fn setup(&mut self) {} |
| 82 | 131 | ||
| 83 | #[allow(unused)] | 132 | #[allow(unused)] |
| 84 | fn channel(&self) -> u8; | 133 | fn channel(&self) -> u8; |
| 134 | |||
| 135 | #[allow(unused)] | ||
| 136 | fn is_differential(&self) -> bool { | ||
| 137 | false | ||
| 138 | } | ||
| 85 | } | 139 | } |
| 86 | 140 | ||
| 87 | /// Performs a busy-wait delay for a specified number of microseconds. | 141 | #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] |
| 88 | #[allow(unused)] | 142 | /// Number of samples used for averaging. |
| 89 | pub(crate) fn blocking_delay_us(us: u32) { | 143 | #[derive(Copy, Clone, Debug)] |
| 90 | #[cfg(feature = "time")] | 144 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 91 | embassy_time::block_for(embassy_time::Duration::from_micros(us as u64)); | 145 | pub enum Averaging { |
| 92 | #[cfg(not(feature = "time"))] | 146 | Disabled, |
| 93 | { | 147 | Samples2, |
| 94 | let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; | 148 | Samples4, |
| 95 | let us = us as u64; | 149 | Samples8, |
| 96 | let cycles = freq * us / 1_000_000; | 150 | Samples16, |
| 97 | cortex_m::asm::delay(cycles as u32); | 151 | Samples32, |
| 152 | Samples64, | ||
| 153 | Samples128, | ||
| 154 | Samples256, | ||
| 155 | #[cfg(any(adc_c0, adc_v4, adc_u5))] | ||
| 156 | Samples512, | ||
| 157 | #[cfg(any(adc_c0, adc_v4, adc_u5))] | ||
| 158 | Samples1024, | ||
| 159 | } | ||
| 160 | |||
| 161 | #[cfg(any( | ||
| 162 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0 | ||
| 163 | ))] | ||
| 164 | pub(crate) enum ConversionMode { | ||
| 165 | // Should match the cfg on "read" below | ||
| 166 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 167 | Singular, | ||
| 168 | // Should match the cfg on "into_ring_buffered" below | ||
| 169 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 170 | Repeated(RegularConversionMode), | ||
| 171 | } | ||
| 172 | |||
| 173 | // Should match the cfg on "into_ring_buffered" below | ||
| 174 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 175 | // Conversion mode for regular ADC channels | ||
| 176 | #[derive(Copy, Clone)] | ||
| 177 | pub enum RegularConversionMode { | ||
| 178 | // Samples as fast as possible | ||
| 179 | Continuous, | ||
| 180 | #[cfg(adc_g4)] | ||
| 181 | // Sample at rate determined by external trigger | ||
| 182 | Triggered(ConversionTrigger), | ||
| 183 | } | ||
| 184 | |||
| 185 | impl<'d, T: Instance> Adc<'d, T> { | ||
| 186 | #[cfg(any( | ||
| 187 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0 | ||
| 188 | ))] | ||
| 189 | /// Read an ADC pin. | ||
| 190 | pub fn blocking_read( | ||
| 191 | &mut self, | ||
| 192 | channel: &mut impl AdcChannel<T>, | ||
| 193 | sample_time: <T::Regs as BasicAdcRegs>::SampleTime, | ||
| 194 | ) -> u16 { | ||
| 195 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] | ||
| 196 | channel.setup(); | ||
| 197 | |||
| 198 | // Ensure no conversions are ongoing | ||
| 199 | T::regs().stop(); | ||
| 200 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h7rs, adc_u0, adc_u5, adc_wba, adc_c0))] | ||
| 201 | T::regs().enable(); | ||
| 202 | T::regs().configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); | ||
| 203 | |||
| 204 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels | ||
| 205 | // | ||
| 206 | // TODO: If hardware allows, enable after configure_sequence on all chips | ||
| 207 | #[cfg(any(adc_g4, adc_h5))] | ||
| 208 | T::regs().enable(); | ||
| 209 | T::regs().convert(); | ||
| 210 | |||
| 211 | unsafe { core::ptr::read_volatile(T::regs().data()) } | ||
| 212 | } | ||
| 213 | |||
| 214 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 215 | /// Read one or multiple ADC regular channels using DMA. | ||
| 216 | /// | ||
| 217 | /// `sequence` iterator and `readings` must have the same length. | ||
| 218 | /// | ||
| 219 | /// Example | ||
| 220 | /// ```rust,ignore | ||
| 221 | /// use embassy_stm32::adc::{Adc, AdcChannel} | ||
| 222 | /// | ||
| 223 | /// let mut adc = Adc::new(p.ADC1); | ||
| 224 | /// let mut adc_pin0 = p.PA0.into(); | ||
| 225 | /// let mut adc_pin1 = p.PA1.into(); | ||
| 226 | /// let mut measurements = [0u16; 2]; | ||
| 227 | /// | ||
| 228 | /// adc.read( | ||
| 229 | /// p.DMA1_CH2.reborrow(), | ||
| 230 | /// [ | ||
| 231 | /// (&mut *adc_pin0, SampleTime::CYCLES160_5), | ||
| 232 | /// (&mut *adc_pin1, SampleTime::CYCLES160_5), | ||
| 233 | /// ] | ||
| 234 | /// .into_iter(), | ||
| 235 | /// &mut measurements, | ||
| 236 | /// ) | ||
| 237 | /// .await; | ||
| 238 | /// defmt::info!("measurements: {}", measurements); | ||
| 239 | /// ``` | ||
| 240 | /// | ||
| 241 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use | ||
| 242 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` | ||
| 243 | /// | ||
| 244 | /// Note: Depending on hardware limitations, this method may require channels to be passed | ||
| 245 | /// in order or require the sequence to have the same sample time for all channnels, depending | ||
| 246 | /// on the number and properties of the channels in the sequence. This method will panic if | ||
| 247 | /// the hardware cannot deliver the requested configuration. | ||
| 248 | pub async fn read<'a, 'b: 'a>( | ||
| 249 | &mut self, | ||
| 250 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, | ||
| 251 | sequence: impl ExactSizeIterator<Item = (&'a mut AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>, | ||
| 252 | readings: &mut [u16], | ||
| 253 | ) { | ||
| 254 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 255 | assert!( | ||
| 256 | sequence.len() == readings.len(), | ||
| 257 | "Sequence length must be equal to readings length" | ||
| 258 | ); | ||
| 259 | assert!( | ||
| 260 | sequence.len() <= 16, | ||
| 261 | "Asynchronous read sequence cannot be more than 16 in length" | ||
| 262 | ); | ||
| 263 | |||
| 264 | // Ensure no conversions are ongoing | ||
| 265 | T::regs().stop(); | ||
| 266 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 267 | T::regs().enable(); | ||
| 268 | |||
| 269 | T::regs().configure_sequence( | ||
| 270 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | ||
| 271 | ); | ||
| 272 | |||
| 273 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels | ||
| 274 | // | ||
| 275 | // TODO: If hardware allows, enable after configure_sequence on all chips | ||
| 276 | #[cfg(any(adc_g4, adc_h5))] | ||
| 277 | T::regs().enable(); | ||
| 278 | T::regs().configure_dma(ConversionMode::Singular); | ||
| 279 | |||
| 280 | let request = rx_dma.request(); | ||
| 281 | let transfer = | ||
| 282 | unsafe { crate::dma::Transfer::new_read(rx_dma, request, T::regs().data(), readings, Default::default()) }; | ||
| 283 | |||
| 284 | T::regs().start(); | ||
| 285 | |||
| 286 | // Wait for conversion sequence to finish. | ||
| 287 | transfer.await; | ||
| 288 | |||
| 289 | // Ensure conversions are finished. | ||
| 290 | T::regs().stop(); | ||
| 291 | } | ||
| 292 | |||
| 293 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 294 | /// Configures the ADC to use a DMA ring buffer for continuous data acquisition. | ||
| 295 | /// | ||
| 296 | /// Use the [`read`] method to retrieve measurements from the DMA ring buffer. The read buffer | ||
| 297 | /// should be exactly half the size of `dma_buf`. When using triggered mode, it is recommended | ||
| 298 | /// to configure `dma_buf` as a double buffer so that one half can be read while the other half | ||
| 299 | /// is being filled by the DMA, preventing data loss. The trigger period of the ADC effectively | ||
| 300 | /// defines the period at which the buffer should be read. | ||
| 301 | /// | ||
| 302 | /// If continous conversion mode is selected, the provided `dma_buf` must be large enough to prevent | ||
| 303 | /// DMA buffer overruns. Its length should be a multiple of the number of ADC channels being measured. | ||
| 304 | /// For example, if 3 channels are measured and you want to store 40 samples per channel, | ||
| 305 | /// the buffer length should be `3 * 40 = 120`. | ||
| 306 | /// | ||
| 307 | /// # Parameters | ||
| 308 | /// - `dma`: The DMA peripheral used to transfer ADC data into the buffer. | ||
| 309 | /// - `dma_buf`: The buffer where DMA stores ADC samples. | ||
| 310 | /// - `regular_sequence`: Sequence of channels and sample times for regular ADC conversions. | ||
| 311 | /// - `regular_conversion_mode`: Mode for regular conversions (continuous or triggered). | ||
| 312 | /// | ||
| 313 | /// # Returns | ||
| 314 | /// A `RingBufferedAdc<'a, T>` instance configured for continuous DMA-based sampling. | ||
| 315 | /// | ||
| 316 | /// Note: Depending on hardware limitations, this method may require channels to be passed | ||
| 317 | /// in order or require the sequence to have the same sample time for all channnels, depending | ||
| 318 | /// on the number and properties of the channels in the sequence. This method will panic if | ||
| 319 | /// the hardware cannot deliver the requested configuration. | ||
| 320 | pub fn into_ring_buffered<'a, 'b>( | ||
| 321 | self, | ||
| 322 | dma: embassy_hal_internal::Peri<'a, impl RxDma<T>>, | ||
| 323 | dma_buf: &'a mut [u16], | ||
| 324 | sequence: impl ExactSizeIterator<Item = (AnyAdcChannel<'b, T>, <T::Regs as BasicAdcRegs>::SampleTime)>, | ||
| 325 | mode: RegularConversionMode, | ||
| 326 | ) -> RingBufferedAdc<'a, T> { | ||
| 327 | assert!(!dma_buf.is_empty() && dma_buf.len() <= 0xFFFF); | ||
| 328 | assert!(sequence.len() != 0, "Asynchronous read sequence cannot be empty"); | ||
| 329 | assert!( | ||
| 330 | sequence.len() <= 16, | ||
| 331 | "Asynchronous read sequence cannot be more than 16 in length" | ||
| 332 | ); | ||
| 333 | // Ensure no conversions are ongoing | ||
| 334 | T::regs().stop(); | ||
| 335 | #[cfg(any(adc_g0, adc_v3, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 336 | T::regs().enable(); | ||
| 337 | |||
| 338 | T::regs().configure_sequence( | ||
| 339 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | ||
| 340 | ); | ||
| 341 | |||
| 342 | // On chips with differential channels, enable after configure_sequence to allow setting differential channels | ||
| 343 | // | ||
| 344 | // TODO: If hardware allows, enable after configure_sequence on all chips | ||
| 345 | #[cfg(any(adc_g4, adc_h5))] | ||
| 346 | T::regs().enable(); | ||
| 347 | T::regs().configure_dma(ConversionMode::Repeated(mode)); | ||
| 348 | |||
| 349 | core::mem::forget(self); | ||
| 350 | |||
| 351 | RingBufferedAdc::new(dma, dma_buf) | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | pub(self) trait SpecialChannel {} | ||
| 356 | |||
| 357 | /// Implemented for ADCs that have a special channel | ||
| 358 | trait SealedSpecialConverter<T: SpecialChannel + Sized> { | ||
| 359 | const CHANNEL: u8; | ||
| 360 | } | ||
| 361 | |||
| 362 | #[allow(private_bounds)] | ||
| 363 | pub trait SpecialConverter<T: SpecialChannel + Sized>: SealedSpecialConverter<T> {} | ||
| 364 | |||
| 365 | impl<C: SpecialChannel + Sized, T: SealedSpecialConverter<C>> SpecialConverter<C> for T {} | ||
| 366 | |||
| 367 | impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> AdcChannel<T> for C {} | ||
| 368 | impl<C: SpecialChannel, T: Instance + SealedSpecialConverter<C>> SealedAdcChannel<T> for C { | ||
| 369 | fn channel(&self) -> u8 { | ||
| 370 | T::CHANNEL | ||
| 98 | } | 371 | } |
| 99 | } | 372 | } |
| 100 | 373 | ||
| 374 | pub struct VrefInt; | ||
| 375 | impl SpecialChannel for VrefInt {} | ||
| 376 | |||
| 377 | impl VrefInt { | ||
| 378 | #[cfg(any(adc_f3v1, adc_f3v2))] | ||
| 379 | /// The value that vref would be if vdda was at 3300mv | ||
| 380 | pub fn calibrated_value(&self) -> u16 { | ||
| 381 | crate::pac::VREFINTCAL.data().read() | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | /// Internal temperature channel. | ||
| 386 | pub struct Temperature; | ||
| 387 | impl SpecialChannel for Temperature {} | ||
| 388 | |||
| 389 | /// Internal battery voltage channel. | ||
| 390 | pub struct Vbat; | ||
| 391 | impl SpecialChannel for Vbat {} | ||
| 392 | |||
| 393 | /// Vcore channel. | ||
| 394 | pub struct Vcore; | ||
| 395 | impl SpecialChannel for Vcore {} | ||
| 396 | |||
| 397 | /// Internal dac channel. | ||
| 398 | pub struct Dac; | ||
| 399 | impl SpecialChannel for Dac {} | ||
| 400 | |||
| 101 | /// ADC instance. | 401 | /// ADC instance. |
| 102 | #[cfg(not(any( | 402 | #[cfg(not(any( |
| 103 | adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, | 403 | adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, |
| @@ -121,12 +421,16 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri | |||
| 121 | #[allow(private_bounds)] | 421 | #[allow(private_bounds)] |
| 122 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { | 422 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { |
| 123 | #[allow(unused_mut)] | 423 | #[allow(unused_mut)] |
| 124 | fn degrade_adc(mut self) -> AnyAdcChannel<T> { | 424 | fn degrade_adc<'a>(mut self) -> AnyAdcChannel<'a, T> |
| 125 | #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 425 | where |
| 426 | Self: 'a, | ||
| 427 | { | ||
| 428 | #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] | ||
| 126 | self.setup(); | 429 | self.setup(); |
| 127 | 430 | ||
| 128 | AnyAdcChannel { | 431 | AnyAdcChannel { |
| 129 | channel: self.channel(), | 432 | channel: self.channel(), |
| 433 | is_differential: self.is_differential(), | ||
| 130 | _phantom: PhantomData, | 434 | _phantom: PhantomData, |
| 131 | } | 435 | } |
| 132 | } | 436 | } |
| @@ -136,34 +440,57 @@ pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { | |||
| 136 | /// | 440 | /// |
| 137 | /// This is useful in scenarios where you need the ADC channels to have the same type, such as | 441 | /// This is useful in scenarios where you need the ADC channels to have the same type, such as |
| 138 | /// storing them in an array. | 442 | /// storing them in an array. |
| 139 | pub struct AnyAdcChannel<T> { | 443 | pub struct AnyAdcChannel<'a, T> { |
| 140 | channel: u8, | 444 | channel: u8, |
| 141 | _phantom: PhantomData<T>, | 445 | is_differential: bool, |
| 446 | _phantom: PhantomData<&'a mut T>, | ||
| 142 | } | 447 | } |
| 143 | impl_peripheral!(AnyAdcChannel<T: Instance>); | 448 | impl<T: Instance> AdcChannel<T> for AnyAdcChannel<'_, T> {} |
| 144 | impl<T: Instance> AdcChannel<T> for AnyAdcChannel<T> {} | 449 | impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<'_, T> { |
| 145 | impl<T: Instance> SealedAdcChannel<T> for AnyAdcChannel<T> { | ||
| 146 | fn channel(&self) -> u8 { | 450 | fn channel(&self) -> u8 { |
| 147 | self.channel | 451 | self.channel |
| 148 | } | 452 | } |
| 453 | |||
| 454 | fn is_differential(&self) -> bool { | ||
| 455 | self.is_differential | ||
| 456 | } | ||
| 149 | } | 457 | } |
| 150 | 458 | ||
| 151 | impl<T> AnyAdcChannel<T> { | 459 | impl<T> AnyAdcChannel<'_, T> { |
| 152 | #[allow(unused)] | 460 | #[allow(unused)] |
| 153 | pub fn get_hw_channel(&self) -> u8 { | 461 | pub fn get_hw_channel(&self) -> u8 { |
| 154 | self.channel | 462 | self.channel |
| 155 | } | 463 | } |
| 156 | } | 464 | } |
| 465 | |||
| 466 | #[cfg(not(adc_wba))] | ||
| 467 | impl BasicAdcRegs for crate::pac::adc::Adc { | ||
| 468 | type SampleTime = SampleTime; | ||
| 469 | } | ||
| 470 | |||
| 471 | #[cfg(any(adc_wba, adc_u5))] | ||
| 472 | impl BasicAdcRegs for crate::pac::adc::Adc4 { | ||
| 473 | type SampleTime = Adc4SampleTime; | ||
| 474 | } | ||
| 475 | |||
| 157 | #[cfg(adc_wba)] | 476 | #[cfg(adc_wba)] |
| 158 | foreach_adc!( | 477 | foreach_adc!( |
| 159 | (ADC4, $common_inst:ident, $clock:ident) => { | 478 | (ADC4, $common_inst:ident, $clock:ident) => { |
| 160 | impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { | 479 | impl crate::adc::BasicInstance for peripherals::ADC4 { |
| 161 | fn regs() -> crate::pac::adc::Adc4 { | 480 | type Regs = crate::pac::adc::Adc4; |
| 481 | } | ||
| 482 | |||
| 483 | impl crate::adc::SealedInstance for peripherals::ADC4 { | ||
| 484 | fn regs() -> Self::Regs { | ||
| 162 | crate::pac::ADC4 | 485 | crate::pac::ADC4 |
| 163 | } | 486 | } |
| 487 | |||
| 488 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 489 | return crate::pac::$common_inst | ||
| 490 | } | ||
| 164 | } | 491 | } |
| 165 | 492 | ||
| 166 | impl crate::adc::adc4::Instance for peripherals::ADC4 { | 493 | impl crate::adc::Instance for peripherals::ADC4 { |
| 167 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; | 494 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; |
| 168 | } | 495 | } |
| 169 | }; | 496 | }; |
| @@ -188,20 +515,32 @@ foreach_adc!( | |||
| 188 | #[cfg(adc_u5)] | 515 | #[cfg(adc_u5)] |
| 189 | foreach_adc!( | 516 | foreach_adc!( |
| 190 | (ADC4, $common_inst:ident, $clock:ident) => { | 517 | (ADC4, $common_inst:ident, $clock:ident) => { |
| 191 | impl crate::adc::adc4::SealedInstance for peripherals::ADC4 { | 518 | impl crate::adc::BasicInstance for peripherals::ADC4 { |
| 192 | fn regs() -> crate::pac::adc::Adc4 { | 519 | type Regs = crate::pac::adc::Adc4; |
| 520 | } | ||
| 521 | |||
| 522 | impl crate::adc::SealedInstance for peripherals::ADC4 { | ||
| 523 | fn regs() -> Self::Regs { | ||
| 193 | crate::pac::ADC4 | 524 | crate::pac::ADC4 |
| 194 | } | 525 | } |
| 526 | |||
| 527 | fn common_regs() -> crate::pac::adccommon::AdcCommon { | ||
| 528 | return crate::pac::$common_inst | ||
| 529 | } | ||
| 195 | } | 530 | } |
| 196 | 531 | ||
| 197 | impl crate::adc::adc4::Instance for peripherals::ADC4 { | 532 | impl crate::adc::Instance for peripherals::ADC4 { |
| 198 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; | 533 | type Interrupt = crate::_generated::peripheral_interrupts::ADC4::GLOBAL; |
| 199 | } | 534 | } |
| 200 | }; | 535 | }; |
| 201 | 536 | ||
| 202 | ($inst:ident, $common_inst:ident, $clock:ident) => { | 537 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 538 | impl crate::adc::BasicInstance for peripherals::$inst { | ||
| 539 | type Regs = crate::pac::adc::Adc; | ||
| 540 | } | ||
| 541 | |||
| 203 | impl crate::adc::SealedInstance for peripherals::$inst { | 542 | impl crate::adc::SealedInstance for peripherals::$inst { |
| 204 | fn regs() -> crate::pac::adc::Adc { | 543 | fn regs() -> Self::Regs { |
| 205 | crate::pac::$inst | 544 | crate::pac::$inst |
| 206 | } | 545 | } |
| 207 | 546 | ||
| @@ -219,14 +558,23 @@ foreach_adc!( | |||
| 219 | #[cfg(not(any(adc_u5, adc_wba)))] | 558 | #[cfg(not(any(adc_u5, adc_wba)))] |
| 220 | foreach_adc!( | 559 | foreach_adc!( |
| 221 | ($inst:ident, $common_inst:ident, $clock:ident) => { | 560 | ($inst:ident, $common_inst:ident, $clock:ident) => { |
| 561 | impl crate::adc::BasicInstance for peripherals::$inst { | ||
| 562 | #[cfg(any( | ||
| 563 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 564 | ))] | ||
| 565 | type Regs = crate::pac::adc::Adc; | ||
| 566 | } | ||
| 567 | |||
| 222 | impl crate::adc::SealedInstance for peripherals::$inst { | 568 | impl crate::adc::SealedInstance for peripherals::$inst { |
| 223 | #[cfg(not(adc_wba))] | 569 | #[cfg(any( |
| 224 | fn regs() -> crate::pac::adc::Adc { | 570 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 571 | ))] | ||
| 572 | fn regs() -> Self::Regs { | ||
| 225 | crate::pac::$inst | 573 | crate::pac::$inst |
| 226 | } | 574 | } |
| 227 | 575 | ||
| 228 | #[cfg(adc_wba)] | 576 | #[cfg(any(adc_f1, adc_f3v1, adc_f3v2, adc_v1, adc_l0))] |
| 229 | fn regs() -> crate::pac::adc::Adc4 { | 577 | fn regs() -> crate::pac::adc::Adc { |
| 230 | crate::pac::$inst | 578 | crate::pac::$inst |
| 231 | } | 579 | } |
| 232 | 580 | ||
| @@ -252,7 +600,7 @@ macro_rules! impl_adc_pin { | |||
| 252 | ($inst:ident, $pin:ident, $ch:expr) => { | 600 | ($inst:ident, $pin:ident, $ch:expr) => { |
| 253 | impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} | 601 | impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} |
| 254 | impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { | 602 | impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { |
| 255 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 603 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] |
| 256 | fn setup(&mut self) { | 604 | fn setup(&mut self) { |
| 257 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); | 605 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); |
| 258 | } | 606 | } |
| @@ -264,6 +612,39 @@ macro_rules! impl_adc_pin { | |||
| 264 | }; | 612 | }; |
| 265 | } | 613 | } |
| 266 | 614 | ||
| 615 | #[allow(unused_macros)] | ||
| 616 | macro_rules! impl_adc_pair { | ||
| 617 | ($inst:ident, $pin:ident, $npin:ident, $ch:expr) => { | ||
| 618 | impl crate::adc::AdcChannel<peripherals::$inst> | ||
| 619 | for ( | ||
| 620 | crate::Peri<'_, crate::peripherals::$pin>, | ||
| 621 | crate::Peri<'_, crate::peripherals::$npin>, | ||
| 622 | ) | ||
| 623 | { | ||
| 624 | } | ||
| 625 | impl crate::adc::SealedAdcChannel<peripherals::$inst> | ||
| 626 | for ( | ||
| 627 | crate::Peri<'_, crate::peripherals::$pin>, | ||
| 628 | crate::Peri<'_, crate::peripherals::$npin>, | ||
| 629 | ) | ||
| 630 | { | ||
| 631 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))] | ||
| 632 | fn setup(&mut self) { | ||
| 633 | <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0); | ||
| 634 | <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1); | ||
| 635 | } | ||
| 636 | |||
| 637 | fn channel(&self) -> u8 { | ||
| 638 | $ch | ||
| 639 | } | ||
| 640 | |||
| 641 | fn is_differential(&self) -> bool { | ||
| 642 | true | ||
| 643 | } | ||
| 644 | } | ||
| 645 | }; | ||
| 646 | } | ||
| 647 | |||
| 267 | /// Get the maximum reading value for this resolution. | 648 | /// Get the maximum reading value for this resolution. |
| 268 | /// | 649 | /// |
| 269 | /// This is `2**n - 1`. | 650 | /// This is `2**n - 1`. |
