diff options
| author | HybridChild <[email protected]> | 2025-11-13 21:29:56 +0100 |
|---|---|---|
| committer | HybridChild <[email protected]> | 2025-11-13 21:29:56 +0100 |
| commit | 4219415e66f20b72d7d09d17195bd1c414bfa8cd (patch) | |
| tree | 29c9672d3eef0c7aacab9caa22c0ae4d1c39abcd | |
| parent | 82dcaf118100c883a95397e3f9867a4043a4de7b (diff) | |
| parent | 86fbcbdd7b9a5d37f6a7b1553e1ad0b5e5c8aa96 (diff) | |
Merge branch 'main' into stm32_i2c_v2_transaction
| -rw-r--r-- | embassy-stm32/build.rs | 124 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/adc4.rs | 83 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/c0.rs | 505 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/g4.rs | 82 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 85 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v2.rs | 51 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v3.rs | 18 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/v4.rs | 102 | ||||
| -rw-r--r-- | examples/stm32c0/src/bin/adc.rs | 18 |
9 files changed, 374 insertions, 694 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index ad6743f96..1e11eb8dc 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -1695,70 +1695,88 @@ fn main() { | |||
| 1695 | } | 1695 | } |
| 1696 | 1696 | ||
| 1697 | // ======== | 1697 | // ======== |
| 1698 | // Generate Div/Mul impls for RCC prescalers/dividers/multipliers. | 1698 | // Generate Div/Mul impls for RCC and ADC prescalers/dividers/multipliers. |
| 1699 | for e in rcc_registers.ir.enums { | 1699 | for (kind, psc_enums) in ["rcc", "adc", "adccommon"].iter().filter_map(|kind| { |
| 1700 | fn is_rcc_name(e: &str) -> bool { | 1700 | METADATA |
| 1701 | match e { | 1701 | .peripherals |
| 1702 | "Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true, | 1702 | .iter() |
| 1703 | "Timpre" | "Pllrclkpre" => false, | 1703 | .filter_map(|p| p.registers.as_ref()) |
| 1704 | e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, | 1704 | .find(|r| r.kind == *kind) |
| 1705 | _ => false, | 1705 | .map(|r| (*kind, r.ir.enums)) |
| 1706 | }) { | ||
| 1707 | for e in psc_enums.iter() { | ||
| 1708 | fn is_adc_name(e: &str) -> bool { | ||
| 1709 | match e { | ||
| 1710 | "Presc" | "Adc4Presc" | "Adcpre" => true, | ||
| 1711 | _ => false, | ||
| 1712 | } | ||
| 1706 | } | 1713 | } |
| 1707 | } | ||
| 1708 | 1714 | ||
| 1709 | fn parse_num(n: &str) -> Result<Frac, ()> { | 1715 | fn is_rcc_name(e: &str) -> bool { |
| 1710 | for prefix in ["DIV", "MUL"] { | 1716 | match e { |
| 1711 | if let Some(n) = n.strip_prefix(prefix) { | 1717 | "Pllp" | "Pllq" | "Pllr" | "Plldivst" | "Pllm" | "Plln" | "Prediv1" | "Prediv2" | "Hpre5" => true, |
| 1712 | let exponent = n.find('_').map(|e| n.len() - 1 - e).unwrap_or(0) as u32; | 1718 | "Timpre" | "Pllrclkpre" => false, |
| 1713 | let mantissa = n.replace('_', "").parse().map_err(|_| ())?; | 1719 | e if e.ends_with("pre") || e.ends_with("pres") || e.ends_with("div") || e.ends_with("mul") => true, |
| 1714 | let f = Frac { | 1720 | _ => false, |
| 1715 | num: mantissa, | ||
| 1716 | denom: 10u32.pow(exponent), | ||
| 1717 | }; | ||
| 1718 | return Ok(f.simplify()); | ||
| 1719 | } | 1721 | } |
| 1720 | } | 1722 | } |
| 1721 | Err(()) | ||
| 1722 | } | ||
| 1723 | 1723 | ||
| 1724 | if is_rcc_name(e.name) { | 1724 | fn parse_num(n: &str) -> Result<Frac, ()> { |
| 1725 | let enum_name = format_ident!("{}", e.name); | 1725 | for prefix in ["DIV", "MUL"] { |
| 1726 | let mut muls = Vec::new(); | 1726 | if let Some(n) = n.strip_prefix(prefix) { |
| 1727 | let mut divs = Vec::new(); | 1727 | let exponent = n.find('_').map(|e| n.len() - 1 - e).unwrap_or(0) as u32; |
| 1728 | for v in e.variants { | 1728 | let mantissa = n.replace('_', "").parse().map_err(|_| ())?; |
| 1729 | let Ok(val) = parse_num(v.name) else { | 1729 | let f = Frac { |
| 1730 | panic!("could not parse mul/div. enum={} variant={}", e.name, v.name) | 1730 | num: mantissa, |
| 1731 | }; | 1731 | denom: 10u32.pow(exponent), |
| 1732 | let variant_name = format_ident!("{}", v.name); | 1732 | }; |
| 1733 | let variant = quote!(crate::pac::rcc::vals::#enum_name::#variant_name); | 1733 | return Ok(f.simplify()); |
| 1734 | let num = val.num; | 1734 | } |
| 1735 | let denom = val.denom; | 1735 | } |
| 1736 | muls.push(quote!(#variant => self * #num / #denom,)); | 1736 | Err(()) |
| 1737 | divs.push(quote!(#variant => self * #denom / #num,)); | ||
| 1738 | } | 1737 | } |
| 1739 | 1738 | ||
| 1740 | g.extend(quote! { | 1739 | if (kind == "rcc" && is_rcc_name(e.name)) || ((kind == "adccommon" || kind == "adc") && is_adc_name(e.name)) |
| 1741 | impl core::ops::Div<crate::pac::rcc::vals::#enum_name> for crate::time::Hertz { | 1740 | { |
| 1742 | type Output = crate::time::Hertz; | 1741 | let kind = format_ident!("{}", kind); |
| 1743 | fn div(self, rhs: crate::pac::rcc::vals::#enum_name) -> Self::Output { | 1742 | let enum_name = format_ident!("{}", e.name); |
| 1744 | match rhs { | 1743 | let mut muls = Vec::new(); |
| 1745 | #(#divs)* | 1744 | let mut divs = Vec::new(); |
| 1746 | #[allow(unreachable_patterns)] | 1745 | for v in e.variants { |
| 1747 | _ => unreachable!(), | 1746 | let Ok(val) = parse_num(v.name) else { |
| 1747 | panic!("could not parse mul/div. enum={} variant={}", e.name, v.name) | ||
| 1748 | }; | ||
| 1749 | let variant_name = format_ident!("{}", v.name); | ||
| 1750 | let variant = quote!(crate::pac::#kind::vals::#enum_name::#variant_name); | ||
| 1751 | let num = val.num; | ||
| 1752 | let denom = val.denom; | ||
| 1753 | muls.push(quote!(#variant => self * #num / #denom,)); | ||
| 1754 | divs.push(quote!(#variant => self * #denom / #num,)); | ||
| 1755 | } | ||
| 1756 | |||
| 1757 | g.extend(quote! { | ||
| 1758 | impl core::ops::Div<crate::pac::#kind::vals::#enum_name> for crate::time::Hertz { | ||
| 1759 | type Output = crate::time::Hertz; | ||
| 1760 | fn div(self, rhs: crate::pac::#kind::vals::#enum_name) -> Self::Output { | ||
| 1761 | match rhs { | ||
| 1762 | #(#divs)* | ||
| 1763 | #[allow(unreachable_patterns)] | ||
| 1764 | _ => unreachable!(), | ||
| 1765 | } | ||
| 1748 | } | 1766 | } |
| 1749 | } | 1767 | } |
| 1750 | } | 1768 | impl core::ops::Mul<crate::pac::#kind::vals::#enum_name> for crate::time::Hertz { |
| 1751 | impl core::ops::Mul<crate::pac::rcc::vals::#enum_name> for crate::time::Hertz { | 1769 | type Output = crate::time::Hertz; |
| 1752 | type Output = crate::time::Hertz; | 1770 | fn mul(self, rhs: crate::pac::#kind::vals::#enum_name) -> Self::Output { |
| 1753 | fn mul(self, rhs: crate::pac::rcc::vals::#enum_name) -> Self::Output { | 1771 | match rhs { |
| 1754 | match rhs { | 1772 | #(#muls)* |
| 1755 | #(#muls)* | 1773 | #[allow(unreachable_patterns)] |
| 1756 | #[allow(unreachable_patterns)] | 1774 | _ => unreachable!(), |
| 1757 | _ => unreachable!(), | 1775 | } |
| 1758 | } | 1776 | } |
| 1759 | } | 1777 | } |
| 1760 | } | 1778 | }); |
| 1761 | }); | 1779 | } |
| 1762 | } | 1780 | } |
| 1763 | } | 1781 | } |
| 1764 | 1782 | ||
diff --git a/embassy-stm32/src/adc/adc4.rs b/embassy-stm32/src/adc/adc4.rs index 52678d1b6..babdebfdb 100644 --- a/embassy-stm32/src/adc/adc4.rs +++ b/embassy-stm32/src/adc/adc4.rs | |||
| @@ -76,71 +76,17 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { | |||
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 79 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 80 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 80 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 81 | #[allow(unused)] | 81 | match raw_prescaler { |
| 82 | enum Prescaler { | 82 | 0 => Presc::DIV1, |
| 83 | NotDivided, | 83 | 1 => Presc::DIV2, |
| 84 | DividedBy2, | 84 | 2..=3 => Presc::DIV4, |
| 85 | DividedBy4, | 85 | 4..=5 => Presc::DIV6, |
| 86 | DividedBy6, | 86 | 6..=7 => Presc::DIV8, |
| 87 | DividedBy8, | 87 | 8..=9 => Presc::DIV10, |
| 88 | DividedBy10, | 88 | 10..=11 => Presc::DIV12, |
| 89 | DividedBy12, | 89 | _ => unimplemented!(), |
| 90 | DividedBy16, | ||
| 91 | DividedBy32, | ||
| 92 | DividedBy64, | ||
| 93 | DividedBy128, | ||
| 94 | DividedBy256, | ||
| 95 | } | ||
| 96 | |||
| 97 | impl Prescaler { | ||
| 98 | fn from_ker_ck(frequency: Hertz) -> Self { | ||
| 99 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | ||
| 100 | match raw_prescaler { | ||
| 101 | 0 => Self::NotDivided, | ||
| 102 | 1 => Self::DividedBy2, | ||
| 103 | 2..=3 => Self::DividedBy4, | ||
| 104 | 4..=5 => Self::DividedBy6, | ||
| 105 | 6..=7 => Self::DividedBy8, | ||
| 106 | 8..=9 => Self::DividedBy10, | ||
| 107 | 10..=11 => Self::DividedBy12, | ||
| 108 | _ => unimplemented!(), | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | fn divisor(&self) -> u32 { | ||
| 113 | match self { | ||
| 114 | Prescaler::NotDivided => 1, | ||
| 115 | Prescaler::DividedBy2 => 2, | ||
| 116 | Prescaler::DividedBy4 => 4, | ||
| 117 | Prescaler::DividedBy6 => 6, | ||
| 118 | Prescaler::DividedBy8 => 8, | ||
| 119 | Prescaler::DividedBy10 => 10, | ||
| 120 | Prescaler::DividedBy12 => 12, | ||
| 121 | Prescaler::DividedBy16 => 16, | ||
| 122 | Prescaler::DividedBy32 => 32, | ||
| 123 | Prescaler::DividedBy64 => 64, | ||
| 124 | Prescaler::DividedBy128 => 128, | ||
| 125 | Prescaler::DividedBy256 => 256, | ||
| 126 | } | ||
| 127 | } | ||
| 128 | |||
| 129 | fn presc(&self) -> Presc { | ||
| 130 | match self { | ||
| 131 | Prescaler::NotDivided => Presc::DIV1, | ||
| 132 | Prescaler::DividedBy2 => Presc::DIV2, | ||
| 133 | Prescaler::DividedBy4 => Presc::DIV4, | ||
| 134 | Prescaler::DividedBy6 => Presc::DIV6, | ||
| 135 | Prescaler::DividedBy8 => Presc::DIV8, | ||
| 136 | Prescaler::DividedBy10 => Presc::DIV10, | ||
| 137 | Prescaler::DividedBy12 => Presc::DIV12, | ||
| 138 | Prescaler::DividedBy16 => Presc::DIV16, | ||
| 139 | Prescaler::DividedBy32 => Presc::DIV32, | ||
| 140 | Prescaler::DividedBy64 => Presc::DIV64, | ||
| 141 | Prescaler::DividedBy128 => Presc::DIV128, | ||
| 142 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 143 | } | ||
| 144 | } | 90 | } |
| 145 | } | 91 | } |
| 146 | 92 | ||
| @@ -212,6 +158,7 @@ foreach_adc!( | |||
| 212 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) | 158 | reg.set_chselrmod(Chselrmod::ENABLE_INPUT) |
| 213 | }); | 159 | }); |
| 214 | } | 160 | } |
| 161 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 215 | _ => unreachable!(), | 162 | _ => unreachable!(), |
| 216 | } | 163 | } |
| 217 | } | 164 | } |
| @@ -283,11 +230,11 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> { | |||
| 283 | /// Create a new ADC driver. | 230 | /// Create a new ADC driver. |
| 284 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { | 231 | pub fn new_adc4(adc: Peri<'d, T>) -> Self { |
| 285 | rcc::enable_and_reset::<T>(); | 232 | rcc::enable_and_reset::<T>(); |
| 286 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 233 | let prescaler = from_ker_ck(T::frequency()); |
| 287 | 234 | ||
| 288 | T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 235 | T::regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 289 | 236 | ||
| 290 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 237 | let frequency = T::frequency() / prescaler; |
| 291 | info!("ADC4 frequency set to {}", frequency); | 238 | info!("ADC4 frequency set to {}", frequency); |
| 292 | 239 | ||
| 293 | if frequency > MAX_ADC_CLK_FREQ { | 240 | if frequency > MAX_ADC_CLK_FREQ { |
diff --git a/embassy-stm32/src/adc/c0.rs b/embassy-stm32/src/adc/c0.rs index bc97a7c4b..983e7c10d 100644 --- a/embassy-stm32/src/adc/c0.rs +++ b/embassy-stm32/src/adc/c0.rs | |||
| @@ -1,12 +1,10 @@ | |||
| 1 | use pac::adc::vals::Scandir; | ||
| 2 | #[allow(unused)] | 1 | #[allow(unused)] |
| 3 | use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; | 2 | use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; |
| 4 | use pac::adccommon::vals::Presc; | 3 | use pac::adccommon::vals::Presc; |
| 4 | use stm32_metapac::adc::vals::Scandir; | ||
| 5 | 5 | ||
| 6 | use super::{ | 6 | use super::{Adc, Instance, Resolution, blocking_delay_us}; |
| 7 | Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, | 7 | use crate::adc::{AnyInstance, ConversionMode}; |
| 8 | }; | ||
| 9 | use crate::dma::Transfer; | ||
| 10 | use crate::time::Hertz; | 8 | use crate::time::Hertz; |
| 11 | use crate::{Peri, pac, rcc}; | 9 | use crate::{Peri, pac, rcc}; |
| 12 | 10 | ||
| @@ -32,123 +30,184 @@ impl<T: Instance> super::SealedSpecialConverter<super::Temperature> for T { | |||
| 32 | const CHANNEL: u8 = 9; | 30 | const CHANNEL: u8 = 9; |
| 33 | } | 31 | } |
| 34 | 32 | ||
| 35 | #[derive(Copy, Clone, Debug)] | 33 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 36 | pub enum Prescaler { | 34 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 37 | NotDivided, | 35 | match raw_prescaler { |
| 38 | DividedBy2, | 36 | 0 => Presc::DIV1, |
| 39 | DividedBy4, | 37 | 1 => Presc::DIV2, |
| 40 | DividedBy6, | 38 | 2..=3 => Presc::DIV4, |
| 41 | DividedBy8, | 39 | 4..=5 => Presc::DIV6, |
| 42 | DividedBy10, | 40 | 6..=7 => Presc::DIV8, |
| 43 | DividedBy12, | 41 | 8..=9 => Presc::DIV10, |
| 44 | DividedBy16, | 42 | 10..=11 => Presc::DIV12, |
| 45 | DividedBy32, | 43 | _ => unimplemented!(), |
| 46 | DividedBy64, | 44 | } |
| 47 | DividedBy128, | ||
| 48 | DividedBy256, | ||
| 49 | } | 45 | } |
| 50 | 46 | ||
| 51 | impl Prescaler { | 47 | impl<T: Instance> super::SealedAnyInstance for T { |
| 52 | fn from_ker_ck(frequency: Hertz) -> Self { | 48 | fn dr() -> *mut u16 { |
| 53 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | 49 | T::regs().dr().as_ptr() as *mut u16 |
| 54 | match raw_prescaler { | ||
| 55 | 0 => Self::NotDivided, | ||
| 56 | 1 => Self::DividedBy2, | ||
| 57 | 2..=3 => Self::DividedBy4, | ||
| 58 | 4..=5 => Self::DividedBy6, | ||
| 59 | 6..=7 => Self::DividedBy8, | ||
| 60 | 8..=9 => Self::DividedBy10, | ||
| 61 | 10..=11 => Self::DividedBy12, | ||
| 62 | _ => unimplemented!(), | ||
| 63 | } | ||
| 64 | } | 50 | } |
| 65 | 51 | ||
| 66 | #[allow(unused)] | 52 | fn enable() { |
| 67 | fn divisor(&self) -> u32 { | 53 | T::regs().isr().modify(|w| w.set_adrdy(true)); |
| 68 | match self { | 54 | T::regs().cr().modify(|w| w.set_aden(true)); |
| 69 | Prescaler::NotDivided => 1, | 55 | // ADRDY is "ADC ready". Wait until it will be True. |
| 70 | Prescaler::DividedBy2 => 2, | 56 | while !T::regs().isr().read().adrdy() {} |
| 71 | Prescaler::DividedBy4 => 4, | 57 | } |
| 72 | Prescaler::DividedBy6 => 6, | 58 | |
| 73 | Prescaler::DividedBy8 => 8, | 59 | fn start() { |
| 74 | Prescaler::DividedBy10 => 10, | 60 | // Start conversion |
| 75 | Prescaler::DividedBy12 => 12, | 61 | T::regs().cr().modify(|reg| { |
| 76 | Prescaler::DividedBy16 => 16, | 62 | reg.set_adstart(true); |
| 77 | Prescaler::DividedBy32 => 32, | 63 | }); |
| 78 | Prescaler::DividedBy64 => 64, | 64 | } |
| 79 | Prescaler::DividedBy128 => 128, | 65 | |
| 80 | Prescaler::DividedBy256 => 256, | 66 | fn stop() { |
| 67 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | ||
| 68 | T::regs().cr().modify(|reg| { | ||
| 69 | reg.set_adstp(Adstp::STOP); | ||
| 70 | }); | ||
| 71 | while T::regs().cr().read().adstart() {} | ||
| 81 | } | 72 | } |
| 73 | |||
| 74 | // Reset configuration. | ||
| 75 | T::regs().cfgr1().modify(|reg| { | ||
| 76 | reg.set_cont(false); | ||
| 77 | reg.set_dmacfg(Dmacfg::from_bits(0)); | ||
| 78 | reg.set_dmaen(false); | ||
| 79 | }); | ||
| 82 | } | 80 | } |
| 83 | 81 | ||
| 84 | fn presc(&self) -> Presc { | 82 | fn configure_dma(conversion_mode: super::ConversionMode) { |
| 85 | match self { | 83 | match conversion_mode { |
| 86 | Prescaler::NotDivided => Presc::DIV1, | 84 | ConversionMode::Singular => { |
| 87 | Prescaler::DividedBy2 => Presc::DIV2, | 85 | // Enable overrun control, so no new DMA requests will be generated until |
| 88 | Prescaler::DividedBy4 => Presc::DIV4, | 86 | // previous DR values is read. |
| 89 | Prescaler::DividedBy6 => Presc::DIV6, | 87 | T::regs().isr().modify(|reg| { |
| 90 | Prescaler::DividedBy8 => Presc::DIV8, | 88 | reg.set_ovr(true); |
| 91 | Prescaler::DividedBy10 => Presc::DIV10, | 89 | }); |
| 92 | Prescaler::DividedBy12 => Presc::DIV12, | 90 | |
| 93 | Prescaler::DividedBy16 => Presc::DIV16, | 91 | // Set continuous mode with oneshot dma. |
| 94 | Prescaler::DividedBy32 => Presc::DIV32, | 92 | T::regs().cfgr1().modify(|reg| { |
| 95 | Prescaler::DividedBy64 => Presc::DIV64, | 93 | reg.set_discen(false); |
| 96 | Prescaler::DividedBy128 => Presc::DIV128, | 94 | reg.set_cont(true); |
| 97 | Prescaler::DividedBy256 => Presc::DIV256, | 95 | reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); |
| 96 | reg.set_dmaen(true); | ||
| 97 | reg.set_ovrmod(Ovrmod::PRESERVE); | ||
| 98 | }); | ||
| 99 | } | ||
| 98 | } | 100 | } |
| 99 | } | 101 | } |
| 100 | } | ||
| 101 | 102 | ||
| 102 | #[cfg(feature = "defmt")] | 103 | fn configure_sequence(mut sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool) { |
| 103 | impl<'a> defmt::Format for Prescaler { | 104 | T::regs().cfgr1().modify(|reg| { |
| 104 | fn format(&self, fmt: defmt::Formatter) { | 105 | reg.set_chselrmod(!blocking); |
| 105 | match self { | 106 | reg.set_align(Align::RIGHT); |
| 106 | Prescaler::NotDivided => defmt::write!(fmt, "Prescaler::NotDivided"), | 107 | }); |
| 107 | Prescaler::DividedBy2 => defmt::write!(fmt, "Prescaler::DividedBy2"), | 108 | |
| 108 | Prescaler::DividedBy4 => defmt::write!(fmt, "Prescaler::DividedBy4"), | 109 | assert!(!blocking || sequence.len() == 1, "Sequence len must be 1 for blocking."); |
| 109 | Prescaler::DividedBy6 => defmt::write!(fmt, "Prescaler::DividedBy6"), | 110 | if blocking { |
| 110 | Prescaler::DividedBy8 => defmt::write!(fmt, "Prescaler::DividedBy8"), | 111 | let ((ch, _), sample_time) = sequence.next().unwrap(); |
| 111 | Prescaler::DividedBy10 => defmt::write!(fmt, "Prescaler::DividedBy10"), | 112 | // Set all channels to use SMP1 field as source. |
| 112 | Prescaler::DividedBy12 => defmt::write!(fmt, "Prescaler::DividedBy12"), | 113 | T::regs().smpr().modify(|w| { |
| 113 | Prescaler::DividedBy16 => defmt::write!(fmt, "Prescaler::DividedBy16"), | 114 | w.smpsel(0); |
| 114 | Prescaler::DividedBy32 => defmt::write!(fmt, "Prescaler::DividedBy32"), | 115 | w.set_smp1(sample_time); |
| 115 | Prescaler::DividedBy64 => defmt::write!(fmt, "Prescaler::DividedBy64"), | 116 | }); |
| 116 | Prescaler::DividedBy128 => defmt::write!(fmt, "Prescaler::DividedBy128"), | 117 | |
| 117 | Prescaler::DividedBy256 => defmt::write!(fmt, "Prescaler::DividedBy256"), | 118 | // write() because we want all other bits to be set to 0. |
| 119 | T::regs().chselr().write(|w| w.set_chsel(ch.into(), true)); | ||
| 120 | } else { | ||
| 121 | let mut hw_channel_selection: u32 = 0; | ||
| 122 | let mut is_ordered_up = true; | ||
| 123 | let mut is_ordered_down = true; | ||
| 124 | let mut needs_hw = false; | ||
| 125 | |||
| 126 | assert!( | ||
| 127 | sequence.len() <= CHSELR_SQ_SIZE, | ||
| 128 | "Sequence read set cannot be more than {} in size.", | ||
| 129 | CHSELR_SQ_SIZE | ||
| 130 | ); | ||
| 131 | let mut last_sq_set: usize = 0; | ||
| 132 | let mut last_channel: u8 = 0; | ||
| 133 | T::regs().chselr_sq().write(|w| { | ||
| 134 | for (i, ((channel, _), _sample_time)) in sequence.enumerate() { | ||
| 135 | needs_hw = needs_hw || channel > CHSELR_SQ_MAX_CHANNEL; | ||
| 136 | last_sq_set = i; | ||
| 137 | is_ordered_up = is_ordered_up && channel > last_channel; | ||
| 138 | is_ordered_down = is_ordered_down && channel < last_channel; | ||
| 139 | hw_channel_selection += 1 << channel; | ||
| 140 | last_channel = channel; | ||
| 141 | |||
| 142 | if !needs_hw { | ||
| 143 | w.set_sq(i, channel); | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | assert!( | ||
| 148 | !needs_hw || is_ordered_up || is_ordered_down, | ||
| 149 | "Sequencer is required because of unordered channels, but only support HW channels smaller than {}.", | ||
| 150 | CHSELR_SQ_MAX_CHANNEL | ||
| 151 | ); | ||
| 152 | |||
| 153 | if needs_hw { | ||
| 154 | assert!( | ||
| 155 | hw_channel_selection != 0, | ||
| 156 | "Some bits in `hw_channel_selection` shall be set." | ||
| 157 | ); | ||
| 158 | assert!( | ||
| 159 | (hw_channel_selection >> NUM_HW_CHANNELS) == 0, | ||
| 160 | "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", | ||
| 161 | NUM_HW_CHANNELS | ||
| 162 | ); | ||
| 163 | |||
| 164 | T::regs().cfgr1().modify(|reg| { | ||
| 165 | reg.set_chselrmod(false); | ||
| 166 | reg.set_scandir(if is_ordered_up { Scandir::UP} else { Scandir::BACK }); | ||
| 167 | }); | ||
| 168 | |||
| 169 | // Set required channels for multi-convert. | ||
| 170 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } | ||
| 171 | } else { | ||
| 172 | for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { | ||
| 173 | w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); | ||
| 174 | } | ||
| 175 | } | ||
| 176 | }); | ||
| 118 | } | 177 | } |
| 178 | |||
| 179 | // Trigger and wait for the channel selection procedure to complete. | ||
| 180 | T::regs().isr().modify(|w| w.set_ccrdy(false)); | ||
| 181 | while !T::regs().isr().read().ccrdy() {} | ||
| 119 | } | 182 | } |
| 120 | } | ||
| 121 | 183 | ||
| 122 | /// Number of samples used for averaging. | 184 | fn convert() -> u16 { |
| 123 | /// TODO: Implement hardware averaging setting. | 185 | // Set single conversion mode. |
| 124 | #[allow(unused)] | 186 | T::regs().cfgr1().modify(|w| w.set_cont(false)); |
| 125 | #[derive(Copy, Clone, Debug)] | 187 | |
| 126 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 188 | // Start conversion |
| 127 | pub enum Averaging { | 189 | T::regs().cr().modify(|reg| { |
| 128 | Disabled, | 190 | reg.set_adstart(true); |
| 129 | Samples2, | 191 | }); |
| 130 | Samples4, | 192 | |
| 131 | Samples8, | 193 | // Waiting for End Of Conversion (EOC). |
| 132 | Samples16, | 194 | while !T::regs().isr().read().eoc() {} |
| 133 | Samples32, | 195 | |
| 134 | Samples64, | 196 | T::regs().dr().read().data() as u16 |
| 135 | Samples128, | 197 | } |
| 136 | Samples256, | ||
| 137 | Samples512, | ||
| 138 | Samples1024, | ||
| 139 | } | 198 | } |
| 140 | 199 | ||
| 141 | impl<'d, T: Instance> Adc<'d, T> { | 200 | impl<'d, T: AnyInstance> Adc<'d, T> { |
| 142 | /// Create a new ADC driver. | 201 | /// Create a new ADC driver. |
| 143 | pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { | 202 | pub fn new(adc: Peri<'d, T>, resolution: Resolution) -> Self { |
| 144 | rcc::enable_and_reset::<T>(); | 203 | rcc::enable_and_reset::<T>(); |
| 145 | 204 | ||
| 146 | T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); | 205 | T::regs().cfgr2().modify(|w| w.set_ckmode(Ckmode::SYSCLK)); |
| 147 | 206 | ||
| 148 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 207 | let prescaler = from_ker_ck(T::frequency()); |
| 149 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 208 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 150 | 209 | ||
| 151 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 210 | let frequency = T::frequency() / prescaler; |
| 152 | debug!("ADC frequency set to {}", frequency); | 211 | debug!("ADC frequency set to {}", frequency); |
| 153 | 212 | ||
| 154 | if frequency > MAX_ADC_CLK_FREQ { | 213 | if frequency > MAX_ADC_CLK_FREQ { |
| @@ -158,22 +217,6 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 158 | ); | 217 | ); |
| 159 | } | 218 | } |
| 160 | 219 | ||
| 161 | let mut s = Self { adc }; | ||
| 162 | |||
| 163 | s.power_up(); | ||
| 164 | |||
| 165 | s.set_resolution(resolution); | ||
| 166 | |||
| 167 | s.calibrate(); | ||
| 168 | |||
| 169 | s.enable(); | ||
| 170 | |||
| 171 | s.configure_default(); | ||
| 172 | |||
| 173 | s | ||
| 174 | } | ||
| 175 | |||
| 176 | fn power_up(&mut self) { | ||
| 177 | T::regs().cr().modify(|reg| { | 220 | T::regs().cr().modify(|reg| { |
| 178 | reg.set_advregen(true); | 221 | reg.set_advregen(true); |
| 179 | }); | 222 | }); |
| @@ -181,9 +224,9 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 181 | // "The software must wait for the ADC voltage regulator startup time." | 224 | // "The software must wait for the ADC voltage regulator startup time." |
| 182 | // See datasheet for the value. | 225 | // See datasheet for the value. |
| 183 | blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); | 226 | blocking_delay_us(TIME_ADC_VOLTAGE_REGUALTOR_STARTUP_US + 1); |
| 184 | } | ||
| 185 | 227 | ||
| 186 | fn calibrate(&mut self) { | 228 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); |
| 229 | |||
| 187 | // We have to make sure AUTOFF is OFF, but keep its value after calibration. | 230 | // We have to make sure AUTOFF is OFF, but keep its value after calibration. |
| 188 | let autoff_value = T::regs().cfgr1().read().autoff(); | 231 | let autoff_value = T::regs().cfgr1().read().autoff(); |
| 189 | T::regs().cfgr1().modify(|w| w.set_autoff(false)); | 232 | T::regs().cfgr1().modify(|w| w.set_autoff(false)); |
| @@ -197,22 +240,17 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 197 | debug!("ADC calibration value: {}.", T::regs().dr().read().data()); | 240 | debug!("ADC calibration value: {}.", T::regs().dr().read().data()); |
| 198 | 241 | ||
| 199 | T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); | 242 | T::regs().cfgr1().modify(|w| w.set_autoff(autoff_value)); |
| 200 | } | ||
| 201 | 243 | ||
| 202 | fn enable(&mut self) { | 244 | T::enable(); |
| 203 | T::regs().isr().modify(|w| w.set_adrdy(true)); | ||
| 204 | T::regs().cr().modify(|w| w.set_aden(true)); | ||
| 205 | // ADRDY is "ADC ready". Wait until it will be True. | ||
| 206 | while !T::regs().isr().read().adrdy() {} | ||
| 207 | } | ||
| 208 | 245 | ||
| 209 | fn configure_default(&mut self) { | ||
| 210 | // single conversion mode, software trigger | 246 | // single conversion mode, software trigger |
| 211 | T::regs().cfgr1().modify(|w| { | 247 | T::regs().cfgr1().modify(|w| { |
| 212 | w.set_cont(false); | 248 | w.set_cont(false); |
| 213 | w.set_exten(Exten::DISABLED); | 249 | w.set_exten(Exten::DISABLED); |
| 214 | w.set_align(Align::RIGHT); | 250 | w.set_align(Align::RIGHT); |
| 215 | }); | 251 | }); |
| 252 | |||
| 253 | Self { adc } | ||
| 216 | } | 254 | } |
| 217 | 255 | ||
| 218 | /// Enable reading the voltage reference internal channel. | 256 | /// Enable reading the voltage reference internal channel. |
| @@ -233,219 +271,4 @@ impl<'d, T: Instance> Adc<'d, T> { | |||
| 233 | 271 | ||
| 234 | super::Temperature {} | 272 | super::Temperature {} |
| 235 | } | 273 | } |
| 236 | |||
| 237 | /// Set the ADC sample time. | ||
| 238 | /// Shall only be called when ADC is not converting. | ||
| 239 | pub fn set_sample_time_all_channels(&mut self, sample_time: SampleTime) { | ||
| 240 | // Set all channels to use SMP1 field as source. | ||
| 241 | T::regs().smpr().modify(|w| { | ||
| 242 | w.smpsel(0); | ||
| 243 | w.set_smp1(sample_time); | ||
| 244 | }); | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Set the ADC resolution. | ||
| 248 | pub fn set_resolution(&mut self, resolution: Resolution) { | ||
| 249 | T::regs().cfgr1().modify(|reg| reg.set_res(resolution)); | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Perform a single conversion. | ||
| 253 | fn convert(&mut self) -> u16 { | ||
| 254 | // Set single conversion mode. | ||
| 255 | T::regs().cfgr1().modify(|w| w.set_cont(false)); | ||
| 256 | |||
| 257 | // Start conversion | ||
| 258 | T::regs().cr().modify(|reg| { | ||
| 259 | reg.set_adstart(true); | ||
| 260 | }); | ||
| 261 | |||
| 262 | // Waiting for End Of Conversion (EOC). | ||
| 263 | while !T::regs().isr().read().eoc() {} | ||
| 264 | |||
| 265 | T::regs().dr().read().data() as u16 | ||
| 266 | } | ||
| 267 | |||
| 268 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: SampleTime) -> u16 { | ||
| 269 | self.set_sample_time_all_channels(sample_time); | ||
| 270 | |||
| 271 | Self::configure_channel(channel); | ||
| 272 | T::regs().cfgr1().write(|reg| { | ||
| 273 | reg.set_chselrmod(false); | ||
| 274 | reg.set_align(Align::RIGHT); | ||
| 275 | }); | ||
| 276 | self.convert() | ||
| 277 | } | ||
| 278 | |||
| 279 | fn setup_channel_sequencer<'a>(channel_sequence: impl ExactSizeIterator<Item = &'a mut AnyAdcChannel<T>>) { | ||
| 280 | assert!( | ||
| 281 | channel_sequence.len() <= CHSELR_SQ_SIZE, | ||
| 282 | "Seqenced read set cannot be more than {} in size.", | ||
| 283 | CHSELR_SQ_SIZE | ||
| 284 | ); | ||
| 285 | let mut last_sq_set: usize = 0; | ||
| 286 | T::regs().chselr_sq().write(|w| { | ||
| 287 | for (i, channel) in channel_sequence.enumerate() { | ||
| 288 | assert!( | ||
| 289 | channel.channel() <= CHSELR_SQ_MAX_CHANNEL, | ||
| 290 | "Sequencer only support HW channels smaller than {}.", | ||
| 291 | CHSELR_SQ_MAX_CHANNEL | ||
| 292 | ); | ||
| 293 | w.set_sq(i, channel.channel()); | ||
| 294 | last_sq_set = i; | ||
| 295 | } | ||
| 296 | |||
| 297 | for i in (last_sq_set + 1)..CHSELR_SQ_SIZE { | ||
| 298 | w.set_sq(i, CHSELR_SQ_SEQUENCE_END_MARKER); | ||
| 299 | } | ||
| 300 | }); | ||
| 301 | |||
| 302 | Self::apply_channel_conf() | ||
| 303 | } | ||
| 304 | |||
| 305 | async fn dma_convert(&mut self, rx_dma: Peri<'_, impl RxDma<T>>, readings: &mut [u16]) { | ||
| 306 | // Enable overrun control, so no new DMA requests will be generated until | ||
| 307 | // previous DR values is read. | ||
| 308 | T::regs().isr().modify(|reg| { | ||
| 309 | reg.set_ovr(true); | ||
| 310 | }); | ||
| 311 | |||
| 312 | // Set continuous mode with oneshot dma. | ||
| 313 | T::regs().cfgr1().modify(|reg| { | ||
| 314 | reg.set_discen(false); | ||
| 315 | reg.set_cont(true); | ||
| 316 | reg.set_dmacfg(Dmacfg::DMA_ONE_SHOT); | ||
| 317 | reg.set_dmaen(true); | ||
| 318 | reg.set_ovrmod(Ovrmod::PRESERVE); | ||
| 319 | }); | ||
| 320 | |||
| 321 | let request = rx_dma.request(); | ||
| 322 | let transfer = unsafe { | ||
| 323 | Transfer::new_read( | ||
| 324 | rx_dma, | ||
| 325 | request, | ||
| 326 | T::regs().dr().as_ptr() as *mut u16, | ||
| 327 | readings, | ||
| 328 | Default::default(), | ||
| 329 | ) | ||
| 330 | }; | ||
| 331 | |||
| 332 | // Start conversion. | ||
| 333 | T::regs().cr().modify(|reg| { | ||
| 334 | reg.set_adstart(true); | ||
| 335 | }); | ||
| 336 | |||
| 337 | // Wait for conversion sequence to finish. | ||
| 338 | transfer.await; | ||
| 339 | |||
| 340 | // Ensure conversions are finished. | ||
| 341 | Self::cancel_conversions(); | ||
| 342 | |||
| 343 | // Reset configuration. | ||
| 344 | T::regs().cfgr1().modify(|reg| { | ||
| 345 | reg.set_cont(false); | ||
| 346 | reg.set_dmacfg(Dmacfg::from_bits(0)); | ||
| 347 | reg.set_dmaen(false); | ||
| 348 | }); | ||
| 349 | } | ||
| 350 | |||
| 351 | /// Read one or multiple ADC channels using DMA in hardware order. | ||
| 352 | /// Readings will be ordered based on **hardware** ADC channel number and `scandir` setting. | ||
| 353 | /// Readings won't be in the same order as in the `set`! | ||
| 354 | /// | ||
| 355 | /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use | ||
| 356 | /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). | ||
| 357 | /// TODO(chudsaviet): externalize generic code and merge with read(). | ||
| 358 | pub async fn read_in_hw_order( | ||
| 359 | &mut self, | ||
| 360 | rx_dma: Peri<'_, impl RxDma<T>>, | ||
| 361 | hw_channel_selection: u32, | ||
| 362 | scandir: Scandir, | ||
| 363 | readings: &mut [u16], | ||
| 364 | ) { | ||
| 365 | assert!( | ||
| 366 | hw_channel_selection != 0, | ||
| 367 | "Some bits in `hw_channel_selection` shall be set." | ||
| 368 | ); | ||
| 369 | assert!( | ||
| 370 | (hw_channel_selection >> NUM_HW_CHANNELS) == 0, | ||
| 371 | "STM32C0 only have {} ADC channels. `hw_channel_selection` cannot have bits higher than this number set.", | ||
| 372 | NUM_HW_CHANNELS | ||
| 373 | ); | ||
| 374 | // To check for correct readings slice size, we shall solve Hamming weight problem, | ||
| 375 | // which is either slow or memory consuming. | ||
| 376 | // Since we have limited resources, we don't do it here. | ||
| 377 | // Not doing this have a great potential for a bug through. | ||
| 378 | |||
| 379 | // Ensure no conversions are ongoing. | ||
| 380 | Self::cancel_conversions(); | ||
| 381 | |||
| 382 | T::regs().cfgr1().modify(|reg| { | ||
| 383 | reg.set_chselrmod(false); | ||
| 384 | reg.set_scandir(scandir); | ||
| 385 | reg.set_align(Align::RIGHT); | ||
| 386 | }); | ||
| 387 | |||
| 388 | // Set required channels for multi-convert. | ||
| 389 | unsafe { (T::regs().chselr().as_ptr() as *mut u32).write_volatile(hw_channel_selection) } | ||
| 390 | |||
| 391 | Self::apply_channel_conf(); | ||
| 392 | |||
| 393 | self.dma_convert(rx_dma, readings).await | ||
| 394 | } | ||
| 395 | |||
| 396 | // Read ADC channels in specified order using DMA (CHSELRMOD = 1). | ||
| 397 | // In STM32C0, only lower 14 ADC channels can be read this way. | ||
| 398 | // For other channels, use `read_in_hw_order()` or blocking read. | ||
| 399 | pub async fn read( | ||
| 400 | &mut self, | ||
| 401 | rx_dma: Peri<'_, impl RxDma<T>>, | ||
| 402 | channel_sequence: impl ExactSizeIterator<Item = &mut AnyAdcChannel<T>>, | ||
| 403 | readings: &mut [u16], | ||
| 404 | ) { | ||
| 405 | assert!( | ||
| 406 | channel_sequence.len() != 0, | ||
| 407 | "Asynchronous read channel sequence cannot be empty." | ||
| 408 | ); | ||
| 409 | assert!( | ||
| 410 | channel_sequence.len() == readings.len(), | ||
| 411 | "Channel sequence length must be equal to readings length." | ||
| 412 | ); | ||
| 413 | |||
| 414 | // Ensure no conversions are ongoing. | ||
| 415 | Self::cancel_conversions(); | ||
| 416 | |||
| 417 | T::regs().cfgr1().modify(|reg| { | ||
| 418 | reg.set_chselrmod(true); | ||
| 419 | reg.set_align(Align::RIGHT); | ||
| 420 | }); | ||
| 421 | |||
| 422 | Self::setup_channel_sequencer(channel_sequence); | ||
| 423 | |||
| 424 | self.dma_convert(rx_dma, readings).await | ||
| 425 | } | ||
| 426 | |||
| 427 | fn configure_channel(channel: &mut impl AdcChannel<T>) { | ||
| 428 | channel.setup(); | ||
| 429 | // write() because we want all other bits to be set to 0. | ||
| 430 | T::regs() | ||
| 431 | .chselr() | ||
| 432 | .write(|w| w.set_chsel(channel.channel().into(), true)); | ||
| 433 | |||
| 434 | Self::apply_channel_conf(); | ||
| 435 | } | ||
| 436 | |||
| 437 | fn apply_channel_conf() { | ||
| 438 | // Trigger and wait for the channel selection procedure to complete. | ||
| 439 | T::regs().isr().modify(|w| w.set_ccrdy(false)); | ||
| 440 | while !T::regs().isr().read().ccrdy() {} | ||
| 441 | } | ||
| 442 | |||
| 443 | fn cancel_conversions() { | ||
| 444 | if T::regs().cr().read().adstart() && !T::regs().cr().read().addis() { | ||
| 445 | T::regs().cr().modify(|reg| { | ||
| 446 | reg.set_adstp(Adstp::STOP); | ||
| 447 | }); | ||
| 448 | while T::regs().cr().read().adstart() {} | ||
| 449 | } | ||
| 450 | } | ||
| 451 | } | 274 | } |
diff --git a/embassy-stm32/src/adc/g4.rs b/embassy-stm32/src/adc/g4.rs index 71dc8acc0..514734017 100644 --- a/embassy-stm32/src/adc/g4.rs +++ b/embassy-stm32/src/adc/g4.rs | |||
| @@ -32,71 +32,17 @@ const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(60); | |||
| 32 | #[cfg(stm32h7)] | 32 | #[cfg(stm32h7)] |
| 33 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); | 33 | const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); |
| 34 | 34 | ||
| 35 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 35 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 36 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 36 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 37 | #[allow(unused)] | 37 | match raw_prescaler { |
| 38 | enum Prescaler { | 38 | 0 => Presc::DIV1, |
| 39 | NotDivided, | 39 | 1 => Presc::DIV2, |
| 40 | DividedBy2, | 40 | 2..=3 => Presc::DIV4, |
| 41 | DividedBy4, | 41 | 4..=5 => Presc::DIV6, |
| 42 | DividedBy6, | 42 | 6..=7 => Presc::DIV8, |
| 43 | DividedBy8, | 43 | 8..=9 => Presc::DIV10, |
| 44 | DividedBy10, | 44 | 10..=11 => Presc::DIV12, |
| 45 | DividedBy12, | 45 | _ => unimplemented!(), |
| 46 | DividedBy16, | ||
| 47 | DividedBy32, | ||
| 48 | DividedBy64, | ||
| 49 | DividedBy128, | ||
| 50 | DividedBy256, | ||
| 51 | } | ||
| 52 | |||
| 53 | impl Prescaler { | ||
| 54 | fn from_ker_ck(frequency: Hertz) -> Self { | ||
| 55 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | ||
| 56 | match raw_prescaler { | ||
| 57 | 0 => Self::NotDivided, | ||
| 58 | 1 => Self::DividedBy2, | ||
| 59 | 2..=3 => Self::DividedBy4, | ||
| 60 | 4..=5 => Self::DividedBy6, | ||
| 61 | 6..=7 => Self::DividedBy8, | ||
| 62 | 8..=9 => Self::DividedBy10, | ||
| 63 | 10..=11 => Self::DividedBy12, | ||
| 64 | _ => unimplemented!(), | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | fn divisor(&self) -> u32 { | ||
| 69 | match self { | ||
| 70 | Prescaler::NotDivided => 1, | ||
| 71 | Prescaler::DividedBy2 => 2, | ||
| 72 | Prescaler::DividedBy4 => 4, | ||
| 73 | Prescaler::DividedBy6 => 6, | ||
| 74 | Prescaler::DividedBy8 => 8, | ||
| 75 | Prescaler::DividedBy10 => 10, | ||
| 76 | Prescaler::DividedBy12 => 12, | ||
| 77 | Prescaler::DividedBy16 => 16, | ||
| 78 | Prescaler::DividedBy32 => 32, | ||
| 79 | Prescaler::DividedBy64 => 64, | ||
| 80 | Prescaler::DividedBy128 => 128, | ||
| 81 | Prescaler::DividedBy256 => 256, | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | fn presc(&self) -> Presc { | ||
| 86 | match self { | ||
| 87 | Prescaler::NotDivided => Presc::DIV1, | ||
| 88 | Prescaler::DividedBy2 => Presc::DIV2, | ||
| 89 | Prescaler::DividedBy4 => Presc::DIV4, | ||
| 90 | Prescaler::DividedBy6 => Presc::DIV6, | ||
| 91 | Prescaler::DividedBy8 => Presc::DIV8, | ||
| 92 | Prescaler::DividedBy10 => Presc::DIV10, | ||
| 93 | Prescaler::DividedBy12 => Presc::DIV12, | ||
| 94 | Prescaler::DividedBy16 => Presc::DIV16, | ||
| 95 | Prescaler::DividedBy32 => Presc::DIV32, | ||
| 96 | Prescaler::DividedBy64 => Presc::DIV64, | ||
| 97 | Prescaler::DividedBy128 => Presc::DIV128, | ||
| 98 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 99 | } | ||
| 100 | } | 46 | } |
| 101 | } | 47 | } |
| 102 | 48 | ||
| @@ -292,11 +238,11 @@ impl<'d, T: Instance + AnyInstance> Adc<'d, T> { | |||
| 292 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 238 | pub fn new(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 293 | rcc::enable_and_reset::<T>(); | 239 | rcc::enable_and_reset::<T>(); |
| 294 | 240 | ||
| 295 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 241 | let prescaler = from_ker_ck(T::frequency()); |
| 296 | 242 | ||
| 297 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 243 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 298 | 244 | ||
| 299 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 245 | let frequency = T::frequency() / prescaler; |
| 300 | trace!("ADC frequency set to {}", frequency); | 246 | trace!("ADC frequency set to {}", frequency); |
| 301 | 247 | ||
| 302 | if frequency > MAX_ADC_CLK_FREQ { | 248 | if frequency > MAX_ADC_CLK_FREQ { |
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 856c2e61e..549f2f5a5 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs | |||
| @@ -88,31 +88,37 @@ pub(crate) trait SealedAdcChannel<T> { | |||
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | // Temporary patch for ADCs that have not implemented the standard iface yet | 90 | // Temporary patch for ADCs that have not implemented the standard iface yet |
| 91 | #[cfg(not(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4)))] | 91 | #[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))] |
| 92 | trait_set::trait_set! { | 92 | trait_set::trait_set! { |
| 93 | pub trait AnyInstance = Instance; | 93 | pub trait AnyInstance = Instance; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 96 | #[cfg(any( |
| 97 | #[allow(dead_code)] | 97 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 98 | ))] | ||
| 98 | pub trait BasicAnyInstance { | 99 | pub trait BasicAnyInstance { |
| 99 | type SampleTime; | 100 | type SampleTime; |
| 100 | } | 101 | } |
| 101 | 102 | ||
| 102 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 103 | #[cfg(any( |
| 103 | #[allow(dead_code)] | 104 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 |
| 105 | ))] | ||
| 104 | pub(self) trait SealedAnyInstance: BasicAnyInstance { | 106 | pub(self) trait SealedAnyInstance: BasicAnyInstance { |
| 105 | fn enable(); | 107 | fn enable(); |
| 106 | fn start(); | 108 | fn start(); |
| 107 | fn stop(); | 109 | fn stop(); |
| 108 | fn convert() -> u16; | 110 | fn convert() -> u16; |
| 109 | fn configure_dma(conversion_mode: ConversionMode); | 111 | fn configure_dma(conversion_mode: ConversionMode); |
| 112 | #[cfg(not(adc_c0))] | ||
| 110 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); | 113 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); |
| 114 | #[cfg(adc_c0)] | ||
| 115 | fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool); | ||
| 116 | #[allow(dead_code)] | ||
| 111 | fn dr() -> *mut u16; | 117 | fn dr() -> *mut u16; |
| 112 | } | 118 | } |
| 113 | 119 | ||
| 114 | // On chips without ADC4, AnyInstance is an Instance | 120 | // On chips without ADC4, AnyInstance is an Instance |
| 115 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4))] | 121 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))] |
| 116 | #[allow(private_bounds)] | 122 | #[allow(private_bounds)] |
| 117 | pub trait AnyInstance: SealedAnyInstance + Instance {} | 123 | pub trait AnyInstance: SealedAnyInstance + Instance {} |
| 118 | 124 | ||
| @@ -122,12 +128,16 @@ pub trait AnyInstance: SealedAnyInstance + Instance {} | |||
| 122 | pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} | 128 | pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} |
| 123 | 129 | ||
| 124 | // Implement AnyInstance automatically for SealedAnyInstance | 130 | // Implement AnyInstance automatically for SealedAnyInstance |
| 125 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 131 | #[cfg(any( |
| 132 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 133 | ))] | ||
| 126 | impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { | 134 | impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { |
| 127 | type SampleTime = SampleTime; | 135 | type SampleTime = SampleTime; |
| 128 | } | 136 | } |
| 129 | 137 | ||
| 130 | #[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] | 138 | #[cfg(any( |
| 139 | adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0 | ||
| 140 | ))] | ||
| 131 | impl<T: SealedAnyInstance + Instance> AnyInstance for T {} | 141 | impl<T: SealedAnyInstance + Instance> AnyInstance for T {} |
| 132 | 142 | ||
| 133 | /// Performs a busy-wait delay for a specified number of microseconds. | 143 | /// Performs a busy-wait delay for a specified number of microseconds. |
| @@ -148,18 +158,41 @@ pub(crate) fn blocking_delay_us(us: u32) { | |||
| 148 | } | 158 | } |
| 149 | } | 159 | } |
| 150 | 160 | ||
| 151 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 161 | #[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))] |
| 152 | #[allow(dead_code)] | 162 | /// Number of samples used for averaging. |
| 163 | #[derive(Copy, Clone, Debug)] | ||
| 164 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 165 | pub enum Averaging { | ||
| 166 | Disabled, | ||
| 167 | Samples2, | ||
| 168 | Samples4, | ||
| 169 | Samples8, | ||
| 170 | Samples16, | ||
| 171 | Samples32, | ||
| 172 | Samples64, | ||
| 173 | Samples128, | ||
| 174 | Samples256, | ||
| 175 | #[cfg(any(adc_c0, adc_v4, adc_u5))] | ||
| 176 | Samples512, | ||
| 177 | #[cfg(any(adc_c0, adc_v4, adc_u5))] | ||
| 178 | Samples1024, | ||
| 179 | } | ||
| 180 | |||
| 181 | #[cfg(any( | ||
| 182 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0 | ||
| 183 | ))] | ||
| 153 | pub(crate) enum ConversionMode { | 184 | pub(crate) enum ConversionMode { |
| 154 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 185 | // Should match the cfg on "read" below |
| 186 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] | ||
| 155 | Singular, | 187 | Singular, |
| 156 | #[allow(dead_code)] | 188 | // Should match the cfg on "into_ring_buffered" below |
| 189 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 157 | Repeated(RegularConversionMode), | 190 | Repeated(RegularConversionMode), |
| 158 | } | 191 | } |
| 159 | 192 | ||
| 160 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 193 | // Should match the cfg on "into_ring_buffered" below |
| 194 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 161 | // Conversion mode for regular ADC channels | 195 | // Conversion mode for regular ADC channels |
| 162 | #[allow(dead_code)] | ||
| 163 | #[derive(Copy, Clone)] | 196 | #[derive(Copy, Clone)] |
| 164 | pub enum RegularConversionMode { | 197 | pub enum RegularConversionMode { |
| 165 | // Samples as fast as possible | 198 | // Samples as fast as possible |
| @@ -170,7 +203,9 @@ pub enum RegularConversionMode { | |||
| 170 | } | 203 | } |
| 171 | 204 | ||
| 172 | impl<'d, T: AnyInstance> Adc<'d, T> { | 205 | impl<'d, T: AnyInstance> Adc<'d, T> { |
| 173 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba))] | 206 | #[cfg(any( |
| 207 | adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0 | ||
| 208 | ))] | ||
| 174 | /// Read an ADC pin. | 209 | /// Read an ADC pin. |
| 175 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { | 210 | pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { |
| 176 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] | 211 | #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] |
| @@ -178,12 +213,18 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 178 | 213 | ||
| 179 | #[cfg(not(adc_v4))] | 214 | #[cfg(not(adc_v4))] |
| 180 | T::enable(); | 215 | T::enable(); |
| 216 | #[cfg(not(adc_c0))] | ||
| 181 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); | 217 | T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); |
| 218 | #[cfg(adc_c0)] | ||
| 219 | T::configure_sequence( | ||
| 220 | [((channel.channel(), channel.is_differential()), sample_time)].into_iter(), | ||
| 221 | true, | ||
| 222 | ); | ||
| 182 | 223 | ||
| 183 | T::convert() | 224 | T::convert() |
| 184 | } | 225 | } |
| 185 | 226 | ||
| 186 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] | 227 | #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))] |
| 187 | /// Read one or multiple ADC regular channels using DMA. | 228 | /// Read one or multiple ADC regular channels using DMA. |
| 188 | /// | 229 | /// |
| 189 | /// `sequence` iterator and `readings` must have the same length. | 230 | /// `sequence` iterator and `readings` must have the same length. |
| @@ -212,6 +253,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 212 | /// | 253 | /// |
| 213 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use | 254 | /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use |
| 214 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` | 255 | /// `into_ring_buffered`, `into_ring_buffered_and_injected` |
| 256 | /// | ||
| 257 | /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use | ||
| 258 | /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0). | ||
| 259 | /// | ||
| 260 | /// In addtion, on STM320, this method will panic if the channels are not passed in order | ||
| 215 | pub async fn read( | 261 | pub async fn read( |
| 216 | &mut self, | 262 | &mut self, |
| 217 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, | 263 | rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, |
| @@ -232,8 +278,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> { | |||
| 232 | T::stop(); | 278 | T::stop(); |
| 233 | T::enable(); | 279 | T::enable(); |
| 234 | 280 | ||
| 281 | #[cfg(not(adc_c0))] | ||
| 282 | T::configure_sequence( | ||
| 283 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | ||
| 284 | ); | ||
| 285 | |||
| 286 | #[cfg(adc_c0)] | ||
| 235 | T::configure_sequence( | 287 | T::configure_sequence( |
| 236 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), | 288 | sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), |
| 289 | false, | ||
| 237 | ); | 290 | ); |
| 238 | 291 | ||
| 239 | T::configure_dma(ConversionMode::Singular); | 292 | T::configure_dma(ConversionMode::Singular); |
diff --git a/embassy-stm32/src/adc/v2.rs b/embassy-stm32/src/adc/v2.rs index 4065f89a7..07eaebf7c 100644 --- a/embassy-stm32/src/adc/v2.rs +++ b/embassy-stm32/src/adc/v2.rs | |||
| @@ -3,6 +3,7 @@ use core::sync::atomic::{Ordering, compiler_fence}; | |||
| 3 | use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; | 3 | use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 4 | use crate::adc::{Adc, Instance, Resolution, SampleTime}; | 4 | use crate::adc::{Adc, Instance, Resolution, SampleTime}; |
| 5 | use crate::pac::adc::vals; | 5 | use crate::pac::adc::vals; |
| 6 | pub use crate::pac::adccommon::vals::Adcpre; | ||
| 6 | use crate::time::Hertz; | 7 | use crate::time::Hertz; |
| 7 | use crate::{Peri, rcc}; | 8 | use crate::{Peri, rcc}; |
| 8 | 9 | ||
| @@ -50,38 +51,20 @@ impl Temperature { | |||
| 50 | } | 51 | } |
| 51 | } | 52 | } |
| 52 | 53 | ||
| 53 | enum Prescaler { | 54 | fn from_pclk2(freq: Hertz) -> Adcpre { |
| 54 | Div2, | 55 | // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). |
| 55 | Div4, | 56 | #[cfg(stm32f2)] |
| 56 | Div6, | 57 | const MAX_FREQUENCY: Hertz = Hertz(30_000_000); |
| 57 | Div8, | 58 | // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. |
| 58 | } | 59 | #[cfg(not(stm32f2))] |
| 59 | 60 | const MAX_FREQUENCY: Hertz = Hertz(36_000_000); | |
| 60 | impl Prescaler { | 61 | let raw_div = freq.0 / MAX_FREQUENCY.0; |
| 61 | fn from_pclk2(freq: Hertz) -> Self { | 62 | match raw_div { |
| 62 | // Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V). | 63 | 0..=1 => Adcpre::DIV2, |
| 63 | #[cfg(stm32f2)] | 64 | 2..=3 => Adcpre::DIV4, |
| 64 | const MAX_FREQUENCY: Hertz = Hertz(30_000_000); | 65 | 4..=5 => Adcpre::DIV6, |
| 65 | // Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz. | 66 | 6..=7 => Adcpre::DIV8, |
| 66 | #[cfg(not(stm32f2))] | 67 | _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), |
| 67 | const MAX_FREQUENCY: Hertz = Hertz(36_000_000); | ||
| 68 | let raw_div = freq.0 / MAX_FREQUENCY.0; | ||
| 69 | match raw_div { | ||
| 70 | 0..=1 => Self::Div2, | ||
| 71 | 2..=3 => Self::Div4, | ||
| 72 | 4..=5 => Self::Div6, | ||
| 73 | 6..=7 => Self::Div8, | ||
| 74 | _ => panic!("Selected PCLK2 frequency is too high for ADC with largest possible prescaler."), | ||
| 75 | } | ||
| 76 | } | ||
| 77 | |||
| 78 | fn adcpre(&self) -> crate::pac::adccommon::vals::Adcpre { | ||
| 79 | match self { | ||
| 80 | Prescaler::Div2 => crate::pac::adccommon::vals::Adcpre::DIV2, | ||
| 81 | Prescaler::Div4 => crate::pac::adccommon::vals::Adcpre::DIV4, | ||
| 82 | Prescaler::Div6 => crate::pac::adccommon::vals::Adcpre::DIV6, | ||
| 83 | Prescaler::Div8 => crate::pac::adccommon::vals::Adcpre::DIV8, | ||
| 84 | } | ||
| 85 | } | 68 | } |
| 86 | } | 69 | } |
| 87 | 70 | ||
| @@ -224,8 +207,8 @@ where | |||
| 224 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { | 207 | pub fn new_with_config(adc: Peri<'d, T>, config: AdcConfig) -> Self { |
| 225 | rcc::enable_and_reset::<T>(); | 208 | rcc::enable_and_reset::<T>(); |
| 226 | 209 | ||
| 227 | let presc = Prescaler::from_pclk2(T::frequency()); | 210 | let presc = from_pclk2(T::frequency()); |
| 228 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc.adcpre())); | 211 | T::common_regs().ccr().modify(|w| w.set_adcpre(presc)); |
| 229 | T::regs().cr2().modify(|reg| { | 212 | T::regs().cr2().modify(|reg| { |
| 230 | reg.set_adon(true); | 213 | reg.set_adon(true); |
| 231 | }); | 214 | }); |
diff --git a/embassy-stm32/src/adc/v3.rs b/embassy-stm32/src/adc/v3.rs index 4cce1dac3..78b497727 100644 --- a/embassy-stm32/src/adc/v3.rs +++ b/embassy-stm32/src/adc/v3.rs | |||
| @@ -11,7 +11,7 @@ pub use pac::adc::vals::{Ovsr, Ovss, Presc}; | |||
| 11 | 11 | ||
| 12 | #[allow(unused_imports)] | 12 | #[allow(unused_imports)] |
| 13 | use super::SealedAdcChannel; | 13 | use super::SealedAdcChannel; |
| 14 | use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; | 14 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 15 | use crate::adc::ConversionMode; | 15 | use crate::adc::ConversionMode; |
| 16 | use crate::{Peri, pac, rcc}; | 16 | use crate::{Peri, pac, rcc}; |
| 17 | 17 | ||
| @@ -100,21 +100,6 @@ cfg_if! { | |||
| 100 | } | 100 | } |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | /// Number of samples used for averaging. | ||
| 104 | #[derive(Copy, Clone, Debug)] | ||
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 106 | pub enum Averaging { | ||
| 107 | Disabled, | ||
| 108 | Samples2, | ||
| 109 | Samples4, | ||
| 110 | Samples8, | ||
| 111 | Samples16, | ||
| 112 | Samples32, | ||
| 113 | Samples64, | ||
| 114 | Samples128, | ||
| 115 | Samples256, | ||
| 116 | } | ||
| 117 | |||
| 118 | cfg_if! { if #[cfg(adc_g0)] { | 103 | cfg_if! { if #[cfg(adc_g0)] { |
| 119 | 104 | ||
| 120 | /// Synchronous PCLK prescaler | 105 | /// Synchronous PCLK prescaler |
| @@ -274,6 +259,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 274 | reg.set_cont(true); | 259 | reg.set_cont(true); |
| 275 | reg.set_dmacfg(match conversion_mode { | 260 | reg.set_dmacfg(match conversion_mode { |
| 276 | ConversionMode::Singular => Dmacfg::ONE_SHOT, | 261 | ConversionMode::Singular => Dmacfg::ONE_SHOT, |
| 262 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 277 | ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, | 263 | ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, |
| 278 | }); | 264 | }); |
| 279 | reg.set_dmaen(true); | 265 | reg.set_dmaen(true); |
diff --git a/embassy-stm32/src/adc/v4.rs b/embassy-stm32/src/adc/v4.rs index 43eb16fd5..804e63db6 100644 --- a/embassy-stm32/src/adc/v4.rs +++ b/embassy-stm32/src/adc/v4.rs | |||
| @@ -4,7 +4,7 @@ use pac::adc::vals::{Adcaldif, Boost}; | |||
| 4 | use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; | 4 | use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; |
| 5 | use pac::adccommon::vals::Presc; | 5 | use pac::adccommon::vals::Presc; |
| 6 | 6 | ||
| 7 | use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; | 7 | use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; |
| 8 | use crate::adc::ConversionMode; | 8 | use crate::adc::ConversionMode; |
| 9 | use crate::time::Hertz; | 9 | use crate::time::Hertz; |
| 10 | use crate::{Peri, pac, rcc}; | 10 | use crate::{Peri, pac, rcc}; |
| @@ -59,91 +59,20 @@ impl<T: Instance> super::SealedSpecialConverter<super::Vbat> for T { | |||
| 59 | const CHANNEL: u8 = 18; | 59 | const CHANNEL: u8 = 18; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | // NOTE (unused): The prescaler enum closely copies the hardware capabilities, | 62 | fn from_ker_ck(frequency: Hertz) -> Presc { |
| 63 | // but high prescaling doesn't make a lot of sense in the current implementation and is ommited. | 63 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; |
| 64 | #[allow(unused)] | 64 | match raw_prescaler { |
| 65 | enum Prescaler { | 65 | 0 => Presc::DIV1, |
| 66 | NotDivided, | 66 | 1 => Presc::DIV2, |
| 67 | DividedBy2, | 67 | 2..=3 => Presc::DIV4, |
| 68 | DividedBy4, | 68 | 4..=5 => Presc::DIV6, |
| 69 | DividedBy6, | 69 | 6..=7 => Presc::DIV8, |
| 70 | DividedBy8, | 70 | 8..=9 => Presc::DIV10, |
| 71 | DividedBy10, | 71 | 10..=11 => Presc::DIV12, |
| 72 | DividedBy12, | 72 | _ => unimplemented!(), |
| 73 | DividedBy16, | ||
| 74 | DividedBy32, | ||
| 75 | DividedBy64, | ||
| 76 | DividedBy128, | ||
| 77 | DividedBy256, | ||
| 78 | } | ||
| 79 | |||
| 80 | impl Prescaler { | ||
| 81 | fn from_ker_ck(frequency: Hertz) -> Self { | ||
| 82 | let raw_prescaler = frequency.0 / MAX_ADC_CLK_FREQ.0; | ||
| 83 | match raw_prescaler { | ||
| 84 | 0 => Self::NotDivided, | ||
| 85 | 1 => Self::DividedBy2, | ||
| 86 | 2..=3 => Self::DividedBy4, | ||
| 87 | 4..=5 => Self::DividedBy6, | ||
| 88 | 6..=7 => Self::DividedBy8, | ||
| 89 | 8..=9 => Self::DividedBy10, | ||
| 90 | 10..=11 => Self::DividedBy12, | ||
| 91 | _ => unimplemented!(), | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | fn divisor(&self) -> u32 { | ||
| 96 | match self { | ||
| 97 | Prescaler::NotDivided => 1, | ||
| 98 | Prescaler::DividedBy2 => 2, | ||
| 99 | Prescaler::DividedBy4 => 4, | ||
| 100 | Prescaler::DividedBy6 => 6, | ||
| 101 | Prescaler::DividedBy8 => 8, | ||
| 102 | Prescaler::DividedBy10 => 10, | ||
| 103 | Prescaler::DividedBy12 => 12, | ||
| 104 | Prescaler::DividedBy16 => 16, | ||
| 105 | Prescaler::DividedBy32 => 32, | ||
| 106 | Prescaler::DividedBy64 => 64, | ||
| 107 | Prescaler::DividedBy128 => 128, | ||
| 108 | Prescaler::DividedBy256 => 256, | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | fn presc(&self) -> Presc { | ||
| 113 | match self { | ||
| 114 | Prescaler::NotDivided => Presc::DIV1, | ||
| 115 | Prescaler::DividedBy2 => Presc::DIV2, | ||
| 116 | Prescaler::DividedBy4 => Presc::DIV4, | ||
| 117 | Prescaler::DividedBy6 => Presc::DIV6, | ||
| 118 | Prescaler::DividedBy8 => Presc::DIV8, | ||
| 119 | Prescaler::DividedBy10 => Presc::DIV10, | ||
| 120 | Prescaler::DividedBy12 => Presc::DIV12, | ||
| 121 | Prescaler::DividedBy16 => Presc::DIV16, | ||
| 122 | Prescaler::DividedBy32 => Presc::DIV32, | ||
| 123 | Prescaler::DividedBy64 => Presc::DIV64, | ||
| 124 | Prescaler::DividedBy128 => Presc::DIV128, | ||
| 125 | Prescaler::DividedBy256 => Presc::DIV256, | ||
| 126 | } | ||
| 127 | } | 73 | } |
| 128 | } | 74 | } |
| 129 | 75 | ||
| 130 | /// Number of samples used for averaging. | ||
| 131 | #[derive(Copy, Clone, Debug)] | ||
| 132 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 133 | pub enum Averaging { | ||
| 134 | Disabled, | ||
| 135 | Samples2, | ||
| 136 | Samples4, | ||
| 137 | Samples8, | ||
| 138 | Samples16, | ||
| 139 | Samples32, | ||
| 140 | Samples64, | ||
| 141 | Samples128, | ||
| 142 | Samples256, | ||
| 143 | Samples512, | ||
| 144 | Samples1024, | ||
| 145 | } | ||
| 146 | |||
| 147 | /// Adc configuration | 76 | /// Adc configuration |
| 148 | #[derive(Default)] | 77 | #[derive(Default)] |
| 149 | pub struct AdcConfig { | 78 | pub struct AdcConfig { |
| @@ -214,6 +143,7 @@ impl<T: Instance> super::SealedAnyInstance for T { | |||
| 214 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); | 143 | reg.set_dmngt(Dmngt::DMA_ONE_SHOT); |
| 215 | }); | 144 | }); |
| 216 | } | 145 | } |
| 146 | #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))] | ||
| 217 | _ => unreachable!(), | 147 | _ => unreachable!(), |
| 218 | } | 148 | } |
| 219 | } | 149 | } |
| @@ -309,11 +239,11 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> { | |||
| 309 | pub fn new(adc: Peri<'d, T>) -> Self { | 239 | pub fn new(adc: Peri<'d, T>) -> Self { |
| 310 | rcc::enable_and_reset::<T>(); | 240 | rcc::enable_and_reset::<T>(); |
| 311 | 241 | ||
| 312 | let prescaler = Prescaler::from_ker_ck(T::frequency()); | 242 | let prescaler = from_ker_ck(T::frequency()); |
| 313 | 243 | ||
| 314 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler.presc())); | 244 | T::common_regs().ccr().modify(|w| w.set_presc(prescaler)); |
| 315 | 245 | ||
| 316 | let frequency = Hertz(T::frequency().0 / prescaler.divisor()); | 246 | let frequency = T::frequency() / prescaler; |
| 317 | info!("ADC frequency set to {}", frequency); | 247 | info!("ADC frequency set to {}", frequency); |
| 318 | 248 | ||
| 319 | if frequency > MAX_ADC_CLK_FREQ { | 249 | if frequency > MAX_ADC_CLK_FREQ { |
diff --git a/examples/stm32c0/src/bin/adc.rs b/examples/stm32c0/src/bin/adc.rs index b52c9e7f8..ad597b63c 100644 --- a/examples/stm32c0/src/bin/adc.rs +++ b/examples/stm32c0/src/bin/adc.rs | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | use defmt::*; | 4 | use defmt::*; |
| 5 | use embassy_executor::Spawner; | 5 | use embassy_executor::Spawner; |
| 6 | use embassy_stm32::adc::vals::Scandir; | ||
| 7 | use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime}; | 6 | use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime}; |
| 8 | use embassy_stm32::peripherals::ADC1; | 7 | use embassy_stm32::peripherals::ADC1; |
| 9 | use embassy_time::Timer; | 8 | use embassy_time::Timer; |
| @@ -35,8 +34,12 @@ async fn main(_spawner: Spawner) { | |||
| 35 | blocking_vref, blocking_temp, blocing_pin0 | 34 | blocking_vref, blocking_temp, blocing_pin0 |
| 36 | ); | 35 | ); |
| 37 | 36 | ||
| 38 | let channels_seqence: [&mut AnyAdcChannel<ADC1>; 3] = [&mut vref, &mut temp, &mut pin0]; | 37 | let channels_sequence: [(&mut AnyAdcChannel<ADC1>, SampleTime); 3] = [ |
| 39 | adc.read(dma.reborrow(), channels_seqence.into_iter(), &mut read_buffer) | 38 | (&mut vref, SampleTime::CYCLES12_5), |
| 39 | (&mut temp, SampleTime::CYCLES12_5), | ||
| 40 | (&mut pin0, SampleTime::CYCLES12_5), | ||
| 41 | ]; | ||
| 42 | adc.read(dma.reborrow(), channels_sequence.into_iter(), &mut read_buffer) | ||
| 40 | .await; | 43 | .await; |
| 41 | // Values are ordered according to hardware ADC channel number! | 44 | // Values are ordered according to hardware ADC channel number! |
| 42 | info!( | 45 | info!( |
| @@ -44,15 +47,6 @@ async fn main(_spawner: Spawner) { | |||
| 44 | read_buffer[0], read_buffer[1], read_buffer[2] | 47 | read_buffer[0], read_buffer[1], read_buffer[2] |
| 45 | ); | 48 | ); |
| 46 | 49 | ||
| 47 | let hw_channel_selection: u32 = | ||
| 48 | (1 << temp.get_hw_channel()) + (1 << vref.get_hw_channel()) + (1 << pin0.get_hw_channel()); | ||
| 49 | adc.read_in_hw_order(dma.reborrow(), hw_channel_selection, Scandir::UP, &mut read_buffer) | ||
| 50 | .await; | ||
| 51 | info!( | ||
| 52 | "DMA ADC read in hardware order: vref = {}, temp = {}, pin0 = {}.", | ||
| 53 | read_buffer[2], read_buffer[1], read_buffer[0] | ||
| 54 | ); | ||
| 55 | |||
| 56 | Timer::after_millis(2000).await; | 50 | Timer::after_millis(2000).await; |
| 57 | } | 51 | } |
| 58 | } | 52 | } |
