diff options
| author | Elias Hanelt <[email protected]> | 2025-11-28 12:05:22 -0800 |
|---|---|---|
| committer | Elias Hanelt <[email protected]> | 2025-11-28 12:05:22 -0800 |
| commit | d6bf4a2647e425ed045b4972a332bec397564b5d (patch) | |
| tree | fb054bf47c3d4582d5606ad688db219b80d925a0 /embassy-stm32/src | |
| parent | 006a0873d8efb9620841759f2c15450dc9ae044e (diff) | |
| parent | 217b683427687e8f3a27f02852e6f5bd2405ace3 (diff) | |
Merge remote-tracking branch 'origin/main' into i2c-slave/fix-early-term
Diffstat (limited to 'embassy-stm32/src')
| -rw-r--r-- | embassy-stm32/src/can/enums.rs | 37 | ||||
| -rw-r--r-- | embassy-stm32/src/can/util.rs | 33 |
2 files changed, 58 insertions, 12 deletions
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, |
