diff options
| author | Jomer.Dev <[email protected]> | 2025-11-27 20:53:02 +0100 |
|---|---|---|
| committer | Jomer.Dev <[email protected]> | 2025-11-27 20:53:02 +0100 |
| commit | e34c43d72b77e78cb971a73c59efa3e746db331f (patch) | |
| tree | e52817fd2c27e9b945082e35e6fe82a5cf000285 /embassy-stm32 | |
| parent | b8afe4ff5fd590903861e44224171f37b9ae6e62 (diff) | |
Add error messages to calc_can_timings
Diffstat (limited to 'embassy-stm32')
| -rw-r--r-- | embassy-stm32/src/can/enums.rs | 37 | ||||
| -rw-r--r-- | embassy-stm32/src/can/util.rs | 27 |
2 files changed, 52 insertions, 12 deletions
diff --git a/embassy-stm32/src/can/enums.rs b/embassy-stm32/src/can/enums.rs index 6d91020fc..0b2fd9901 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..e93fe607d 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,7 @@ 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(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Result<NominalBitTiming, TimingCalcError> { |
| 21 | const BS1_MAX: u8 = 16; | 23 | const BS1_MAX: u8 = 16; |
| 22 | const BS2_MAX: u8 = 8; | 24 | const BS2_MAX: u8 = 8; |
| 23 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | 25 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; |
| @@ -25,7 +27,7 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O | |||
| 25 | let periph_clock = periph_clock.0; | 27 | let periph_clock = periph_clock.0; |
| 26 | 28 | ||
| 27 | if can_bitrate < 1000 { | 29 | if can_bitrate < 1000 { |
| 28 | return None; | 30 | return Err(TimingCalcError::BitrateTooLow { bitrate: can_bitrate }); |
| 29 | } | 31 | } |
| 30 | 32 | ||
| 31 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG | 33 | // Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG |
| @@ -53,14 +55,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; | 55 | let mut bs1_bs2_sum = max_quanta_per_bit - 1; |
| 54 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { | 56 | while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 { |
| 55 | if bs1_bs2_sum <= 2 { | 57 | if bs1_bs2_sum <= 2 { |
| 56 | return None; // No solution | 58 | return Err(TimingCalcError::NoSolution { bs1_bs2_sum }); // No solution |
| 57 | } | 59 | } |
| 58 | bs1_bs2_sum -= 1; | 60 | bs1_bs2_sum -= 1; |
| 59 | } | 61 | } |
| 60 | 62 | ||
| 61 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; | 63 | let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32; |
| 62 | if (prescaler < 1) || (prescaler > 1024) { | 64 | if (prescaler < 1) || (prescaler > 1024) { |
| 63 | return None; // No solution | 65 | return Err(TimingCalcError::InvalidPrescaler { prescaler }); // No solution |
| 64 | } | 66 | } |
| 65 | 67 | ||
| 66 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. | 68 | // Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum. |
| @@ -93,22 +95,23 @@ pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> O | |||
| 93 | 95 | ||
| 94 | // Check is BS1 and BS2 are in range | 96 | // Check is BS1 and BS2 are in range |
| 95 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { | 97 | if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) { |
| 96 | return None; | 98 | return Err(TimingCalcError::BSNotInRange { bs1, bs2 }); |
| 97 | } | 99 | } |
| 98 | 100 | ||
| 101 | let calculated = periph_clock / (prescaler * (1 + bs1 + bs2) as u32); | ||
| 99 | // Check if final bitrate matches the requested | 102 | // Check if final bitrate matches the requested |
| 100 | if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) { | 103 | if can_bitrate != calculated { |
| 101 | return None; | 104 | return Err(TimingCalcError::NoMatch { requested: can_bitrate, final_calculated: calculated }); |
| 102 | } | 105 | } |
| 103 | 106 | ||
| 104 | // One is recommended by DS-015, CANOpen, and DeviceNet | 107 | // One is recommended by DS-015, CANOpen, and DeviceNet |
| 105 | let sync_jump_width = core::num::NonZeroU8::new(1)?; | 108 | let sync_jump_width = core::num::NonZeroU8::new(1).ok_or(TimingCalcError::CoreNumNew)?; |
| 106 | 109 | ||
| 107 | let seg1 = core::num::NonZeroU8::new(bs1)?; | 110 | let seg1 = core::num::NonZeroU8::new(bs1).ok_or(TimingCalcError::CoreNumNew)?; |
| 108 | let seg2 = core::num::NonZeroU8::new(bs2)?; | 111 | let seg2 = core::num::NonZeroU8::new(bs2).ok_or(TimingCalcError::CoreNumNew)?; |
| 109 | let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?; | 112 | let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16).ok_or(TimingCalcError::CoreNumNew)?; |
| 110 | 113 | ||
| 111 | Some(NominalBitTiming { | 114 | Ok(NominalBitTiming { |
| 112 | sync_jump_width, | 115 | sync_jump_width, |
| 113 | prescaler: nz_prescaler, | 116 | prescaler: nz_prescaler, |
| 114 | seg1, | 117 | seg1, |
