aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorxoviat <[email protected]>2025-12-01 08:39:40 -0600
committerxoviat <[email protected]>2025-12-01 08:39:40 -0600
commit6638d4c85e00b624c3b30591f48af255548c4cc0 (patch)
tree968625ed9f4ed338855e367535557a51c720fa7c
parentb466ba29d2857815e5b25af7d8ab82d5b7e05e30 (diff)
parentcf6a27da33479d2ba11ac73066a4bb31746c5e04 (diff)
Merge branch 'main' of github.com:embassy-rs/embassy into timer
-rw-r--r--embassy-stm32/CHANGELOG.md3
-rw-r--r--embassy-stm32/src/adc/mod.rs12
-rw-r--r--embassy-stm32/src/can/enums.rs37
-rw-r--r--embassy-stm32/src/can/util.rs33
-rw-r--r--embassy-stm32/src/gpio.rs6
-rw-r--r--embassy-stm32/src/i2c/v2.rs3
6 files changed, 74 insertions, 20 deletions
diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md
index 13c95b60a..70c46b025 100644
--- a/embassy-stm32/CHANGELOG.md
+++ b/embassy-stm32/CHANGELOG.md
@@ -85,6 +85,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
85- removal: ExtiInput no longer accepts AnyPin/AnyChannel; AnyChannel removed entirely 85- removal: ExtiInput no longer accepts AnyPin/AnyChannel; AnyChannel removed entirely
86- fix: build script ensures EXTI2_TSC is listed as the IRQ of EXTI2 even if the PAC doesn't 86- fix: build script ensures EXTI2_TSC is listed as the IRQ of EXTI2 even if the PAC doesn't
87- feat: stm32/lcd: added implementation 87- feat: stm32/lcd: added implementation
88- change: add error messages to can timing calculations ([#4961](https://github.com/embassy-rs/embassy/pull/4961))
89- fix: stm32/i2c v2: add stop flag on stop received
90- fix: stm32l47*/stm32l48* adc analog pin setup
88 91
89## 0.4.0 - 2025-08-26 92## 0.4.0 - 2025-08-26
90 93
diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs
index 6d53d9b91..a55b99e6a 100644
--- a/embassy-stm32/src/adc/mod.rs
+++ b/embassy-stm32/src/adc/mod.rs
@@ -77,7 +77,7 @@ trait SealedInstance {
77} 77}
78 78
79pub(crate) trait SealedAdcChannel<T> { 79pub(crate) trait SealedAdcChannel<T> {
80 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 80 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
81 fn setup(&mut self) {} 81 fn setup(&mut self) {}
82 82
83 #[allow(unused)] 83 #[allow(unused)]
@@ -185,11 +185,11 @@ pub enum RegularConversionMode {
185 185
186impl<'d, T: AnyInstance> Adc<'d, T> { 186impl<'d, T: AnyInstance> Adc<'d, T> {
187 #[cfg(any( 187 #[cfg(any(
188 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v4, adc_wba, adc_c0 188 adc_v2, adc_g4, adc_v3, adc_g0, adc_h5, adc_h7rs, adc_u0, adc_u5, adc_v3, adc_v4, adc_wba, adc_c0
189 ))] 189 ))]
190 /// Read an ADC pin. 190 /// Read an ADC pin.
191 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 { 191 pub fn blocking_read(&mut self, channel: &mut impl AdcChannel<T>, sample_time: T::SampleTime) -> u16 {
192 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 192 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
193 channel.setup(); 193 channel.setup();
194 194
195 // Ensure no conversions are ongoing 195 // Ensure no conversions are ongoing
@@ -418,7 +418,7 @@ pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeri
418pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { 418pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized {
419 #[allow(unused_mut)] 419 #[allow(unused_mut)]
420 fn degrade_adc(mut self) -> AnyAdcChannel<T> { 420 fn degrade_adc(mut self) -> AnyAdcChannel<T> {
421 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 421 #[cfg(any(adc_v1, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
422 self.setup(); 422 self.setup();
423 423
424 AnyAdcChannel { 424 AnyAdcChannel {
@@ -554,7 +554,7 @@ macro_rules! impl_adc_pin {
554 ($inst:ident, $pin:ident, $ch:expr) => { 554 ($inst:ident, $pin:ident, $ch:expr) => {
555 impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {} 555 impl crate::adc::AdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {}
556 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> { 556 impl crate::adc::SealedAdcChannel<peripherals::$inst> for crate::Peri<'_, crate::peripherals::$pin> {
557 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 557 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
558 fn setup(&mut self) { 558 fn setup(&mut self) {
559 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self); 559 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(self);
560 } 560 }
@@ -582,7 +582,7 @@ macro_rules! impl_adc_pair {
582 crate::Peri<'_, crate::peripherals::$npin>, 582 crate::Peri<'_, crate::peripherals::$npin>,
583 ) 583 )
584 { 584 {
585 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v4, adc_u5, adc_wba))] 585 #[cfg(any(adc_v1, adc_c0, adc_l0, adc_v2, adc_g4, adc_v3, adc_v4, adc_u5, adc_wba))]
586 fn setup(&mut self) { 586 fn setup(&mut self) {
587 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0); 587 <crate::peripherals::$pin as crate::gpio::SealedPin>::set_as_analog(&mut self.0);
588 <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1); 588 <crate::peripherals::$npin as crate::gpio::SealedPin>::set_as_analog(&mut self.1);
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs
index 6d91020fc..c5900cadc 100644
--- a/embassy-stm32/src/can/enums.rs
+++ b/embassy-stm32/src/can/enums.rs
@@ -82,3 +82,40 @@ pub enum RefCountOp {
82 /// Notify sender destroyed 82 /// Notify sender destroyed
83 NotifySenderDestroyed, 83 NotifySenderDestroyed,
84} 84}
85
86/// Error returned when calculating the can timing fails
87#[derive(Debug)]
88#[cfg_attr(feature = "defmt", derive(defmt::Format))]
89pub enum TimingCalcError {
90 /// Bitrate is lower than 1000
91 BitrateTooLow {
92 /// The set bitrate
93 bitrate: u32,
94 },
95 /// No solution possible
96 NoSolution {
97 /// The sum of BS1 and BS2
98 bs1_bs2_sum: u8,
99 },
100 /// Prescaler is not 1 < prescaler < 1024
101 InvalidPrescaler {
102 /// The calculated prescaler value
103 prescaler: u32,
104 },
105 /// BS1 or BS2 are not in the range 0 < BSx < BSx_MAX
106 BSNotInRange {
107 /// The value of BS1
108 bs1: u8,
109 /// The value of BS2
110 bs2: u8,
111 },
112 /// Final bitrate doesn't match the requested bitrate
113 NoMatch {
114 /// The requested bitrate
115 requested: u32,
116 /// The calculated bitrate
117 final_calculated: u32,
118 },
119 /// core::num::NonZeroUxx::new error
120 CoreNumNew,
121}
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs
index 6d7f0c16a..beca4c34e 100644
--- a/embassy-stm32/src/can/util.rs
+++ b/embassy-stm32/src/can/util.rs
@@ -2,6 +2,8 @@
2 2
3use core::num::{NonZeroU8, NonZeroU16}; 3use core::num::{NonZeroU8, NonZeroU16};
4 4
5use crate::can::enums::TimingCalcError;
6
5/// Shared struct to represent bit timings used by calc_can_timings. 7/// Shared struct to represent bit timings used by calc_can_timings.
6#[derive(Clone, Copy, Debug)] 8#[derive(Clone, Copy, Debug)]
7pub struct NominalBitTiming { 9pub struct NominalBitTiming {
@@ -17,7 +19,10 @@ pub struct NominalBitTiming {
17} 19}
18 20
19/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency 21/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency
20pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> { 22pub fn calc_can_timings(
23 periph_clock: crate::time::Hertz,
24 can_bitrate: u32,
25) -> Result<NominalBitTiming, TimingCalcError> {
21 const BS1_MAX: u8 = 16; 26 const BS1_MAX: u8 = 16;
22 const BS2_MAX: u8 = 8; 27 const BS2_MAX: u8 = 8;
23 const MAX_SAMPLE_POINT_PERMILL: u16 = 900; 28 const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
@@ -25,7 +30,7 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O
25 let periph_clock = periph_clock.0; 30 let periph_clock = periph_clock.0;
26 31
27 if can_bitrate < 1000 { 32 if can_bitrate < 1000 {
28 return None; 33 return Err(TimingCalcError::BitrateTooLow { bitrate: can_bitrate });
29 } 34 }
30 35
31 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG 36 // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
@@ -53,14 +58,14 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O
53 let mut bs1_bs2_sum = max_quanta_per_bit - 1; 58 let mut bs1_bs2_sum = max_quanta_per_bit - 1;
54 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { 59 while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
55 if bs1_bs2_sum <= 2 { 60 if bs1_bs2_sum <= 2 {
56 return None; // No solution 61 return Err(TimingCalcError::NoSolution { bs1_bs2_sum }); // No solution
57 } 62 }
58 bs1_bs2_sum -= 1; 63 bs1_bs2_sum -= 1;
59 } 64 }
60 65
61 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; 66 let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
62 if (prescaler < 1) || (prescaler > 1024) { 67 if (prescaler < 1) || (prescaler > 1024) {
63 return None; // No solution 68 return Err(TimingCalcError::InvalidPrescaler { prescaler }); // No solution
64 } 69 }
65 70
66 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. 71 // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
@@ -93,22 +98,26 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O
93 98
94 // Check is BS1 and BS2 are in range 99 // Check is BS1 and BS2 are in range
95 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { 100 if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
96 return None; 101 return Err(TimingCalcError::BSNotInRange { bs1, bs2 });
97 } 102 }
98 103
104 let calculated = periph_clock / (prescaler * (1 + bs1 + bs2) as u32);
99 // Check if final bitrate matches the requested 105 // Check if final bitrate matches the requested
100 if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { 106 if can_bitrate != calculated {
101 return None; 107 return Err(TimingCalcError::NoMatch {
108 requested: can_bitrate,
109 final_calculated: calculated,
110 });
102 } 111 }
103 112
104 // One is recommended by DS-015, CANOpen, and DeviceNet 113 // One is recommended by DS-015, CANOpen, and DeviceNet
105 let sync_jump_width = core::num::NonZeroU8::new(1)?; 114 let sync_jump_width = core::num::NonZeroU8::new(1).ok_or(TimingCalcError::CoreNumNew)?;
106 115
107 let seg1 = core::num::NonZeroU8::new(bs1)?; 116 let seg1 = core::num::NonZeroU8::new(bs1).ok_or(TimingCalcError::CoreNumNew)?;
108 let seg2 = core::num::NonZeroU8::new(bs2)?; 117 let seg2 = core::num::NonZeroU8::new(bs2).ok_or(TimingCalcError::CoreNumNew)?;
109 let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?; 118 let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16).ok_or(TimingCalcError::CoreNumNew)?;
110 119
111 Some(NominalBitTiming { 120 Ok(NominalBitTiming {
112 sync_jump_width, 121 sync_jump_width,
113 prescaler: nz_prescaler, 122 prescaler: nz_prescaler,
114 seg1, 123 seg1,
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index e7d4e9ad3..5de8bad2c 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -684,7 +684,11 @@ fn set_as_analog(pin_port: PinNumber) {
684 }); 684 });
685 685
686 #[cfg(gpio_v2)] 686 #[cfg(gpio_v2)]
687 r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG)); 687 {
688 #[cfg(any(stm32l47x, stm32l48x))]
689 r.ascr().modify(|w| w.set_asc(n, true));
690 r.moder().modify(|w| w.set_moder(n, vals::Moder::ANALOG));
691 }
688} 692}
689 693
690#[inline(never)] 694#[inline(never)]
diff --git a/embassy-stm32/src/i2c/v2.rs b/embassy-stm32/src/i2c/v2.rs
index b2ba94e21..6b213484c 100644
--- a/embassy-stm32/src/i2c/v2.rs
+++ b/embassy-stm32/src/i2c/v2.rs
@@ -1600,7 +1600,8 @@ impl<'d, M: Mode> I2c<'d, M, MultiMaster> {
1600 for byte in chunk { 1600 for byte in chunk {
1601 // Wait until we have received something 1601 // Wait until we have received something
1602 match self.wait_rxne(timeout) { 1602 match self.wait_rxne(timeout) {
1603 Ok(ReceiveResult::StopReceived) | Ok(ReceiveResult::NewStart) => { 1603 Ok(ReceiveResult::StopReceived) => {}
1604 Ok(ReceiveResult::NewStart) => {
1604 trace!("--- Slave RX transmission end (early)"); 1605 trace!("--- Slave RX transmission end (early)");
1605 return Ok(total_len - remaining_len); // Return N bytes read 1606 return Ok(total_len - remaining_len); // Return N bytes read
1606 } 1607 }