diff options
| author | xoviat <[email protected]> | 2025-12-01 08:39:40 -0600 |
|---|---|---|
| committer | xoviat <[email protected]> | 2025-12-01 08:39:40 -0600 |
| commit | 6638d4c85e00b624c3b30591f48af255548c4cc0 (patch) | |
| tree | 968625ed9f4ed338855e367535557a51c720fa7c | |
| parent | b466ba29d2857815e5b25af7d8ab82d5b7e05e30 (diff) | |
| parent | cf6a27da33479d2ba11ac73066a4bb31746c5e04 (diff) | |
Merge branch 'main' of github.com:embassy-rs/embassy into timer
| -rw-r--r-- | embassy-stm32/CHANGELOG.md | 3 | ||||
| -rw-r--r-- | embassy-stm32/src/adc/mod.rs | 12 | ||||
| -rw-r--r-- | embassy-stm32/src/can/enums.rs | 37 | ||||
| -rw-r--r-- | embassy-stm32/src/can/util.rs | 33 | ||||
| -rw-r--r-- | embassy-stm32/src/gpio.rs | 6 | ||||
| -rw-r--r-- | embassy-stm32/src/i2c/v2.rs | 3 |
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 | ||
| 79 | pub(crate) trait SealedAdcChannel<T> { | 79 | pub(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 | ||
| 186 | impl<'d, T: AnyInstance> Adc<'d, T> { | 186 | impl<'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 | |||
| 418 | pub trait AdcChannel<T>: SealedAdcChannel<T> + Sized { | 418 | pub 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))] | ||
| 89 | pub 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 | ||
| 3 | use core::num::{NonZeroU8, NonZeroU16}; | 3 | use core::num::{NonZeroU8, NonZeroU16}; |
| 4 | 4 | ||
| 5 | use 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)] |
| 7 | pub struct NominalBitTiming { | 9 | pub 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 |
| 20 | pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> { | 22 | pub 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 | } |
