aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-13 08:51:14 -0600
committerxoviat <[email protected]>2025-11-13 08:51:14 -0600
commitde582f7d5ed9d4903fb5f07d7816f67a907c1d47 (patch)
tree79e5335d80607abf684b1f182cfce1a949093102
parentc17d24d0cc8fedbe69b22032ea7323997ddfe4dc (diff)
adc: extract prescalers
-rw-r--r--embassy-stm32/build.rs124
-rw-r--r--embassy-stm32/src/adc/adc4.rs82
-rw-r--r--embassy-stm32/src/adc/g4.rs82
-rw-r--r--embassy-stm32/src/adc/v4.rs82
4 files changed, 113 insertions, 257 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs
index ad6743f96..67041a9e0 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" => 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..d816eea57 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, 79fn 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 {
82enum 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
97impl 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
@@ -283,11 +229,11 @@ impl<'d, T: Instance + super::AnyInstance> super::Adc<'d, T> {
283 /// Create a new ADC driver. 229 /// Create a new ADC driver.
284 pub fn new_adc4(adc: Peri<'d, T>) -> Self { 230 pub fn new_adc4(adc: Peri<'d, T>) -> Self {
285 rcc::enable_and_reset::<T>(); 231 rcc::enable_and_reset::<T>();
286 let prescaler = Prescaler::from_ker_ck(T::frequency()); 232 let prescaler = from_ker_ck(T::frequency());
287 233
288 T::regs().ccr().modify(|w| w.set_presc(prescaler.presc())); 234 T::regs().ccr().modify(|w| w.set_presc(prescaler));
289 235
290 let frequency = Hertz(T::frequency().0 / prescaler.divisor()); 236 let frequency = T::frequency() / prescaler;
291 info!("ADC4 frequency set to {}", frequency); 237 info!("ADC4 frequency set to {}", frequency);
292 238
293 if frequency > MAX_ADC_CLK_FREQ { 239 if frequency > MAX_ADC_CLK_FREQ {
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)]
33const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50); 33const MAX_ADC_CLK_FREQ: Hertz = Hertz::mhz(50);
34 34
35// NOTE (unused): The prescaler enum closely copies the hardware capabilities, 35fn 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 {
38enum 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
53impl 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/v4.rs b/embassy-stm32/src/adc/v4.rs
index 1b17b744f..5c4a1975f 100644
--- a/embassy-stm32/src/adc/v4.rs
+++ b/embassy-stm32/src/adc/v4.rs
@@ -59,71 +59,17 @@ 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, 62fn 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 {
65enum 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
80impl 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
@@ -292,11 +238,11 @@ impl<'d, T: Instance + super::AnyInstance> Adc<'d, T> {
292 pub fn new(adc: Peri<'d, T>) -> Self { 238 pub fn new(adc: Peri<'d, T>) -> 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 info!("ADC frequency set to {}", frequency); 246 info!("ADC frequency set to {}", frequency);
301 247
302 if frequency > MAX_ADC_CLK_FREQ { 248 if frequency > MAX_ADC_CLK_FREQ {