aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-11-13 17:41:44 -0600
committerxoviat <[email protected]>2025-11-13 17:41:44 -0600
commitcc1aad2cc4d2f87a177495e8352dd312c1ac331c (patch)
tree8bca5d0816882f151a87b88121e15c9e4f11f36a
parent4fb60b5991c4c98427ef23e6c011210341ba09e1 (diff)
parent578679771eafe93ccc0e8de8fc3f97a5b991b02c (diff)
Merge branch 'main' of https://github.com/embassy-rs/embassy into adc
-rw-r--r--embassy-rp/CHANGELOG.md2
-rw-r--r--embassy-rp/src/pio/instr.rs16
-rw-r--r--embassy-stm32/CHANGELOG.md5
-rw-r--r--embassy-stm32/build.rs124
-rw-r--r--embassy-stm32/src/adc/adc4.rs83
-rw-r--r--embassy-stm32/src/adc/c0.rs507
-rw-r--r--embassy-stm32/src/adc/f1.rs4
-rw-r--r--embassy-stm32/src/adc/f3.rs2
-rw-r--r--embassy-stm32/src/adc/g4.rs82
-rw-r--r--embassy-stm32/src/adc/mod.rs101
-rw-r--r--embassy-stm32/src/adc/v2.rs51
-rw-r--r--embassy-stm32/src/adc/v3.rs18
-rw-r--r--embassy-stm32/src/adc/v4.rs102
-rw-r--r--embassy-stm32/src/dsihost.rs17
-rw-r--r--embassy-stm32/src/eth/generic_phy.rs14
-rw-r--r--embassy-stm32/src/flash/c.rs131
-rw-r--r--embassy-stm32/src/flash/common.rs8
-rw-r--r--embassy-stm32/src/flash/g.rs5
-rw-r--r--embassy-stm32/src/flash/mod.rs3
-rw-r--r--embassy-stm32/src/i2c/v2.rs704
-rw-r--r--embassy-stm32/src/lib.rs14
-rw-r--r--embassy-stm32/src/opamp.rs13
-rw-r--r--examples/stm32c0/src/bin/adc.rs18
-rw-r--r--examples/stm32f0/Cargo.toml1
-rw-r--r--examples/stm32f0/src/bin/i2c_master.rs609
-rw-r--r--examples/stm32f469/src/bin/dsi_bsp.rs14
26 files changed, 1823 insertions, 825 deletions
diff --git a/embassy-rp/CHANGELOG.md b/embassy-rp/CHANGELOG.md
index 3b3cb5351..4b0d738a7 100644
--- a/embassy-rp/CHANGELOG.md
+++ b/embassy-rp/CHANGELOG.md
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8<!-- next-header --> 8<!-- next-header -->
9## Unreleased - ReleaseDate 9## Unreleased - ReleaseDate
10 10
11- Add documentation for pio `get_x` about autopush.
11- Fix several minor typos in documentation 12- Fix several minor typos in documentation
12- Add PIO SPI 13- Add PIO SPI
13- Add PIO I2S input 14- Add PIO I2S input
@@ -114,3 +115,4 @@ Small release fixing a few gnarly bugs, upgrading is strongly recommended.
114- rename the Channel trait to Slice and the PwmPin to PwmChannel 115- rename the Channel trait to Slice and the PwmPin to PwmChannel
115- i2c: Fix race condition that appears on fast repeated transfers. 116- i2c: Fix race condition that appears on fast repeated transfers.
116- Add a basic "read to break" function 117- Add a basic "read to break" function
118
diff --git a/embassy-rp/src/pio/instr.rs b/embassy-rp/src/pio/instr.rs
index b15d507de..304ddb20a 100644
--- a/embassy-rp/src/pio/instr.rs
+++ b/embassy-rp/src/pio/instr.rs
@@ -5,6 +5,10 @@ use crate::pio::{Instance, StateMachine};
5 5
6impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> { 6impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> {
7 /// Set value of scratch register X. 7 /// Set value of scratch register X.
8 ///
9 /// SAFETY: autopull enabled else it will write undefined data.
10 /// Make sure to have setup the according configuration see
11 /// [shift_out](crate::pio::Config::shift_out) and [auto_fill](crate::pio::ShiftConfig::auto_fill).
8 pub unsafe fn set_x(&mut self, value: u32) { 12 pub unsafe fn set_x(&mut self, value: u32) {
9 const OUT: u16 = InstructionOperands::OUT { 13 const OUT: u16 = InstructionOperands::OUT {
10 destination: OutDestination::X, 14 destination: OutDestination::X,
@@ -16,6 +20,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> {
16 } 20 }
17 21
18 /// Get value of scratch register X. 22 /// Get value of scratch register X.
23 ///
24 /// SAFETY: autopush enabled else it will read undefined data.
25 /// Make sure to have setup the according configurations see
26 /// [shift_in](crate::pio::Config::shift_in) and [auto_fill](crate::pio::ShiftConfig::auto_fill).
19 pub unsafe fn get_x(&mut self) -> u32 { 27 pub unsafe fn get_x(&mut self) -> u32 {
20 const IN: u16 = InstructionOperands::IN { 28 const IN: u16 = InstructionOperands::IN {
21 source: InSource::X, 29 source: InSource::X,
@@ -27,6 +35,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> {
27 } 35 }
28 36
29 /// Set value of scratch register Y. 37 /// Set value of scratch register Y.
38 ///
39 /// SAFETY: autopull enabled else it will write undefined data.
40 /// Make sure to have setup the according configuration see
41 /// [shift_out](crate::pio::Config::shift_out) and [auto_fill](crate::pio::ShiftConfig::auto_fill).
30 pub unsafe fn set_y(&mut self, value: u32) { 42 pub unsafe fn set_y(&mut self, value: u32) {
31 const OUT: u16 = InstructionOperands::OUT { 43 const OUT: u16 = InstructionOperands::OUT {
32 destination: OutDestination::Y, 44 destination: OutDestination::Y,
@@ -38,6 +50,10 @@ impl<'d, PIO: Instance, const SM: usize> StateMachine<'d, PIO, SM> {
38 } 50 }
39 51
40 /// Get value of scratch register Y. 52 /// Get value of scratch register Y.
53 ///
54 /// SAFETY: autopush enabled else it will read undefined data.
55 /// Make sure to have setup the according configurations see
56 /// [shift_in](crate::pio::Config::shift_in) and [auto_fill](crate::pio::ShiftConfig::auto_fill).
41 pub unsafe fn get_y(&mut self) -> u32 { 57 pub unsafe fn get_y(&mut self) -> u32 {
42 const IN: u16 = InstructionOperands::IN { 58 const IN: u16 = InstructionOperands::IN {
43 source: InSource::Y, 59 source: InSource::Y,
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 3431848d3..8bd930e79 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7 7
8## Unreleased - ReleaseDate 8## Unreleased - ReleaseDate
9 9
10- fix: flash erase on dual-bank STM32Gxxx
10- feat: Add support for STM32N657X0 11- feat: Add support for STM32N657X0
11- feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717)) 12- feat: timer: Add 32-bit timer support to SimplePwm waveform_up method following waveform pattern ([#4717](https://github.com/embassy-rs/embassy/pull/4717))
12- feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840)) 13- feat: Add support for injected ADC measurements for g4 ([#4840](https://github.com/embassy-rs/embassy/pull/4840))
@@ -43,7 +44,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
43- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723) 44- fix: sdmmc: don't wait for DBCKEND flag on sdmmc_v2 devices as it never fires (Fixes #4723)
44- fix: usart: fix race condition in ringbuffered usart 45- fix: usart: fix race condition in ringbuffered usart
45- feat: Add backup_sram::init() for H5 devices to access BKPSRAM 46- feat: Add backup_sram::init() for H5 devices to access BKPSRAM
46- feat: Add I2C MultiMaster (Slave) support for I2C v1 47- feat: stm32/i2c v1: Add I2C MultiMaster (Slave) support
48- feat: stm32/i2c v2: Add transaction() and blocking_transaction() methods with contract-compliant operation merging
47- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821)) 49- feat: stm32/fdcan: add ability to control automatic recovery from bus off ([#4821](https://github.com/embassy-rs/embassy/pull/4821))
48- low-power: update rtc api to allow reconfig 50- low-power: update rtc api to allow reconfig
49- adc: consolidate ringbuffer 51- adc: consolidate ringbuffer
@@ -55,6 +57,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
55- chore: Updated stm32-metapac and stm32-data dependencies 57- chore: Updated stm32-metapac and stm32-data dependencies
56- adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion 58- adc: reogranize and cleanup somewhat. require sample_time to be passed on conversion
57- fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written 59- fix: stm32/i2c v2 slave: prevent misaligned reads, error false positives, and incorrect counts of bytes read/written
60- feat: add flash support for c0 family ([#4874](https://github.com/embassy-rs/embassy/pull/4874))
58 61
59## 0.4.0 - 2025-08-26 62## 0.4.0 - 2025-08-26
60 63
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, 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
@@ -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..3bdca7edb 100644
--- a/embassy-stm32/src/adc/c0.rs
+++ b/embassy-stm32/src/adc/c0.rs
@@ -1,12 +1,10 @@
1use pac::adc::vals::Scandir;
2#[allow(unused)] 1#[allow(unused)]
3use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr}; 2use pac::adc::vals::{Adstp, Align, Ckmode, Dmacfg, Exten, Ovrmod, Ovsr};
4use pac::adccommon::vals::Presc; 3use pac::adccommon::vals::Presc;
4use stm32_metapac::adc::vals::Scandir;
5 5
6use super::{ 6use super::{Adc, Instance, Resolution, blocking_delay_us};
7 Adc, AdcChannel, AnyAdcChannel, Instance, Resolution, RxDma, SampleTime, SealedAdcChannel, blocking_delay_us, 7use crate::adc::{AnyInstance, ConversionMode};
8};
9use crate::dma::Transfer;
10use crate::time::Hertz; 8use crate::time::Hertz;
11use crate::{Peri, pac, rcc}; 9use 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)] 33fn from_ker_ck(frequency: Hertz) -> Presc {
36pub 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
51impl Prescaler { 47impl<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) {
103impl<'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
127pub 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
141impl<'d, T: Instance> Adc<'d, T> { 200impl<'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,32 +217,16 @@ 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 });
180 223
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 as u64 + 1);
184 } 227
228 T::regs().cfgr1().modify(|reg| reg.set_res(resolution));
185 229
186 fn calibrate(&mut self) {
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/f1.rs b/embassy-stm32/src/adc/f1.rs
index f6220de78..d6c6f480b 100644
--- a/embassy-stm32/src/adc/f1.rs
+++ b/embassy-stm32/src/adc/f1.rs
@@ -43,7 +43,7 @@ impl<'d, T: Instance> Adc<'d, T> {
43 43
44 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’) 44 // 11.4: Before starting a calibration, the ADC must have been in power-on state (ADON bit = ‘1’)
45 // for at least two ADC clock cycles. 45 // for at least two ADC clock cycles.
46 blocking_delay_us((1_000_000 * 2) / Self::freq().0 + 1); 46 blocking_delay_us((1_000_000 * 2) / Self::freq().0 as u64 + 1);
47 47
48 // Reset calibration 48 // Reset calibration
49 T::regs().cr2().modify(|reg| reg.set_rstcal(true)); 49 T::regs().cr2().modify(|reg| reg.set_rstcal(true));
@@ -58,7 +58,7 @@ impl<'d, T: Instance> Adc<'d, T> {
58 } 58 }
59 59
60 // One cycle after calibration 60 // One cycle after calibration
61 blocking_delay_us((1_000_000 * 1) / Self::freq().0 + 1); 61 blocking_delay_us((1_000_000 * 1) / Self::freq().0 as u64 + 1);
62 62
63 T::Interrupt::unpend(); 63 T::Interrupt::unpend();
64 unsafe { T::Interrupt::enable() }; 64 unsafe { T::Interrupt::enable() };
diff --git a/embassy-stm32/src/adc/f3.rs b/embassy-stm32/src/adc/f3.rs
index 4a77f3c5b..29bfdac97 100644
--- a/embassy-stm32/src/adc/f3.rs
+++ b/embassy-stm32/src/adc/f3.rs
@@ -62,7 +62,7 @@ impl<'d, T: Instance> Adc<'d, T> {
62 while T::regs().cr().read().adcal() {} 62 while T::regs().cr().read().adcal() {}
63 63
64 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223). 64 // Wait more than 4 clock cycles after adcal is cleared (RM0364 p. 223).
65 blocking_delay_us((1_000_000 * 4) / Self::freq().0 + 1); 65 blocking_delay_us((1_000_000 * 4) / Self::freq().0 as u64 + 1);
66 66
67 // Enable the adc 67 // Enable the adc
68 T::regs().cr().modify(|w| w.set_aden(true)); 68 T::regs().cr().modify(|w| w.set_aden(true));
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/mod.rs b/embassy-stm32/src/adc/mod.rs
index 856c2e61e..5ec08a22d 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -35,6 +35,8 @@ pub use ringbuffered::RingBufferedAdc;
35#[path = "adc4.rs"] 35#[path = "adc4.rs"]
36pub mod adc4; 36pub mod adc4;
37 37
38#[allow(unused)]
39pub(self) use crate::block_for_us as blocking_delay_us;
38pub use crate::pac::adc::vals; 40pub use crate::pac::adc::vals;
39#[cfg(not(any(adc_f1, adc_f3v3)))] 41#[cfg(not(any(adc_f1, adc_f3v3)))]
40pub use crate::pac::adc::vals::Res as Resolution; 42pub use crate::pac::adc::vals::Res as Resolution;
@@ -88,31 +90,37 @@ pub(crate) trait SealedAdcChannel<T> {
88} 90}
89 91
90// Temporary patch for ADCs that have not implemented the standard iface yet 92// 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)))] 93#[cfg(any(adc_v1, adc_l0, adc_f1, adc_f3v1, adc_f3v2, adc_f3v3, adc_v1))]
92trait_set::trait_set! { 94trait_set::trait_set! {
93 pub trait AnyInstance = Instance; 95 pub trait AnyInstance = Instance;
94} 96}
95 97
96#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 98#[cfg(any(
97#[allow(dead_code)] 99 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
100))]
98pub trait BasicAnyInstance { 101pub trait BasicAnyInstance {
99 type SampleTime; 102 type SampleTime;
100} 103}
101 104
102#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 105#[cfg(any(
103#[allow(dead_code)] 106 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
107))]
104pub(self) trait SealedAnyInstance: BasicAnyInstance { 108pub(self) trait SealedAnyInstance: BasicAnyInstance {
105 fn enable(); 109 fn enable();
106 fn start(); 110 fn start();
107 fn stop(); 111 fn stop();
108 fn convert() -> u16; 112 fn convert() -> u16;
109 fn configure_dma(conversion_mode: ConversionMode); 113 fn configure_dma(conversion_mode: ConversionMode);
114 #[cfg(not(adc_c0))]
110 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>); 115 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>);
116 #[cfg(adc_c0)]
117 fn configure_sequence(sequence: impl ExactSizeIterator<Item = ((u8, bool), Self::SampleTime)>, blocking: bool);
118 #[allow(dead_code)]
111 fn dr() -> *mut u16; 119 fn dr() -> *mut u16;
112} 120}
113 121
114// On chips without ADC4, AnyInstance is an Instance 122// 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))] 123#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_g4, adc_c0))]
116#[allow(private_bounds)] 124#[allow(private_bounds)]
117pub trait AnyInstance: SealedAnyInstance + Instance {} 125pub trait AnyInstance: SealedAnyInstance + Instance {}
118 126
@@ -122,44 +130,53 @@ pub trait AnyInstance: SealedAnyInstance + Instance {}
122pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {} 130pub trait AnyInstance: SealedAnyInstance + crate::PeripheralType + crate::rcc::RccPeripheral {}
123 131
124// Implement AnyInstance automatically for SealedAnyInstance 132// 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))] 133#[cfg(any(
134 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
135))]
126impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T { 136impl<T: SealedAnyInstance + Instance> BasicAnyInstance for T {
127 type SampleTime = SampleTime; 137 type SampleTime = SampleTime;
128} 138}
129 139
130#[cfg(any(adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4))] 140#[cfg(any(
141 adc_v2, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_g4, adc_c0
142))]
131impl<T: SealedAnyInstance + Instance> AnyInstance for T {} 143impl<T: SealedAnyInstance + Instance> AnyInstance for T {}
132 144
133/// Performs a busy-wait delay for a specified number of microseconds. 145#[cfg(any(adc_c0, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5))]
134#[allow(unused)] 146/// Number of samples used for averaging.
135pub(crate) fn blocking_delay_us(us: u32) { 147#[derive(Copy, Clone, Debug)]
136 cfg_if::cfg_if! { 148#[cfg_attr(feature = "defmt", derive(defmt::Format))]
137 // this does strange things on stm32wlx in low power mode depending on exactly when it's called 149pub enum Averaging {
138 // as in sometimes 15 us (1 tick) would take > 20 seconds. 150 Disabled,
139 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] { 151 Samples2,
140 let duration = embassy_time::Duration::from_micros(us as u64); 152 Samples4,
141 embassy_time::block_for(duration); 153 Samples8,
142 } else { 154 Samples16,
143 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64; 155 Samples32,
144 let us = us as u64; 156 Samples64,
145 let cycles = freq * us / 1_000_000; 157 Samples128,
146 cortex_m::asm::delay(cycles as u32); 158 Samples256,
147 } 159 #[cfg(any(adc_c0, adc_v4, adc_u5))]
148 } 160 Samples512,
161 #[cfg(any(adc_c0, adc_v4, adc_u5))]
162 Samples1024,
149} 163}
150 164
151#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 165#[cfg(any(
152#[allow(dead_code)] 166 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0
167))]
153pub(crate) enum ConversionMode { 168pub(crate) enum ConversionMode {
154 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 169 // Should match the cfg on "read" below
170 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba, adc_c0))]
155 Singular, 171 Singular,
156 #[allow(dead_code)] 172 // Should match the cfg on "into_ring_buffered" below
173 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
157 Repeated(RegularConversionMode), 174 Repeated(RegularConversionMode),
158} 175}
159 176
160#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 177// Should match the cfg on "into_ring_buffered" below
178#[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
161// Conversion mode for regular ADC channels 179// Conversion mode for regular ADC channels
162#[allow(dead_code)]
163#[derive(Copy, Clone)] 180#[derive(Copy, Clone)]
164pub enum RegularConversionMode { 181pub enum RegularConversionMode {
165 // Samples as fast as possible 182 // Samples as fast as possible
@@ -170,7 +187,9 @@ pub enum RegularConversionMode {
170} 187}
171 188
172impl<'d, T: AnyInstance> Adc<'d, T> { 189impl<'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))] 190 #[cfg(any(
191 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0
192 ))]
174 /// Read an ADC pin. 193 /// Read an ADC pin.
175 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { 194 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))] 195 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))]
@@ -178,12 +197,18 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
178 197
179 #[cfg(not(adc_v4))] 198 #[cfg(not(adc_v4))]
180 T::enable(); 199 T::enable();
200 #[cfg(not(adc_c0))]
181 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter()); 201 T::configure_sequence([((channel.channel(), channel.is_differential()), sample_time)].into_iter());
202 #[cfg(adc_c0)]
203 T::configure_sequence(
204 [((channel.channel(), channel.is_differential()), sample_time)].into_iter(),
205 true,
206 );
182 207
183 T::convert() 208 T::convert()
184 } 209 }
185 210
186 #[cfg(any(adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_v4, adc_u5, adc_wba))] 211 #[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. 212 /// Read one or multiple ADC regular channels using DMA.
188 /// 213 ///
189 /// `sequence` iterator and `readings` must have the same length. 214 /// `sequence` iterator and `readings` must have the same length.
@@ -212,6 +237,11 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
212 /// 237 ///
213 /// Note: This is not very efficient as the ADC needs to be reconfigured for each read. Use 238 /// 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` 239 /// `into_ring_buffered`, `into_ring_buffered_and_injected`
240 ///
241 /// In STM32C0, channels bigger than 14 cannot be read using sequencer, so you have to use
242 /// either blocking reads or use the mechanism to read in HW order (CHSELRMOD=0).
243 ///
244 /// In addtion, on STM320, this method will panic if the channels are not passed in order
215 pub async fn read( 245 pub async fn read(
216 &mut self, 246 &mut self,
217 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>, 247 rx_dma: embassy_hal_internal::Peri<'_, impl RxDma<T>>,
@@ -232,8 +262,15 @@ impl<'d, T: AnyInstance> Adc<'d, T> {
232 T::stop(); 262 T::stop();
233 T::enable(); 263 T::enable();
234 264
265 #[cfg(not(adc_c0))]
266 T::configure_sequence(
267 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
268 );
269
270 #[cfg(adc_c0)]
235 T::configure_sequence( 271 T::configure_sequence(
236 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)), 272 sequence.map(|(channel, sample_time)| ((channel.channel, channel.is_differential), sample_time)),
273 false,
237 ); 274 );
238 275
239 T::configure_dma(ConversionMode::Singular); 276 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};
3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us}; 3use super::{ConversionMode, Temperature, Vbat, VrefInt, blocking_delay_us};
4use crate::adc::{Adc, Instance, Resolution, SampleTime}; 4use crate::adc::{Adc, Instance, Resolution, SampleTime};
5use crate::pac::adc::vals; 5use crate::pac::adc::vals;
6pub use crate::pac::adccommon::vals::Adcpre;
6use crate::time::Hertz; 7use crate::time::Hertz;
7use crate::{Peri, rcc}; 8use crate::{Peri, rcc};
8 9
@@ -50,38 +51,20 @@ impl Temperature {
50 } 51 }
51} 52}
52 53
53enum Prescaler { 54fn 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);
60impl 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 ba1afbe05..288bd77ce 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)]
13use super::SealedAdcChannel; 13use super::SealedAdcChannel;
14use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; 14use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
15use crate::adc::ConversionMode; 15use crate::adc::ConversionMode;
16use crate::{Peri, pac, rcc}; 16use 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))]
106pub enum Averaging {
107 Disabled,
108 Samples2,
109 Samples4,
110 Samples8,
111 Samples16,
112 Samples32,
113 Samples64,
114 Samples128,
115 Samples256,
116}
117
118cfg_if! { if #[cfg(adc_g0)] { 103cfg_if! { if #[cfg(adc_g0)] {
119 104
120/// Synchronous PCLK prescaler 105/// Synchronous PCLK prescaler
@@ -267,6 +252,7 @@ impl<T: Instance> super::SealedAnyInstance for T {
267 reg.set_cont(true); 252 reg.set_cont(true);
268 reg.set_dmacfg(match conversion_mode { 253 reg.set_dmacfg(match conversion_mode {
269 ConversionMode::Singular => Dmacfg::ONE_SHOT, 254 ConversionMode::Singular => Dmacfg::ONE_SHOT,
255 #[cfg(any(adc_v2, adc_g4, adc_v3, adc_g0, adc_u0))]
270 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR, 256 ConversionMode::Repeated(_) => Dmacfg::CIRCULAR,
271 }); 257 });
272 reg.set_dmaen(true); 258 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};
4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel}; 4use pac::adc::vals::{Adstp, Difsel, Dmngt, Exten, Pcsel};
5use pac::adccommon::vals::Presc; 5use pac::adccommon::vals::Presc;
6 6
7use super::{Adc, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us}; 7use super::{Adc, Averaging, Instance, Resolution, SampleTime, Temperature, Vbat, VrefInt, blocking_delay_us};
8use crate::adc::ConversionMode; 8use crate::adc::ConversionMode;
9use crate::time::Hertz; 9use crate::time::Hertz;
10use crate::{Peri, pac, rcc}; 10use 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, 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
130/// Number of samples used for averaging.
131#[derive(Copy, Clone, Debug)]
132#[cfg_attr(feature = "defmt", derive(defmt::Format))]
133pub 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)]
149pub struct AdcConfig { 78pub 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/embassy-stm32/src/dsihost.rs b/embassy-stm32/src/dsihost.rs
index 59a2cbcdb..b8945820c 100644
--- a/embassy-stm32/src/dsihost.rs
+++ b/embassy-stm32/src/dsihost.rs
@@ -5,18 +5,11 @@ use core::marker::PhantomData;
5use embassy_hal_internal::PeripheralType; 5use embassy_hal_internal::PeripheralType;
6 6
7//use crate::gpio::{AnyPin, SealedPin}; 7//use crate::gpio::{AnyPin, SealedPin};
8use crate::block_for_us;
8use crate::gpio::{AfType, AnyPin, OutputType, Speed}; 9use crate::gpio::{AfType, AnyPin, OutputType, Speed};
9use crate::rcc::{self, RccPeripheral}; 10use crate::rcc::{self, RccPeripheral};
10use crate::{Peri, peripherals}; 11use crate::{Peri, peripherals};
11 12
12/// Performs a busy-wait delay for a specified number of microseconds.
13pub fn blocking_delay_ms(ms: u32) {
14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
18}
19
20/// PacketTypes extracted from CubeMX 13/// PacketTypes extracted from CubeMX
21#[repr(u8)] 14#[repr(u8)]
22#[allow(dead_code)] 15#[allow(dead_code)]
@@ -334,7 +327,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
334 if T::regs().gpsr().read().cmdfe() { 327 if T::regs().gpsr().read().cmdfe() {
335 return Ok(()); 328 return Ok(());
336 } 329 }
337 blocking_delay_ms(1); 330 block_for_us(1_000);
338 } 331 }
339 Err(Error::FifoTimeout) 332 Err(Error::FifoTimeout)
340 } 333 }
@@ -345,7 +338,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
345 if !T::regs().gpsr().read().cmdff() { 338 if !T::regs().gpsr().read().cmdff() {
346 return Ok(()); 339 return Ok(());
347 } 340 }
348 blocking_delay_ms(1); 341 block_for_us(1_000);
349 } 342 }
350 Err(Error::FifoTimeout) 343 Err(Error::FifoTimeout)
351 } 344 }
@@ -356,7 +349,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
356 if !self.read_busy() { 349 if !self.read_busy() {
357 return Ok(()); 350 return Ok(());
358 } 351 }
359 blocking_delay_ms(1); 352 block_for_us(1_000);
360 } 353 }
361 Err(Error::ReadTimeout) 354 Err(Error::ReadTimeout)
362 } 355 }
@@ -367,7 +360,7 @@ impl<'d, T: Instance> DsiHost<'d, T> {
367 if !T::regs().gpsr().read().prdfe() { 360 if !T::regs().gpsr().read().prdfe() {
368 return Ok(()); 361 return Ok(());
369 } 362 }
370 blocking_delay_ms(1); 363 block_for_us(1_000);
371 } 364 }
372 Err(Error::FifoTimeout) 365 Err(Error::FifoTimeout)
373 } 366 }
diff --git a/embassy-stm32/src/eth/generic_phy.rs b/embassy-stm32/src/eth/generic_phy.rs
index 774beef80..947874d7f 100644
--- a/embassy-stm32/src/eth/generic_phy.rs
+++ b/embassy-stm32/src/eth/generic_phy.rs
@@ -8,6 +8,7 @@ use embassy_time::{Duration, Timer};
8use futures_util::FutureExt; 8use futures_util::FutureExt;
9 9
10use super::{Phy, StationManagement}; 10use super::{Phy, StationManagement};
11use crate::block_for_us as blocking_delay_us;
11 12
12#[allow(dead_code)] 13#[allow(dead_code)]
13mod phy_consts { 14mod phy_consts {
@@ -76,19 +77,6 @@ impl GenericPhy {
76 } 77 }
77} 78}
78 79
79// TODO: Factor out to shared functionality
80fn blocking_delay_us(us: u32) {
81 #[cfg(feature = "time")]
82 embassy_time::block_for(Duration::from_micros(us as u64));
83 #[cfg(not(feature = "time"))]
84 {
85 let freq = unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 as u64;
86 let us = us as u64;
87 let cycles = freq * us / 1_000_000;
88 cortex_m::asm::delay(cycles as u32);
89 }
90}
91
92impl Phy for GenericPhy { 80impl Phy for GenericPhy {
93 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) { 81 fn phy_reset<S: StationManagement>(&mut self, sm: &mut S) {
94 // Detect SMI address 82 // Detect SMI address
diff --git a/embassy-stm32/src/flash/c.rs b/embassy-stm32/src/flash/c.rs
new file mode 100644
index 000000000..0ad1002b0
--- /dev/null
+++ b/embassy-stm32/src/flash/c.rs
@@ -0,0 +1,131 @@
1use core::ptr::write_volatile;
2use core::sync::atomic::{Ordering, fence};
3
4use cortex_m::interrupt;
5
6use super::{FlashSector, WRITE_SIZE};
7use crate::flash::Error;
8use crate::pac;
9
10pub(crate) unsafe fn lock() {
11 pac::FLASH.cr().modify(|w| w.set_lock(true));
12}
13pub(crate) unsafe fn unlock() {
14 // Wait, while the memory interface is busy.
15 wait_busy();
16
17 // Unlock flash
18 if pac::FLASH.cr().read().lock() {
19 pac::FLASH.keyr().write_value(0x4567_0123);
20 pac::FLASH.keyr().write_value(0xCDEF_89AB);
21 }
22}
23
24pub(crate) unsafe fn enable_blocking_write() {
25 assert_eq!(0, WRITE_SIZE % 4);
26 pac::FLASH.cr().write(|w| w.set_pg(true));
27}
28
29pub(crate) unsafe fn disable_blocking_write() {
30 pac::FLASH.cr().write(|w| w.set_pg(false));
31}
32
33pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> {
34 let mut address = start_address;
35 for val in buf.chunks(4) {
36 write_volatile(address as *mut u32, u32::from_le_bytes(unwrap!(val.try_into())));
37 address += val.len() as u32;
38
39 // prevents parallelism errors
40 fence(Ordering::SeqCst);
41 }
42
43 wait_ready_blocking()
44}
45
46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
47 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
48
49 #[cfg(feature = "defmt")]
50 defmt::trace!(
51 "STM32C0 Erase: addr=0x{:08x}, idx={}, erase_size={}",
52 sector.start,
53 idx,
54 super::BANK1_REGION.erase_size
55 );
56
57 wait_busy();
58 clear_all_err();
59
60 // Explicitly unlock before erase
61 unlock();
62
63 interrupt::free(|_| {
64 #[cfg(feature = "defmt")]
65 {
66 let cr_before = pac::FLASH.cr().read();
67 defmt::trace!("FLASH_CR before: 0x{:08x}", cr_before.0);
68 }
69
70 pac::FLASH.cr().modify(|w| {
71 w.set_per(true);
72 w.set_pnb(idx as u8);
73 w.set_strt(true);
74 });
75
76 #[cfg(feature = "defmt")]
77 {
78 let cr_after = pac::FLASH.cr().read();
79 defmt::trace!(
80 "FLASH_CR after: 0x{:08x}, PER={}, PNB={}, STRT={}",
81 cr_after.0,
82 cr_after.per(),
83 cr_after.pnb(),
84 cr_after.strt()
85 );
86 }
87 });
88
89 let ret: Result<(), Error> = wait_ready_blocking();
90
91 // Clear erase bit
92 pac::FLASH.cr().modify(|w| w.set_per(false));
93
94 // Explicitly lock after erase
95 lock();
96
97 // Extra wait to ensure operation completes
98 wait_busy();
99
100 ret
101}
102
103pub(crate) unsafe fn wait_ready_blocking() -> Result<(), Error> {
104 while pac::FLASH.sr().read().bsy() {}
105
106 let sr = pac::FLASH.sr().read();
107
108 if sr.progerr() {
109 return Err(Error::Prog);
110 }
111
112 if sr.wrperr() {
113 return Err(Error::Protected);
114 }
115
116 if sr.pgaerr() {
117 return Err(Error::Unaligned);
118 }
119
120 Ok(())
121}
122
123pub(crate) unsafe fn clear_all_err() {
124 // read and write back the same value.
125 // This clears all "write 1 to clear" bits.
126 pac::FLASH.sr().modify(|_| {});
127}
128
129fn wait_busy() {
130 while pac::FLASH.sr().read().bsy() {}
131}
diff --git a/embassy-stm32/src/flash/common.rs b/embassy-stm32/src/flash/common.rs
index b595938a6..60d00e766 100644
--- a/embassy-stm32/src/flash/common.rs
+++ b/embassy-stm32/src/flash/common.rs
@@ -102,7 +102,13 @@ pub(super) unsafe fn blocking_write(
102 } 102 }
103 103
104 let mut address = base + offset; 104 let mut address = base + offset;
105 trace!("Writing {} bytes at 0x{:x}", bytes.len(), address); 105 trace!(
106 "Writing {} bytes at 0x{:x} (base=0x{:x}, offset=0x{:x})",
107 bytes.len(),
108 address,
109 base,
110 offset
111 );
106 112
107 for chunk in bytes.chunks(WRITE_SIZE) { 113 for chunk in bytes.chunks(WRITE_SIZE) {
108 write_chunk(address, chunk)?; 114 write_chunk(address, chunk)?;
diff --git a/embassy-stm32/src/flash/g.rs b/embassy-stm32/src/flash/g.rs
index d026541a4..d7ba2f571 100644
--- a/embassy-stm32/src/flash/g.rs
+++ b/embassy-stm32/src/flash/g.rs
@@ -44,7 +44,6 @@ pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE])
44} 44}
45 45
46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { 46pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> {
47 let idx = (sector.start - super::FLASH_BASE as u32) / super::BANK1_REGION.erase_size as u32;
48 wait_busy(); 47 wait_busy();
49 clear_all_err(); 48 clear_all_err();
50 49
@@ -54,9 +53,9 @@ pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), E
54 #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))] 53 #[cfg(any(flash_g0x0, flash_g0x1, flash_g4c3))]
55 w.set_bker(sector.bank == crate::flash::FlashBank::Bank2); 54 w.set_bker(sector.bank == crate::flash::FlashBank::Bank2);
56 #[cfg(flash_g0x0)] 55 #[cfg(flash_g0x0)]
57 w.set_pnb(idx as u16); 56 w.set_pnb(sector.index_in_bank as u16);
58 #[cfg(not(flash_g0x0))] 57 #[cfg(not(flash_g0x0))]
59 w.set_pnb(idx as u8); 58 w.set_pnb(sector.index_in_bank as u8);
60 w.set_strt(true); 59 w.set_strt(true);
61 }); 60 });
62 }); 61 });
diff --git a/embassy-stm32/src/flash/mod.rs b/embassy-stm32/src/flash/mod.rs
index 3e74d857a..39cd9b3a9 100644
--- a/embassy-stm32/src/flash/mod.rs
+++ b/embassy-stm32/src/flash/mod.rs
@@ -99,6 +99,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is
99#[cfg_attr(flash_f4, path = "f4.rs")] 99#[cfg_attr(flash_f4, path = "f4.rs")]
100#[cfg_attr(flash_f7, path = "f7.rs")] 100#[cfg_attr(flash_f7, path = "f7.rs")]
101#[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")] 101#[cfg_attr(any(flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4), path = "g.rs")]
102#[cfg_attr(flash_c0, path = "c.rs")]
102#[cfg_attr(flash_h7, path = "h7.rs")] 103#[cfg_attr(flash_h7, path = "h7.rs")]
103#[cfg_attr(flash_h7ab, path = "h7.rs")] 104#[cfg_attr(flash_h7ab, path = "h7.rs")]
104#[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")] 105#[cfg_attr(any(flash_u5, flash_wba), path = "u5.rs")]
@@ -108,7 +109,7 @@ compile_error!("The 'eeprom' cfg is enabled for a non-L0/L1 chip family. This is
108#[cfg_attr( 109#[cfg_attr(
109 not(any( 110 not(any(
110 flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4, 111 flash_l0, flash_l1, flash_l4, flash_l5, flash_wl, flash_wb, flash_f0, flash_f1, flash_f2, flash_f3, flash_f4,
111 flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_h7, flash_h7ab, flash_u5, 112 flash_f7, flash_g0x0, flash_g0x1, flash_g4c2, flash_g4c3, flash_g4c4, flash_c0, flash_h7, flash_h7ab, flash_u5,
112 flash_wba, flash_h50, flash_u0, flash_h5, 113 flash_wba, flash_h50, flash_u0, flash_h5,
113 )), 114 )),
114 path = "other.rs" 115 path = "other.rs"
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index 4527e55b9..61e550ad4 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -98,6 +98,27 @@ pub(crate) unsafe fn on_interrupt<T: Instance>() {
98} 98}
99 99
100impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> { 100impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
101 #[inline]
102 fn to_reload(reload: bool) -> i2c::vals::Reload {
103 if reload {
104 i2c::vals::Reload::NOT_COMPLETED
105 } else {
106 i2c::vals::Reload::COMPLETED
107 }
108 }
109
110 /// Calculate total bytes in a group of operations
111 #[inline]
112 fn total_operation_bytes(operations: &[Operation<'_>]) -> usize {
113 operations
114 .iter()
115 .map(|op| match op {
116 Operation::Write(buf) => buf.len(),
117 Operation::Read(buf) => buf.len(),
118 })
119 .sum()
120 }
121
101 pub(crate) fn init(&mut self, config: Config) { 122 pub(crate) fn init(&mut self, config: Config) {
102 self.info.regs.cr1().modify(|reg| { 123 self.info.regs.cr1().modify(|reg| {
103 reg.set_pe(false); 124 reg.set_pe(false);
@@ -147,12 +168,6 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
147 // `buffer`. The START bit can be set even if the bus 168 // `buffer`. The START bit can be set even if the bus
148 // is BUSY or I2C is in slave mode. 169 // is BUSY or I2C is in slave mode.
149 170
150 let reload = if reload {
151 i2c::vals::Reload::NOT_COMPLETED
152 } else {
153 i2c::vals::Reload::COMPLETED
154 };
155
156 info.regs.cr2().modify(|w| { 171 info.regs.cr2().modify(|w| {
157 w.set_sadd(address.addr() << 1); 172 w.set_sadd(address.addr() << 1);
158 w.set_add10(address.add_mode()); 173 w.set_add10(address.add_mode());
@@ -160,7 +175,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
160 w.set_nbytes(length as u8); 175 w.set_nbytes(length as u8);
161 w.set_start(true); 176 w.set_start(true);
162 w.set_autoend(stop.autoend()); 177 w.set_autoend(stop.autoend());
163 w.set_reload(reload); 178 w.set_reload(Self::to_reload(reload));
164 }); 179 });
165 180
166 Ok(()) 181 Ok(())
@@ -172,28 +187,25 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
172 length: usize, 187 length: usize,
173 stop: Stop, 188 stop: Stop,
174 reload: bool, 189 reload: bool,
190 restart: bool,
175 timeout: Timeout, 191 timeout: Timeout,
176 ) -> Result<(), Error> { 192 ) -> Result<(), Error> {
177 assert!(length < 256); 193 assert!(length < 256);
178 194
179 // Wait for any previous address sequence to end 195 if !restart {
180 // automatically. This could be up to 50% of a bus 196 // Wait for any previous address sequence to end
181 // cycle (ie. up to 0.5/freq) 197 // automatically. This could be up to 50% of a bus
182 while info.regs.cr2().read().start() { 198 // cycle (ie. up to 0.5/freq)
183 timeout.check()?; 199 while info.regs.cr2().read().start() {
184 } 200 timeout.check()?;
201 }
185 202
186 // Wait for the bus to be free 203 // Wait for the bus to be free
187 while info.regs.isr().read().busy() { 204 while info.regs.isr().read().busy() {
188 timeout.check()?; 205 timeout.check()?;
206 }
189 } 207 }
190 208
191 let reload = if reload {
192 i2c::vals::Reload::NOT_COMPLETED
193 } else {
194 i2c::vals::Reload::COMPLETED
195 };
196
197 // Set START and prepare to send `bytes`. The 209 // Set START and prepare to send `bytes`. The
198 // START bit can be set even if the bus is BUSY or 210 // START bit can be set even if the bus is BUSY or
199 // I2C is in slave mode. 211 // I2C is in slave mode.
@@ -204,28 +216,36 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
204 w.set_nbytes(length as u8); 216 w.set_nbytes(length as u8);
205 w.set_start(true); 217 w.set_start(true);
206 w.set_autoend(stop.autoend()); 218 w.set_autoend(stop.autoend());
207 w.set_reload(reload); 219 w.set_reload(Self::to_reload(reload));
208 }); 220 });
209 221
210 Ok(()) 222 Ok(())
211 } 223 }
212 224
213 fn reload(info: &'static Info, length: usize, will_reload: bool, timeout: Timeout) -> Result<(), Error> { 225 fn reload(
226 info: &'static Info,
227 length: usize,
228 will_reload: bool,
229 stop: Stop,
230 timeout: Timeout,
231 ) -> Result<(), Error> {
214 assert!(length < 256 && length > 0); 232 assert!(length < 256 && length > 0);
215 233
216 while !info.regs.isr().read().tcr() { 234 // Wait for either TCR (Transfer Complete Reload) or TC (Transfer Complete)
235 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
236 // Both indicate the peripheral is ready for the next transfer
237 loop {
238 let isr = info.regs.isr().read();
239 if isr.tcr() || isr.tc() {
240 break;
241 }
217 timeout.check()?; 242 timeout.check()?;
218 } 243 }
219 244
220 let will_reload = if will_reload {
221 i2c::vals::Reload::NOT_COMPLETED
222 } else {
223 i2c::vals::Reload::COMPLETED
224 };
225
226 info.regs.cr2().modify(|w| { 245 info.regs.cr2().modify(|w| {
227 w.set_nbytes(length as u8); 246 w.set_nbytes(length as u8);
228 w.set_reload(will_reload); 247 w.set_reload(Self::to_reload(will_reload));
248 w.set_autoend(stop.autoend());
229 }); 249 });
230 250
231 Ok(()) 251 Ok(())
@@ -369,7 +389,9 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
369 loop { 389 loop {
370 let isr = self.info.regs.isr().read(); 390 let isr = self.info.regs.isr().read();
371 self.error_occurred(&isr, timeout)?; 391 self.error_occurred(&isr, timeout)?;
372 if isr.tc() { 392 // Wait for either TC or TCR - both indicate transfer completion
393 // TCR occurs when RELOAD=1, TC occurs when RELOAD=0
394 if isr.tc() || isr.tcr() {
373 return Ok(()); 395 return Ok(());
374 } 396 }
375 timeout.check()?; 397 timeout.check()?;
@@ -396,14 +418,20 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
396 address, 418 address,
397 read.len().min(255), 419 read.len().min(255),
398 Stop::Automatic, 420 Stop::Automatic,
399 last_chunk_idx != 0, 421 last_chunk_idx != 0, // reload
400 restart, 422 restart,
401 timeout, 423 timeout,
402 )?; 424 )?;
403 425
404 for (number, chunk) in read.chunks_mut(255).enumerate() { 426 for (number, chunk) in read.chunks_mut(255).enumerate() {
405 if number != 0 { 427 if number != 0 {
406 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 428 Self::reload(
429 self.info,
430 chunk.len(),
431 number != last_chunk_idx,
432 Stop::Automatic,
433 timeout,
434 )?;
407 } 435 }
408 436
409 for byte in chunk { 437 for byte in chunk {
@@ -441,6 +469,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
441 write.len().min(255), 469 write.len().min(255),
442 Stop::Software, 470 Stop::Software,
443 last_chunk_idx != 0, 471 last_chunk_idx != 0,
472 false, // restart
444 timeout, 473 timeout,
445 ) { 474 ) {
446 if send_stop { 475 if send_stop {
@@ -451,7 +480,13 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
451 480
452 for (number, chunk) in write.chunks(255).enumerate() { 481 for (number, chunk) in write.chunks(255).enumerate() {
453 if number != 0 { 482 if number != 0 {
454 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 483 Self::reload(
484 self.info,
485 chunk.len(),
486 number != last_chunk_idx,
487 Stop::Software,
488 timeout,
489 )?;
455 } 490 }
456 491
457 for byte in chunk { 492 for byte in chunk {
@@ -507,9 +542,215 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
507 /// 542 ///
508 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction 543 /// [transaction contract]: embedded_hal_1::i2c::I2c::transaction
509 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 544 pub fn blocking_transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
510 let _ = addr; 545 if operations.is_empty() {
511 let _ = operations; 546 return Err(Error::ZeroLengthTransfer);
512 todo!() 547 }
548
549 let address = addr.into();
550 let timeout = self.timeout();
551
552 // Group consecutive operations of the same type
553 let mut op_idx = 0;
554 let mut is_first_group = true;
555
556 while op_idx < operations.len() {
557 // Determine the type of current group and find all consecutive operations of same type
558 let is_read = matches!(operations[op_idx], Operation::Read(_));
559 let group_start = op_idx;
560
561 // Find end of this group (consecutive operations of same type)
562 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
563 op_idx += 1;
564 }
565 let group_end = op_idx;
566 let is_last_group = op_idx >= operations.len();
567
568 // Execute this group of operations
569 if is_read {
570 self.execute_read_group(
571 address,
572 &mut operations[group_start..group_end],
573 is_first_group,
574 is_last_group,
575 timeout,
576 )?;
577 } else {
578 self.execute_write_group(
579 address,
580 &operations[group_start..group_end],
581 is_first_group,
582 is_last_group,
583 timeout,
584 )?;
585 }
586
587 is_first_group = false;
588 }
589
590 Ok(())
591 }
592
593 fn execute_write_group(
594 &mut self,
595 address: Address,
596 operations: &[Operation<'_>],
597 is_first_group: bool,
598 is_last_group: bool,
599 timeout: Timeout,
600 ) -> Result<(), Error> {
601 // Calculate total bytes across all operations in this group
602 let total_bytes = Self::total_operation_bytes(operations);
603
604 if total_bytes == 0 {
605 // Handle empty write group - just send address
606 if is_first_group {
607 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
608 }
609 if is_last_group {
610 self.master_stop();
611 }
612 return Ok(());
613 }
614
615 let mut total_remaining = total_bytes;
616 let mut first_chunk = true;
617
618 for operation in operations {
619 if let Operation::Write(buffer) = operation {
620 for chunk in buffer.chunks(255) {
621 let chunk_len = chunk.len();
622 total_remaining -= chunk_len;
623 let is_last_chunk = total_remaining == 0;
624 let will_reload = !is_last_chunk;
625
626 if first_chunk {
627 // First chunk: initiate transfer
628 // If not first group, use RESTART instead of START
629 Self::master_write(
630 self.info,
631 address,
632 chunk_len,
633 Stop::Software,
634 will_reload,
635 !is_first_group,
636 timeout,
637 )?;
638 first_chunk = false;
639 } else {
640 // Subsequent chunks: use reload
641 // Always use Software stop for writes
642 Self::reload(self.info, chunk_len, will_reload, Stop::Software, timeout)?;
643 }
644
645 // Send data bytes
646 for byte in chunk {
647 self.wait_txis(timeout)?;
648 self.info.regs.txdr().write(|w| w.set_txdata(*byte));
649 }
650 }
651 }
652 }
653
654 // Wait for transfer to complete
655 if is_last_group {
656 self.wait_tc(timeout)?;
657 self.master_stop();
658 self.wait_stop(timeout)?;
659 } else {
660 // Wait for TC before next group (enables RESTART)
661 self.wait_tc(timeout)?;
662 }
663
664 Ok(())
665 }
666
667 fn execute_read_group(
668 &mut self,
669 address: Address,
670 operations: &mut [Operation<'_>],
671 is_first_group: bool,
672 is_last_group: bool,
673 timeout: Timeout,
674 ) -> Result<(), Error> {
675 // Calculate total bytes across all operations in this group
676 let total_bytes = Self::total_operation_bytes(operations);
677
678 if total_bytes == 0 {
679 // Handle empty read group
680 if is_first_group {
681 Self::master_read(
682 self.info,
683 address,
684 0,
685 if is_last_group { Stop::Automatic } else { Stop::Software },
686 false, // reload
687 !is_first_group,
688 timeout,
689 )?;
690 }
691 if is_last_group {
692 self.wait_stop(timeout)?;
693 }
694 return Ok(());
695 }
696
697 let mut total_remaining = total_bytes;
698 let mut first_chunk = true;
699
700 for operation in operations {
701 if let Operation::Read(buffer) = operation {
702 for chunk in buffer.chunks_mut(255) {
703 let chunk_len = chunk.len();
704 total_remaining -= chunk_len;
705 let is_last_chunk = total_remaining == 0;
706 let will_reload = !is_last_chunk;
707
708 if first_chunk {
709 // First chunk: initiate transfer
710 let stop = if is_last_group && is_last_chunk {
711 Stop::Automatic
712 } else {
713 Stop::Software
714 };
715
716 Self::master_read(
717 self.info,
718 address,
719 chunk_len,
720 stop,
721 will_reload,
722 !is_first_group, // restart if not first group
723 timeout,
724 )?;
725 first_chunk = false;
726 } else {
727 // Subsequent chunks: use reload
728 let stop = if is_last_group && is_last_chunk {
729 Stop::Automatic
730 } else {
731 Stop::Software
732 };
733 Self::reload(self.info, chunk_len, will_reload, stop, timeout)?;
734 }
735
736 // Receive data bytes
737 for byte in chunk {
738 self.wait_rxne(timeout)?;
739 *byte = self.info.regs.rxdr().read().rxdata();
740 }
741 }
742 }
743 }
744
745 // Wait for transfer to complete
746 if is_last_group {
747 self.wait_stop(timeout)?;
748 }
749 // For non-last read groups, don't wait for TC - the peripheral may hold SCL low
750 // in Software AUTOEND mode until the next START is issued. Just proceed directly
751 // to the next group which will issue RESTART and release the clock.
752
753 Ok(())
513 } 754 }
514 755
515 /// Blocking write multiple buffers. 756 /// Blocking write multiple buffers.
@@ -531,6 +772,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
531 first_length.min(255), 772 first_length.min(255),
532 Stop::Software, 773 Stop::Software,
533 (first_length > 255) || (last_slice_index != 0), 774 (first_length > 255) || (last_slice_index != 0),
775 false, // restart
534 timeout, 776 timeout,
535 ) { 777 ) {
536 self.master_stop(); 778 self.master_stop();
@@ -552,6 +794,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
552 self.info, 794 self.info,
553 slice_len.min(255), 795 slice_len.min(255),
554 (idx != last_slice_index) || (slice_len > 255), 796 (idx != last_slice_index) || (slice_len > 255),
797 Stop::Software,
555 timeout, 798 timeout,
556 ) { 799 ) {
557 if err != Error::Nack { 800 if err != Error::Nack {
@@ -567,6 +810,7 @@ impl<'d, M: Mode, IM: MasterMode> I2c<'d, M, IM> {
567 self.info, 810 self.info,
568 chunk.len(), 811 chunk.len(),
569 (number != last_chunk_idx) || (idx != last_slice_index), 812 (number != last_chunk_idx) || (idx != last_slice_index),
813 Stop::Software,
570 timeout, 814 timeout,
571 ) { 815 ) {
572 if err != Error::Nack { 816 if err != Error::Nack {
@@ -610,6 +854,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
610 first_slice: bool, 854 first_slice: bool,
611 last_slice: bool, 855 last_slice: bool,
612 send_stop: bool, 856 send_stop: bool,
857 restart: bool,
613 timeout: Timeout, 858 timeout: Timeout,
614 ) -> Result<(), Error> { 859 ) -> Result<(), Error> {
615 let total_len = write.len(); 860 let total_len = write.len();
@@ -676,10 +921,17 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
676 total_len.min(255), 921 total_len.min(255),
677 Stop::Software, 922 Stop::Software,
678 (total_len > 255) || !last_slice, 923 (total_len > 255) || !last_slice,
924 restart,
679 timeout, 925 timeout,
680 )?; 926 )?;
681 } else { 927 } else {
682 Self::reload(self.info, total_len.min(255), (total_len > 255) || !last_slice, timeout)?; 928 Self::reload(
929 self.info,
930 total_len.min(255),
931 (total_len > 255) || !last_slice,
932 Stop::Software,
933 timeout,
934 )?;
683 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 935 self.info.regs.cr1().modify(|w| w.set_tcie(true));
684 } 936 }
685 } else if !(isr.tcr() || isr.tc()) { 937 } else if !(isr.tcr() || isr.tc()) {
@@ -688,9 +940,13 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
688 } else if remaining_len == 0 { 940 } else if remaining_len == 0 {
689 return Poll::Ready(Ok(())); 941 return Poll::Ready(Ok(()));
690 } else { 942 } else {
691 let last_piece = (remaining_len <= 255) && last_slice; 943 if let Err(e) = Self::reload(
692 944 self.info,
693 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 945 remaining_len.min(255),
946 (remaining_len > 255) || !last_slice,
947 Stop::Software,
948 timeout,
949 ) {
694 return Poll::Ready(Err(e)); 950 return Poll::Ready(Err(e));
695 } 951 }
696 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 952 self.info.regs.cr1().modify(|w| w.set_tcie(true));
@@ -702,10 +958,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
702 .await?; 958 .await?;
703 959
704 dma_transfer.await; 960 dma_transfer.await;
705 if last_slice { 961
706 // This should be done already 962 // Always wait for TC after DMA completes - needed for consecutive buffers
707 self.wait_tc(timeout)?; 963 self.wait_tc(timeout)?;
708 }
709 964
710 if last_slice & send_stop { 965 if last_slice & send_stop {
711 self.master_stop(); 966 self.master_stop();
@@ -780,7 +1035,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
780 address, 1035 address,
781 total_len.min(255), 1036 total_len.min(255),
782 Stop::Automatic, 1037 Stop::Automatic,
783 total_len > 255, 1038 total_len > 255, // reload
784 restart, 1039 restart,
785 timeout, 1040 timeout,
786 )?; 1041 )?;
@@ -788,12 +1043,10 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
788 return Poll::Ready(Ok(())); 1043 return Poll::Ready(Ok(()));
789 } 1044 }
790 } else if isr.tcr() { 1045 } else if isr.tcr() {
791 // poll_fn was woken without an interrupt present 1046 // Transfer Complete Reload - need to set up next chunk
792 return Poll::Pending;
793 } else {
794 let last_piece = remaining_len <= 255; 1047 let last_piece = remaining_len <= 255;
795 1048
796 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, timeout) { 1049 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, Stop::Automatic, timeout) {
797 return Poll::Ready(Err(e)); 1050 return Poll::Ready(Err(e));
798 } 1051 }
799 // Return here if we are on last chunk, 1052 // Return here if we are on last chunk,
@@ -802,6 +1055,9 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
802 return Poll::Ready(Ok(())); 1055 return Poll::Ready(Ok(()));
803 } 1056 }
804 self.info.regs.cr1().modify(|w| w.set_tcie(true)); 1057 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1058 } else {
1059 // poll_fn was woken without TCR interrupt
1060 return Poll::Pending;
805 } 1061 }
806 1062
807 remaining_len = remaining_len.saturating_sub(255); 1063 remaining_len = remaining_len.saturating_sub(255);
@@ -826,7 +1082,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
826 self.write_internal(address.into(), write, true, timeout) 1082 self.write_internal(address.into(), write, true, timeout)
827 } else { 1083 } else {
828 timeout 1084 timeout
829 .with(self.write_dma_internal(address.into(), write, true, true, true, timeout)) 1085 .with(self.write_dma_internal(address.into(), write, true, true, true, false, timeout))
830 .await 1086 .await
831 } 1087 }
832 } 1088 }
@@ -842,16 +1098,24 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
842 if write.is_empty() { 1098 if write.is_empty() {
843 return Err(Error::ZeroLengthTransfer); 1099 return Err(Error::ZeroLengthTransfer);
844 } 1100 }
845 let mut iter = write.iter();
846 1101
1102 let mut iter = write.iter();
847 let mut first = true; 1103 let mut first = true;
848 let mut current = iter.next(); 1104 let mut current = iter.next();
1105
849 while let Some(c) = current { 1106 while let Some(c) = current {
850 let next = iter.next(); 1107 let next = iter.next();
851 let is_last = next.is_none(); 1108 let is_last = next.is_none();
852 1109
853 let fut = self.write_dma_internal(address, c, first, is_last, is_last, timeout); 1110 let fut = self.write_dma_internal(
1111 address, c, first, // first_slice
1112 is_last, // last_slice
1113 is_last, // send_stop (only on last buffer)
1114 false, // restart (false for all - they're one continuous write)
1115 timeout,
1116 );
854 timeout.with(fut).await?; 1117 timeout.with(fut).await?;
1118
855 first = false; 1119 first = false;
856 current = next; 1120 current = next;
857 } 1121 }
@@ -881,7 +1145,7 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
881 if write.is_empty() { 1145 if write.is_empty() {
882 self.write_internal(address.into(), write, false, timeout)?; 1146 self.write_internal(address.into(), write, false, timeout)?;
883 } else { 1147 } else {
884 let fut = self.write_dma_internal(address.into(), write, true, true, false, timeout); 1148 let fut = self.write_dma_internal(address.into(), write, true, true, false, false, timeout);
885 timeout.with(fut).await?; 1149 timeout.with(fut).await?;
886 } 1150 }
887 1151
@@ -903,9 +1167,299 @@ impl<'d, IM: MasterMode> I2c<'d, Async, IM> {
903 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> { 1167 pub async fn transaction(&mut self, addr: u8, operations: &mut [Operation<'_>]) -> Result<(), Error> {
904 #[cfg(all(feature = "low-power", stm32wlex))] 1168 #[cfg(all(feature = "low-power", stm32wlex))]
905 let _device_busy = crate::low_power::DeviceBusy::new_stop1(); 1169 let _device_busy = crate::low_power::DeviceBusy::new_stop1();
906 let _ = addr; 1170
907 let _ = operations; 1171 if operations.is_empty() {
908 todo!() 1172 return Err(Error::ZeroLengthTransfer);
1173 }
1174
1175 let address = addr.into();
1176 let timeout = self.timeout();
1177
1178 // Group consecutive operations of the same type
1179 let mut op_idx = 0;
1180 let mut is_first_group = true;
1181
1182 while op_idx < operations.len() {
1183 // Determine the type of current group and find all consecutive operations of same type
1184 let is_read = matches!(operations[op_idx], Operation::Read(_));
1185 let group_start = op_idx;
1186
1187 // Find end of this group (consecutive operations of same type)
1188 while op_idx < operations.len() && matches!(operations[op_idx], Operation::Read(_)) == is_read {
1189 op_idx += 1;
1190 }
1191 let group_end = op_idx;
1192 let is_last_group = op_idx >= operations.len();
1193
1194 // Execute this group of operations
1195 if is_read {
1196 self.execute_read_group_async(
1197 address,
1198 &mut operations[group_start..group_end],
1199 is_first_group,
1200 is_last_group,
1201 timeout,
1202 )
1203 .await?;
1204 } else {
1205 self.execute_write_group_async(
1206 address,
1207 &operations[group_start..group_end],
1208 is_first_group,
1209 is_last_group,
1210 timeout,
1211 )
1212 .await?;
1213 }
1214
1215 is_first_group = false;
1216 }
1217
1218 Ok(())
1219 }
1220
1221 async fn execute_write_group_async(
1222 &mut self,
1223 address: Address,
1224 operations: &[Operation<'_>],
1225 is_first_group: bool,
1226 is_last_group: bool,
1227 timeout: Timeout,
1228 ) -> Result<(), Error> {
1229 // Calculate total bytes across all operations in this group
1230 let total_bytes = Self::total_operation_bytes(operations);
1231
1232 if total_bytes == 0 {
1233 // Handle empty write group using blocking call
1234 if is_first_group {
1235 Self::master_write(self.info, address, 0, Stop::Software, false, !is_first_group, timeout)?;
1236 }
1237 if is_last_group {
1238 self.master_stop();
1239 }
1240 return Ok(());
1241 }
1242
1243 // Collect all write buffers
1244 let mut write_buffers: heapless::Vec<&[u8], 16> = heapless::Vec::new();
1245 for operation in operations {
1246 if let Operation::Write(buffer) = operation {
1247 if !buffer.is_empty() {
1248 let _ = write_buffers.push(buffer);
1249 }
1250 }
1251 }
1252
1253 if write_buffers.is_empty() {
1254 return Ok(());
1255 }
1256
1257 // Send each buffer using DMA
1258 let num_buffers = write_buffers.len();
1259 for (idx, buffer) in write_buffers.iter().enumerate() {
1260 let is_first_buffer = idx == 0;
1261 let is_last_buffer = idx == num_buffers - 1;
1262
1263 let fut = self.write_dma_internal(
1264 address,
1265 buffer,
1266 is_first_buffer, // first_slice
1267 is_last_buffer, // last_slice
1268 is_last_buffer && is_last_group, // send_stop
1269 is_first_buffer && !is_first_group, // restart (only for first buffer if not first group)
1270 timeout,
1271 );
1272 timeout.with(fut).await?;
1273 }
1274
1275 Ok(())
1276 }
1277
1278 async fn execute_read_group_async(
1279 &mut self,
1280 address: Address,
1281 operations: &mut [Operation<'_>],
1282 is_first_group: bool,
1283 is_last_group: bool,
1284 timeout: Timeout,
1285 ) -> Result<(), Error> {
1286 // Calculate total bytes across all operations in this group
1287 let total_bytes = Self::total_operation_bytes(operations);
1288
1289 if total_bytes == 0 {
1290 // Handle empty read group using blocking call
1291 if is_first_group {
1292 Self::master_read(
1293 self.info,
1294 address,
1295 0,
1296 if is_last_group { Stop::Automatic } else { Stop::Software },
1297 false, // reload
1298 !is_first_group,
1299 timeout,
1300 )?;
1301 }
1302 if is_last_group {
1303 self.wait_stop(timeout)?;
1304 }
1305 return Ok(());
1306 }
1307
1308 // Use DMA for read operations - need to handle multiple buffers
1309 let restart = !is_first_group;
1310 let mut total_remaining = total_bytes;
1311 let mut is_first_in_group = true;
1312
1313 for operation in operations {
1314 if let Operation::Read(buffer) = operation {
1315 if buffer.is_empty() {
1316 // Skip empty buffers
1317 continue;
1318 }
1319
1320 let buf_len = buffer.len();
1321 total_remaining -= buf_len;
1322 let is_last_in_group = total_remaining == 0;
1323
1324 // Perform DMA read
1325 if is_first_in_group {
1326 // First buffer: use read_dma_internal which handles restart properly
1327 // Only use Automatic stop if this is the last buffer in the last group
1328 let stop_mode = if is_last_group && is_last_in_group {
1329 Stop::Automatic
1330 } else {
1331 Stop::Software
1332 };
1333
1334 // We need a custom DMA read that respects our stop mode
1335 self.read_dma_group_internal(address, buffer, restart, stop_mode, timeout)
1336 .await?;
1337 is_first_in_group = false;
1338 } else {
1339 // Subsequent buffers: need to reload and continue
1340 let stop_mode = if is_last_group && is_last_in_group {
1341 Stop::Automatic
1342 } else {
1343 Stop::Software
1344 };
1345
1346 self.read_dma_group_internal(
1347 address, buffer, false, // no restart for subsequent buffers in same group
1348 stop_mode, timeout,
1349 )
1350 .await?;
1351 }
1352 }
1353 }
1354
1355 // Wait for transfer to complete
1356 if is_last_group {
1357 self.wait_stop(timeout)?;
1358 }
1359
1360 Ok(())
1361 }
1362
1363 /// Internal DMA read helper for transaction groups
1364 async fn read_dma_group_internal(
1365 &mut self,
1366 address: Address,
1367 buffer: &mut [u8],
1368 restart: bool,
1369 stop_mode: Stop,
1370 timeout: Timeout,
1371 ) -> Result<(), Error> {
1372 let total_len = buffer.len();
1373
1374 let dma_transfer = unsafe {
1375 let regs = self.info.regs;
1376 regs.cr1().modify(|w| {
1377 w.set_rxdmaen(true);
1378 w.set_tcie(true);
1379 w.set_nackie(true);
1380 w.set_errie(true);
1381 });
1382 let src = regs.rxdr().as_ptr() as *mut u8;
1383
1384 self.rx_dma.as_mut().unwrap().read(src, buffer, Default::default())
1385 };
1386
1387 let mut remaining_len = total_len;
1388
1389 let on_drop = OnDrop::new(|| {
1390 let regs = self.info.regs;
1391 regs.cr1().modify(|w| {
1392 w.set_rxdmaen(false);
1393 w.set_tcie(false);
1394 w.set_nackie(false);
1395 w.set_errie(false);
1396 });
1397 regs.icr().write(|w| {
1398 w.set_nackcf(true);
1399 w.set_berrcf(true);
1400 w.set_arlocf(true);
1401 w.set_ovrcf(true);
1402 });
1403 });
1404
1405 poll_fn(|cx| {
1406 self.state.waker.register(cx.waker());
1407
1408 let isr = self.info.regs.isr().read();
1409
1410 if isr.nackf() {
1411 return Poll::Ready(Err(Error::Nack));
1412 }
1413 if isr.arlo() {
1414 return Poll::Ready(Err(Error::Arbitration));
1415 }
1416 if isr.berr() {
1417 return Poll::Ready(Err(Error::Bus));
1418 }
1419 if isr.ovr() {
1420 return Poll::Ready(Err(Error::Overrun));
1421 }
1422
1423 if remaining_len == total_len {
1424 Self::master_read(
1425 self.info,
1426 address,
1427 total_len.min(255),
1428 stop_mode,
1429 total_len > 255, // reload
1430 restart,
1431 timeout,
1432 )?;
1433 if total_len <= 255 {
1434 return Poll::Ready(Ok(()));
1435 }
1436 } else if isr.tcr() {
1437 // Transfer Complete Reload - need to set up next chunk
1438 let last_piece = remaining_len <= 255;
1439
1440 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !last_piece, stop_mode, timeout) {
1441 return Poll::Ready(Err(e));
1442 }
1443 // Return here if we are on last chunk,
1444 // end of transfer will be awaited with the DMA below
1445 if last_piece {
1446 return Poll::Ready(Ok(()));
1447 }
1448 self.info.regs.cr1().modify(|w| w.set_tcie(true));
1449 } else {
1450 // poll_fn was woken without TCR interrupt
1451 return Poll::Pending;
1452 }
1453
1454 remaining_len = remaining_len.saturating_sub(255);
1455 Poll::Pending
1456 })
1457 .await?;
1458
1459 dma_transfer.await;
1460 drop(on_drop);
1461
1462 Ok(())
909 } 1463 }
910} 1464}
911 1465
@@ -1043,7 +1597,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1043 if number == 0 { 1597 if number == 0 {
1044 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1598 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1045 } else { 1599 } else {
1046 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1600 Self::reload(
1601 self.info,
1602 chunk.len(),
1603 number != last_chunk_idx,
1604 Stop::Software,
1605 timeout,
1606 )?;
1047 } 1607 }
1048 1608
1049 let mut index = 0; 1609 let mut index = 0;
@@ -1092,7 +1652,13 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1092 if number == 0 { 1652 if number == 0 {
1093 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx); 1653 Self::slave_start(self.info, chunk.len(), number != last_chunk_idx);
1094 } else { 1654 } else {
1095 Self::reload(self.info, chunk.len(), number != last_chunk_idx, timeout)?; 1655 Self::reload(
1656 self.info,
1657 chunk.len(),
1658 number != last_chunk_idx,
1659 Stop::Software,
1660 timeout,
1661 )?;
1096 } 1662 }
1097 1663
1098 let mut index = 0; 1664 let mut index = 0;
@@ -1228,7 +1794,13 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1228 Poll::Pending 1794 Poll::Pending
1229 } else if isr.tcr() { 1795 } else if isr.tcr() {
1230 let is_last_slice = remaining_len <= 255; 1796 let is_last_slice = remaining_len <= 255;
1231 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1797 if let Err(e) = Self::reload(
1798 self.info,
1799 remaining_len.min(255),
1800 !is_last_slice,
1801 Stop::Software,
1802 timeout,
1803 ) {
1232 return Poll::Ready(Err(e)); 1804 return Poll::Ready(Err(e));
1233 } 1805 }
1234 remaining_len = remaining_len.saturating_sub(255); 1806 remaining_len = remaining_len.saturating_sub(255);
@@ -1292,7 +1864,13 @@ impl<'d> I2c<'d, Async, MultiMaster> {
1292 Poll::Pending 1864 Poll::Pending
1293 } else if isr.tcr() { 1865 } else if isr.tcr() {
1294 let is_last_slice = remaining_len <= 255; 1866 let is_last_slice = remaining_len <= 255;
1295 if let Err(e) = Self::reload(self.info, remaining_len.min(255), !is_last_slice, timeout) { 1867 if let Err(e) = Self::reload(
1868 self.info,
1869 remaining_len.min(255),
1870 !is_last_slice,
1871 Stop::Software,
1872 timeout,
1873 ) {
1296 return Poll::Ready(Err(e)); 1874 return Poll::Ready(Err(e));
1297 } 1875 }
1298 remaining_len = remaining_len.saturating_sub(255); 1876 remaining_len = remaining_len.saturating_sub(255);
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 680edf433..6e492946a 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -658,3 +658,17 @@ fn init_hw(config: Config) -> Peripherals {
658 p 658 p
659 }) 659 })
660} 660}
661
662/// Performs a busy-wait delay for a specified number of microseconds.
663#[allow(unused)]
664pub(crate) fn block_for_us(us: u64) {
665 cfg_if::cfg_if! {
666 // this does strange things on stm32wlx in low power mode depending on exactly when it's called
667 // as in sometimes 15 us (1 tick) would take > 20 seconds.
668 if #[cfg(all(feature = "time", all(not(feature = "low-power"), not(stm32wlex))))] {
669 embassy_time::block_for(embassy_time::Duration::from_micros(us));
670 } else {
671 cortex_m::asm::delay(unsafe { rcc::get_freqs().sys.to_hertz().unwrap().0 as u64 * us / 1_000_000 } as u32);
672 }
673 }
674}
diff --git a/embassy-stm32/src/opamp.rs b/embassy-stm32/src/opamp.rs
index ac8d5de21..4a55f5bd3 100644
--- a/embassy-stm32/src/opamp.rs
+++ b/embassy-stm32/src/opamp.rs
@@ -4,19 +4,12 @@
4use embassy_hal_internal::PeripheralType; 4use embassy_hal_internal::PeripheralType;
5 5
6use crate::Peri; 6use crate::Peri;
7#[cfg(opamp_v5)]
8use crate::block_for_us;
7use crate::pac::opamp::vals::*; 9use crate::pac::opamp::vals::*;
8#[cfg(not(any(stm32g4, stm32f3)))] 10#[cfg(not(any(stm32g4, stm32f3)))]
9use crate::rcc::RccInfo; 11use crate::rcc::RccInfo;
10 12
11/// Performs a busy-wait delay for a specified number of microseconds.
12#[cfg(opamp_v5)]
13fn blocking_delay_ms(ms: u32) {
14 #[cfg(feature = "time")]
15 embassy_time::block_for(embassy_time::Duration::from_millis(ms as u64));
16 #[cfg(not(feature = "time"))]
17 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 1_000 * ms);
18}
19
20/// Gain 13/// Gain
21#[allow(missing_docs)] 14#[allow(missing_docs)]
22#[derive(Clone, Copy)] 15#[derive(Clone, Copy)]
@@ -439,7 +432,7 @@ impl<'d, T: Instance> OpAmp<'d, T> {
439 432
440 // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize 433 // The closer the trimming value is to the optimum trimming value, the longer it takes to stabilize
441 // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7 434 // (with a maximum stabilization time remaining below 2 ms in any case) -- RM0440 25.3.7
442 blocking_delay_ms(2); 435 block_for_us(2_000);
443 436
444 if !T::regs().csr().read().calout() { 437 if !T::regs().csr().read().calout() {
445 if mid == 0 { 438 if mid == 0 {
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
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::adc::vals::Scandir;
7use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime}; 6use embassy_stm32::adc::{Adc, AdcChannel, AnyAdcChannel, Resolution, SampleTime};
8use embassy_stm32::peripherals::ADC1; 7use embassy_stm32::peripherals::ADC1;
9use embassy_time::Timer; 8use 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}
diff --git a/examples/stm32f0/Cargo.toml b/examples/stm32f0/Cargo.toml
index a78873d21..177dd0ac2 100644
--- a/examples/stm32f0/Cargo.toml
+++ b/examples/stm32f0/Cargo.toml
@@ -16,6 +16,7 @@ panic-probe = { version = "1.0.0", features = ["print-defmt"] }
16embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] } 16embassy-sync = { version = "0.7.2", path = "../../embassy-sync", features = ["defmt"] }
17embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } 17embassy-executor = { version = "0.9.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
18embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 18embassy-time = { version = "0.5.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
19embedded-hal-1 = { package = "embedded-hal", version = "1.0" }
19static_cell = "2" 20static_cell = "2"
20portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] } 21portable-atomic = { version = "1.5", features = ["unsafe-assume-single-core"] }
21 22
diff --git a/examples/stm32f0/src/bin/i2c_master.rs b/examples/stm32f0/src/bin/i2c_master.rs
new file mode 100644
index 000000000..2e61ecdf7
--- /dev/null
+++ b/examples/stm32f0/src/bin/i2c_master.rs
@@ -0,0 +1,609 @@
1#![no_std]
2#![no_main]
3
4// Hardware Setup for NUCLEO-F072RB:
5// - I2C1 pins: PB8 (SCL), PB9 (SDA) on CN5 connector
6// - Connect to I2C slave device (e.g., Digilent Analog Discovery I2C slave, or EEPROM)
7// - Default slave address: 0x50
8// - Pull-up resistors: 4.7kΩ on both SCL and SDA
9// - CN5 Pin 10 (PB8/SCL) and CN5 Pin 9 (PB9/SDA)
10//
11// Analog Discovery - Waveforms Setup:
12// - Increase buffer size: Settings -> Device Manager -> Option 4
13// - Run Protocol Analyzer
14// - Configure as I2C Slave at address 0x50
15// - Connect and configure DIO pins for SCL and SDA
16// - Frequency: 100kHz - [✓] Clock Stretching
17
18use defmt::*;
19use embassy_executor::Spawner;
20use embassy_stm32::i2c::{Config, I2c, Master};
21use embassy_stm32::mode::{Async, Blocking};
22use embassy_stm32::time::Hertz;
23use embassy_stm32::{bind_interrupts, i2c, peripherals};
24use embassy_time::Timer;
25use embedded_hal_1::i2c::Operation;
26use {defmt_rtt as _, panic_probe as _};
27
28bind_interrupts!(struct Irqs {
29 I2C1 => i2c::EventInterruptHandler<peripherals::I2C1>, i2c::ErrorInterruptHandler<peripherals::I2C1>;
30});
31
32#[embassy_executor::main]
33async fn main(_spawner: Spawner) {
34 let p = embassy_stm32::init(Default::default());
35 info!("Run stm32 I2C v2 Master Tests...");
36
37 let mut i2c_peri = p.I2C1;
38 let mut scl = p.PB8;
39 let mut sda = p.PB9;
40
41 let mut config = Config::default();
42 config.frequency = Hertz(100_000);
43
44 // I2C slave address for Analog Discovery or test EEPROM
45 let slave_addr = 0x50u8;
46
47 // Wait for slave device to be ready
48 Timer::after_millis(100).await;
49
50 // ========== BLOCKING DIRECT API TESTS ==========
51 info!("========== BLOCKING DIRECT API TESTS ==========");
52 {
53 let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config);
54
55 info!("=== Test 1: Direct blocking_write ===");
56 test_blocking_write(&mut i2c, slave_addr);
57
58 info!("=== Test 2: Direct blocking_read ===");
59 test_blocking_read(&mut i2c, slave_addr);
60
61 info!("=== Test 3: Direct blocking_write_read ===");
62 test_blocking_write_read(&mut i2c, slave_addr);
63
64 info!("=== Test 4: Direct blocking_write_vectored ===");
65 test_blocking_write_vectored(&mut i2c, slave_addr);
66
67 info!("=== Test 5: Large buffer (>255 bytes) ===");
68 test_blocking_large_buffer(&mut i2c, slave_addr);
69
70 info!("Blocking direct API tests OK");
71 }
72
73 Timer::after_millis(100).await;
74
75 // ========== BLOCKING TRANSACTION TESTS ==========
76 info!("========== BLOCKING TRANSACTION TESTS ==========");
77 {
78 let mut i2c = I2c::new_blocking(i2c_peri.reborrow(), scl.reborrow(), sda.reborrow(), config);
79
80 info!("=== Test 6: Consecutive Writes (Should Merge) ===");
81 test_consecutive_writes_blocking(&mut i2c, slave_addr);
82
83 info!("=== Test 7: Consecutive Reads (Should Merge) ===");
84 test_consecutive_reads_blocking(&mut i2c, slave_addr);
85
86 info!("=== Test 8: Write then Read (RESTART) ===");
87 test_write_then_read_blocking(&mut i2c, slave_addr);
88
89 info!("=== Test 9: Read then Write (RESTART) ===");
90 test_read_then_write_blocking(&mut i2c, slave_addr);
91
92 info!("=== Test 10: Complex Mixed Sequence ===");
93 test_mixed_sequence_blocking(&mut i2c, slave_addr);
94
95 info!("=== Test 11: Single Operations ===");
96 test_single_operations_blocking(&mut i2c, slave_addr);
97
98 info!("Blocking transaction tests OK");
99 }
100
101 Timer::after_millis(100).await;
102
103 // ========== ASYNC TESTS (DMA) ==========
104 info!("========== ASYNC TESTS (DMA) ==========");
105 {
106 let tx_dma = p.DMA1_CH2;
107 let rx_dma = p.DMA1_CH3;
108
109 let mut i2c = I2c::new(i2c_peri, scl, sda, Irqs, tx_dma, rx_dma, config);
110
111 // Direct API tests (reusing same I2C instance)
112 info!("=== Direct API Test 1: write() ===");
113 test_async_write(&mut i2c, slave_addr).await;
114
115 info!("=== Direct API Test 2: read() ===");
116 test_async_read(&mut i2c, slave_addr).await;
117
118 info!("=== Direct API Test 3: write_read() ===");
119 test_async_write_read(&mut i2c, slave_addr).await;
120
121 info!("=== Direct API Test 4: write_vectored() ===");
122 test_async_write_vectored(&mut i2c, slave_addr).await;
123
124 info!("=== Direct API Test 5: Large buffer (>255 bytes) ===");
125 test_async_large_buffer(&mut i2c, slave_addr).await;
126
127 info!("Async Direct API tests OK");
128
129 // Transaction tests
130 info!("=== Transaction Test 6: Consecutive Writes (Should Merge) ===");
131 test_consecutive_writes_async(&mut i2c, slave_addr).await;
132
133 info!("=== Transaction Test 7: Consecutive Reads (Should Merge) ===");
134 test_consecutive_reads_async(&mut i2c, slave_addr).await;
135
136 info!("=== Transaction Test 8: Write then Read (RESTART) ===");
137 test_write_then_read_async(&mut i2c, slave_addr).await;
138
139 info!("=== Transaction Test 9: Read then Write (RESTART) ===");
140 test_read_then_write_async(&mut i2c, slave_addr).await;
141
142 info!("=== Transaction Test 10: Complex Mixed Sequence ===");
143 test_mixed_sequence_async(&mut i2c, slave_addr).await;
144
145 info!("=== Transaction Test 11: Single Operations ===");
146 test_single_operations_async(&mut i2c, slave_addr).await;
147
148 info!("Async transaction tests OK");
149 }
150
151 info!("All tests OK");
152 cortex_m::asm::bkpt();
153}
154
155// ==================== BLOCKING DIRECT API TEST FUNCTIONS ====================
156
157fn test_blocking_write(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
158 let write_data = [0x42, 0x43, 0x44, 0x45];
159
160 match i2c.blocking_write(addr, &write_data) {
161 Ok(_) => info!("✓ blocking_write succeeded: {:02x}", write_data),
162 Err(e) => {
163 error!("✗ blocking_write failed: {:?}", e);
164 defmt::panic!("Test failed: blocking_write");
165 }
166 }
167}
168
169fn test_blocking_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
170 let mut read_buf = [0u8; 8];
171
172 match i2c.blocking_read(addr, &mut read_buf) {
173 Ok(_) => info!("✓ blocking_read succeeded: {:02x}", read_buf),
174 Err(e) => {
175 error!("✗ blocking_read failed: {:?}", e);
176 defmt::panic!("Test failed: blocking_read");
177 }
178 }
179}
180
181fn test_blocking_write_read(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
182 let write_data = [0x50, 0x51];
183 let mut read_buf = [0u8; 6];
184
185 match i2c.blocking_write_read(addr, &write_data, &mut read_buf) {
186 Ok(_) => {
187 info!("✓ blocking_write_read succeeded");
188 info!(" Written: {:02x}", write_data);
189 info!(" Read: {:02x}", read_buf);
190 }
191 Err(e) => {
192 error!("✗ blocking_write_read failed: {:?}", e);
193 defmt::panic!("Test failed: blocking_write_read");
194 }
195 }
196}
197
198fn test_blocking_write_vectored(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
199 let buf1 = [0x60, 0x61, 0x62];
200 let buf2 = [0x70, 0x71];
201 let buf3 = [0x80, 0x81, 0x82, 0x83];
202 let bufs = [&buf1[..], &buf2[..], &buf3[..]];
203
204 match i2c.blocking_write_vectored(addr, &bufs) {
205 Ok(_) => info!("✓ blocking_write_vectored succeeded (9 bytes total)"),
206 Err(e) => {
207 error!("✗ blocking_write_vectored failed: {:?}", e);
208 defmt::panic!("Test failed: blocking_write_vectored");
209 }
210 }
211}
212
213fn test_blocking_large_buffer(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
214 // Test with 300 bytes to verify RELOAD mechanism works (needs chunking at 255 bytes)
215 let mut write_buf = [0u8; 300];
216 for (i, byte) in write_buf.iter_mut().enumerate() {
217 *byte = (i & 0xFF) as u8;
218 }
219
220 match i2c.blocking_write(addr, &write_buf) {
221 Ok(_) => info!("✓ Large buffer write succeeded (300 bytes, tests RELOAD)"),
222 Err(e) => {
223 error!("✗ Large buffer write failed: {:?}", e);
224 defmt::panic!("Test failed: large buffer write");
225 }
226 }
227
228 // Test large read
229 let mut read_buf = [0u8; 300];
230 match i2c.blocking_read(addr, &mut read_buf) {
231 Ok(_) => info!("✓ Large buffer read succeeded (300 bytes, tests RELOAD)"),
232 Err(e) => {
233 error!("✗ Large buffer read failed: {:?}", e);
234 defmt::panic!("Test failed: large buffer read");
235 }
236 }
237}
238
239// ==================== BLOCKING TRANSACTION TEST FUNCTIONS ====================
240
241fn test_consecutive_writes_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
242 // Expected on bus: START, ADDR+W, data1, data2, data3, STOP
243 // NO intermediate RESTART/STOP between writes - they should be merged
244 let data1 = [0x10, 0x11, 0x12];
245 let data2 = [0x20, 0x21];
246 let data3 = [0x30, 0x31, 0x32, 0x33];
247
248 let mut ops = [
249 Operation::Write(&data1),
250 Operation::Write(&data2),
251 Operation::Write(&data3),
252 ];
253
254 match i2c.blocking_transaction(addr, &mut ops) {
255 Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"),
256 Err(e) => {
257 error!("✗ Consecutive writes failed: {:?}", e);
258 defmt::panic!("Test failed: consecutive writes");
259 }
260 }
261}
262
263fn test_consecutive_reads_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
264 // Expected on bus: START, ADDR+R, data1, data2, data3, NACK, STOP
265 // NO intermediate RESTART/STOP between reads - they should be merged
266 let mut buf1 = [0u8; 4];
267 let mut buf2 = [0u8; 3];
268 let mut buf3 = [0u8; 2];
269
270 let mut ops = [
271 Operation::Read(&mut buf1),
272 Operation::Read(&mut buf2),
273 Operation::Read(&mut buf3),
274 ];
275
276 match i2c.blocking_transaction(addr, &mut ops) {
277 Ok(_) => {
278 info!("✓ Consecutive reads succeeded (merged 9 bytes)");
279 info!(" buf1: {:02x}", buf1);
280 info!(" buf2: {:02x}", buf2);
281 info!(" buf3: {:02x}", buf3);
282 }
283 Err(e) => {
284 error!("✗ Consecutive reads failed: {:?}", e);
285 defmt::panic!("Test failed: consecutive reads");
286 }
287 }
288}
289
290fn test_write_then_read_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
291 // Expected: START, ADDR+W, data, RESTART, ADDR+R, data, NACK, STOP
292 let write_data = [0xAA, 0xBB];
293 let mut read_buf = [0u8; 4];
294
295 let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)];
296
297 match i2c.blocking_transaction(addr, &mut ops) {
298 Ok(_) => {
299 info!("✓ Write-then-read succeeded with RESTART");
300 info!(" Written: {:02x}", write_data);
301 info!(" Read: {:02x}", read_buf);
302 }
303 Err(e) => {
304 error!("✗ Write-then-read failed: {:?}", e);
305 defmt::panic!("Test failed: write-then-read");
306 }
307 }
308}
309
310fn test_read_then_write_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
311 // Expected: START, ADDR+R, data, NACK, RESTART, ADDR+W, data, STOP
312 let mut read_buf = [0u8; 3];
313 let write_data = [0xCC, 0xDD, 0xEE];
314
315 let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)];
316
317 match i2c.blocking_transaction(addr, &mut ops) {
318 Ok(_) => {
319 info!("✓ Read-then-write succeeded with RESTART");
320 info!(" Read: {:02x}", read_buf);
321 info!(" Written: {:02x}", write_data);
322 }
323 Err(e) => {
324 error!("✗ Read-then-write failed: {:?}", e);
325 defmt::panic!("Test failed: read-then-write");
326 }
327 }
328}
329
330fn test_mixed_sequence_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
331 // Complex: W, W, R, R, W, R
332 // Groups: [W,W] RESTART [R,R] RESTART [W] RESTART [R]
333 let w1 = [0x01, 0x02];
334 let w2 = [0x03, 0x04];
335 let mut r1 = [0u8; 2];
336 let mut r2 = [0u8; 2];
337 let w3 = [0x05];
338 let mut r3 = [0u8; 1];
339
340 let mut ops = [
341 Operation::Write(&w1),
342 Operation::Write(&w2),
343 Operation::Read(&mut r1),
344 Operation::Read(&mut r2),
345 Operation::Write(&w3),
346 Operation::Read(&mut r3),
347 ];
348
349 match i2c.blocking_transaction(addr, &mut ops) {
350 Ok(_) => {
351 info!("✓ Mixed sequence succeeded");
352 info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]");
353 }
354 Err(e) => {
355 error!("✗ Mixed sequence failed: {:?}", e);
356 defmt::panic!("Test failed: mixed sequence");
357 }
358 }
359}
360
361fn test_single_operations_blocking(i2c: &mut I2c<'_, Blocking, Master>, addr: u8) {
362 // Test single write
363 let write_data = [0xFF];
364 let mut ops = [Operation::Write(&write_data)];
365
366 match i2c.blocking_transaction(addr, &mut ops) {
367 Ok(_) => info!("✓ Single write succeeded"),
368 Err(e) => {
369 error!("✗ Single write failed: {:?}", e);
370 defmt::panic!("Test failed: single write");
371 }
372 }
373
374 // Test single read
375 let mut read_buf = [0u8; 1];
376 let mut ops = [Operation::Read(&mut read_buf)];
377
378 match i2c.blocking_transaction(addr, &mut ops) {
379 Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]),
380 Err(e) => {
381 error!("✗ Single read failed: {:?}", e);
382 defmt::panic!("Test failed: single read");
383 }
384 }
385}
386
387// ==================== ASYNC DIRECT API TEST FUNCTIONS ====================
388
389async fn test_async_write(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
390 let write_data = [0x42, 0x43, 0x44, 0x45];
391
392 match i2c.write(addr, &write_data).await {
393 Ok(_) => info!("✓ async write succeeded: {:02x}", write_data),
394 Err(e) => {
395 error!("✗ async write failed: {:?}", e);
396 defmt::panic!("Test failed: async write");
397 }
398 }
399}
400
401async fn test_async_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
402 let mut read_buf = [0u8; 8];
403
404 match i2c.read(addr, &mut read_buf).await {
405 Ok(_) => info!("✓ async read succeeded: {:02x}", read_buf),
406 Err(e) => {
407 error!("✗ async read failed: {:?}", e);
408 defmt::panic!("Test failed: async read");
409 }
410 }
411}
412
413async fn test_async_write_read(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
414 let write_data = [0x50, 0x51];
415 let mut read_buf = [0u8; 6];
416
417 match i2c.write_read(addr, &write_data, &mut read_buf).await {
418 Ok(_) => {
419 info!("✓ async write_read succeeded");
420 info!(" Written: {:02x}", write_data);
421 info!(" Read: {:02x}", read_buf);
422 }
423 Err(e) => {
424 error!("✗ async write_read failed: {:?}", e);
425 defmt::panic!("Test failed: async write_read");
426 }
427 }
428}
429
430async fn test_async_write_vectored(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
431 let buf1 = [0x60, 0x61, 0x62];
432 let buf2 = [0x70, 0x71];
433 let buf3 = [0x80, 0x81, 0x82, 0x83];
434 let bufs = [&buf1[..], &buf2[..], &buf3[..]];
435
436 match i2c.write_vectored(addr.into(), &bufs).await {
437 Ok(_) => info!("✓ async write_vectored succeeded (9 bytes total)"),
438 Err(e) => {
439 error!("✗ async write_vectored failed: {:?}", e);
440 defmt::panic!("Test failed: async write_vectored");
441 }
442 }
443}
444
445async fn test_async_large_buffer(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
446 // Test with 300 bytes to verify RELOAD mechanism works with DMA (needs chunking at 255 bytes)
447 let mut write_buf = [0u8; 300];
448 for (i, byte) in write_buf.iter_mut().enumerate() {
449 *byte = (i & 0xFF) as u8;
450 }
451
452 match i2c.write(addr, &write_buf).await {
453 Ok(_) => info!("✓ Large buffer async write succeeded (300 bytes, tests RELOAD with DMA)"),
454 Err(e) => {
455 error!("✗ Large buffer async write failed: {:?}", e);
456 defmt::panic!("Test failed: large buffer async write");
457 }
458 }
459
460 // Test large read
461 let mut read_buf = [0u8; 300];
462 match i2c.read(addr, &mut read_buf).await {
463 Ok(_) => info!("✓ Large buffer async read succeeded (300 bytes, tests RELOAD with DMA)"),
464 Err(e) => {
465 error!("✗ Large buffer async read failed: {:?}", e);
466 defmt::panic!("Test failed: large buffer async read");
467 }
468 }
469}
470
471// ==================== ASYNC TRANSACTION TEST FUNCTIONS ====================
472
473async fn test_consecutive_writes_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
474 let data1 = [0x10, 0x11, 0x12];
475 let data2 = [0x20, 0x21];
476 let data3 = [0x30, 0x31, 0x32, 0x33];
477
478 let mut ops = [
479 Operation::Write(&data1),
480 Operation::Write(&data2),
481 Operation::Write(&data3),
482 ];
483
484 match i2c.transaction(addr, &mut ops).await {
485 Ok(_) => info!("✓ Consecutive writes succeeded (merged 9 bytes)"),
486 Err(e) => {
487 error!("✗ Consecutive writes failed: {:?}", e);
488 defmt::panic!("Test failed: consecutive writes");
489 }
490 }
491}
492
493async fn test_consecutive_reads_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
494 let mut buf1 = [0u8; 4];
495 let mut buf2 = [0u8; 3];
496 let mut buf3 = [0u8; 2];
497
498 let mut ops = [
499 Operation::Read(&mut buf1),
500 Operation::Read(&mut buf2),
501 Operation::Read(&mut buf3),
502 ];
503
504 match i2c.transaction(addr, &mut ops).await {
505 Ok(_) => {
506 info!("✓ Consecutive reads succeeded (merged 9 bytes)");
507 info!(" buf1: {:02x}", buf1);
508 info!(" buf2: {:02x}", buf2);
509 info!(" buf3: {:02x}", buf3);
510 }
511 Err(e) => {
512 error!("✗ Consecutive reads failed: {:?}", e);
513 defmt::panic!("Test failed: consecutive reads");
514 }
515 }
516}
517
518async fn test_write_then_read_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
519 let write_data = [0xAA, 0xBB];
520 let mut read_buf = [0u8; 4];
521
522 let mut ops = [Operation::Write(&write_data), Operation::Read(&mut read_buf)];
523
524 match i2c.transaction(addr, &mut ops).await {
525 Ok(_) => {
526 info!("✓ Write-then-read succeeded with RESTART");
527 info!(" Written: {:02x}", write_data);
528 info!(" Read: {:02x}", read_buf);
529 }
530 Err(e) => {
531 error!("✗ Write-then-read failed: {:?}", e);
532 defmt::panic!("Test failed: write-then-read");
533 }
534 }
535}
536
537async fn test_read_then_write_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
538 let mut read_buf = [0u8; 3];
539 let write_data = [0xCC, 0xDD, 0xEE];
540
541 let mut ops = [Operation::Read(&mut read_buf), Operation::Write(&write_data)];
542
543 match i2c.transaction(addr, &mut ops).await {
544 Ok(_) => {
545 info!("✓ Read-then-write succeeded with RESTART");
546 info!(" Read: {:02x}", read_buf);
547 info!(" Written: {:02x}", write_data);
548 }
549 Err(e) => {
550 error!("✗ Read-then-write failed: {:?}", e);
551 defmt::panic!("Test failed: read-then-write");
552 }
553 }
554}
555
556async fn test_mixed_sequence_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
557 let w1 = [0x01, 0x02];
558 let w2 = [0x03, 0x04];
559 let mut r1 = [0u8; 2];
560 let mut r2 = [0u8; 2];
561 let w3 = [0x05];
562 let mut r3 = [0u8; 1];
563
564 let mut ops = [
565 Operation::Write(&w1),
566 Operation::Write(&w2),
567 Operation::Read(&mut r1),
568 Operation::Read(&mut r2),
569 Operation::Write(&w3),
570 Operation::Read(&mut r3),
571 ];
572
573 match i2c.transaction(addr, &mut ops).await {
574 Ok(_) => {
575 info!("✓ Mixed sequence succeeded");
576 info!(" Groups: [W4] RESTART [R4] RESTART [W1] RESTART [R1]");
577 }
578 Err(e) => {
579 error!("✗ Mixed sequence failed: {:?}", e);
580 defmt::panic!("Test failed: mixed sequence");
581 }
582 }
583}
584
585async fn test_single_operations_async(i2c: &mut I2c<'_, Async, Master>, addr: u8) {
586 // Test single write
587 let write_data = [0xFF];
588 let mut ops = [Operation::Write(&write_data)];
589
590 match i2c.transaction(addr, &mut ops).await {
591 Ok(_) => info!("✓ Single write succeeded"),
592 Err(e) => {
593 error!("✗ Single write failed: {:?}", e);
594 defmt::panic!("Test failed: single write");
595 }
596 }
597
598 // Test single read
599 let mut read_buf = [0u8; 1];
600 let mut ops = [Operation::Read(&mut read_buf)];
601
602 match i2c.transaction(addr, &mut ops).await {
603 Ok(_) => info!("✓ Single read succeeded, data: 0x{:02x}", read_buf[0]),
604 Err(e) => {
605 error!("✗ Single read failed: {:?}", e);
606 defmt::panic!("Test failed: single read");
607 }
608 }
609}
diff --git a/examples/stm32f469/src/bin/dsi_bsp.rs b/examples/stm32f469/src/bin/dsi_bsp.rs
index d659291ff..7ba4da72b 100644
--- a/examples/stm32f469/src/bin/dsi_bsp.rs
+++ b/examples/stm32f469/src/bin/dsi_bsp.rs
@@ -3,7 +3,7 @@
3 3
4use defmt::*; 4use defmt::*;
5use embassy_executor::Spawner; 5use embassy_executor::Spawner;
6use embassy_stm32::dsihost::{DsiHost, PacketType, blocking_delay_ms}; 6use embassy_stm32::dsihost::{DsiHost, PacketType};
7use embassy_stm32::gpio::{Level, Output, Speed}; 7use embassy_stm32::gpio::{Level, Output, Speed};
8use embassy_stm32::ltdc::Ltdc; 8use embassy_stm32::ltdc::Ltdc;
9use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1}; 9use embassy_stm32::pac::dsihost::regs::{Ier0, Ier1};
@@ -13,7 +13,7 @@ use embassy_stm32::rcc::{
13 AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk, 13 AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllMul, PllPDiv, PllPreDiv, PllQDiv, PllRDiv, PllSource, Sysclk,
14}; 14};
15use embassy_stm32::time::mhz; 15use embassy_stm32::time::mhz;
16use embassy_time::Timer; 16use embassy_time::{Duration, Timer, block_for};
17use {defmt_rtt as _, panic_probe as _}; 17use {defmt_rtt as _, panic_probe as _};
18 18
19enum _Orientation { 19enum _Orientation {
@@ -444,7 +444,7 @@ async fn main(_spawner: Spawner) {
444 dsi.enable_wrapper_dsi(); 444 dsi.enable_wrapper_dsi();
445 445
446 // First, delay 120 ms (reason unknown, STM32 Cube Example does it) 446 // First, delay 120 ms (reason unknown, STM32 Cube Example does it)
447 blocking_delay_ms(120); 447 block_for(Duration::from_millis(120));
448 448
449 // 1 to 26 449 // 1 to 26
450 dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap(); 450 dsi.write_cmd(0, NT35510_WRITES_0[0], &NT35510_WRITES_0[1..]).unwrap();
@@ -480,7 +480,7 @@ async fn main(_spawner: Spawner) {
480 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); 480 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
481 481
482 // Add a delay, otherwise MADCTL not taken 482 // Add a delay, otherwise MADCTL not taken
483 blocking_delay_ms(200); 483 block_for(Duration::from_millis(200));
484 484
485 // Configure orientation as landscape 485 // Configure orientation as landscape
486 dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..]) 486 dsi.write_cmd(0, NT35510_MADCTL_LANDSCAPE[0], &NT35510_MADCTL_LANDSCAPE[1..])
@@ -494,7 +494,7 @@ async fn main(_spawner: Spawner) {
494 dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap(); 494 dsi.write_cmd(0, NT35510_WRITES_27[0], &NT35510_WRITES_27[1..]).unwrap();
495 495
496 // Wait for sleep out exit 496 // Wait for sleep out exit
497 blocking_delay_ms(120); 497 block_for(Duration::from_millis(120));
498 498
499 // Configure COLOR_CODING 499 // Configure COLOR_CODING
500 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap(); 500 dsi.write_cmd(0, NT35510_WRITES_37[0], &NT35510_WRITES_37[1..]).unwrap();
@@ -590,7 +590,7 @@ async fn main(_spawner: Spawner) {
590 //LTDC->SRCR = LTDC_SRCR_IMR; 590 //LTDC->SRCR = LTDC_SRCR_IMR;
591 LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD)); 591 LTDC.srcr().modify(|w| w.set_imr(Imr::RELOAD));
592 592
593 blocking_delay_ms(5000); 593 block_for(Duration::from_millis(5000));
594 594
595 const READ_SIZE: u16 = 1; 595 const READ_SIZE: u16 = 1;
596 let mut data = [1u8; READ_SIZE as usize]; 596 let mut data = [1u8; READ_SIZE as usize];
@@ -606,7 +606,7 @@ async fn main(_spawner: Spawner) {
606 .unwrap(); 606 .unwrap();
607 info!("Display ID3: {:#04x}", data); 607 info!("Display ID3: {:#04x}", data);
608 608
609 blocking_delay_ms(500); 609 block_for(Duration::from_millis(500));
610 610
611 info!("Config done, start blinking LED"); 611 info!("Config done, start blinking LED");
612 loop { 612 loop {