diff options
Diffstat (limited to 'embassy-stm32/src/can/util.rs')
| -rw-r--r-- | embassy-stm32/src/can/util.rs | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/embassy-stm32/src/can/util.rs b/embassy-stm32/src/can/util.rs index fcdbbad62..beca4c34e 100644 --- a/embassy-stm32/src/can/util.rs +++ b/embassy-stm32/src/can/util.rs | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | //! Utility functions shared between CAN controller types. | 1 | //! Utility functions shared between CAN controller types. |
| 2 | 2 | ||
| 3 | use core::num::{NonZeroU16, NonZeroU8}; | 3 | use core::num::{NonZeroU8, NonZeroU16}; |
| 4 | |||
| 5 | use crate::can::enums::TimingCalcError; | ||
| 4 | 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)] |
| @@ -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, |
