aboutsummaryrefslogtreecommitdiff
path: root/embassy-stm32/src/can
diff options
context:
space:
mode:
authorJomer.Dev <[email protected]>2025-11-27 20:53:02 +0100
committerJomer.Dev <[email protected]>2025-11-27 20:53:02 +0100
commite34c43d72b77e78cb971a73c59efa3e746db331f (patch)
treee52817fd2c27e9b945082e35e6fe82a5cf000285 /embassy-stm32/src/can
parentb8afe4ff5fd590903861e44224171f37b9ae6e62 (diff)
Add error messages to calc_can_timings
Diffstat (limited to 'embassy-stm32/src/can')
-rw-r--r--embassy-stm32/src/can/enums.rs37
-rw-r--r--embassy-stm32/src/can/util.rs27
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))]
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..e93fe607d 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,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
20pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> { 22pub 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,