diff --git a/mcan/CHANGELOG.md b/mcan/CHANGELOG.md index 3875446..a073e12 100644 --- a/mcan/CHANGELOG.md +++ b/mcan/CHANGELOG.md @@ -3,6 +3,7 @@ Tagging in git follows a pattern: `mcan/`. ## [Unreleased] +- Added support for fractional baudrates (#59) ## [0.7.0] - 2025-04-23 diff --git a/mcan/src/config.rs b/mcan/src/config.rs index bc0c389..a296deb 100644 --- a/mcan/src/config.rs +++ b/mcan/src/config.rs @@ -68,14 +68,22 @@ pub struct BitTiming { /// MCAN peripheral is divisible into time quanta such that the bit time /// determined by `phase_seg_1` and `phase_seg_2` is a whole number of time /// quanta. + /// + /// When [`Self::allow_fractional`] is selected, the real bitrate + /// is allowed to be up to 0.05% off (Which is within tolerance) pub bitrate: HertzU32, + /// Allows for fractional bitrates where there may be no perfect + /// combination of bit-timing parameters. This is useful for bitrates + /// like 83.3kbps where some tolerance is allowed (Up to 0.05%). + pub allow_fractional: bool, } impl BitTiming { /// Create an instance /// /// Nominal bitrate value must be provided, all other settings come - /// pre-populated with default values. + /// pre-populated with default values. No fractional bitrates + /// are allowed. pub fn new(bitrate: HertzU32) -> Self { Self { // Note: SWJ and {N,D}TSEG{1,2} defaults come from reset values @@ -83,6 +91,7 @@ impl BitTiming { phase_seg_1: 0xB, phase_seg_2: 0x4, bitrate, + allow_fractional: false, } } } @@ -199,19 +208,25 @@ impl BitTiming { let f_out = self.bitrate; let bit_time_quanta = self.time_quanta_per_bit(); let f_q = f_out * bit_time_quanta; - if let Some(0) = f_can.to_Hz().checked_rem(f_q.to_Hz()) { - let prescaler = f_can / f_q; - if !valid.prescaler.contains(&prescaler) { - Err(BitTimingError::PrescalerOutOfRange(valid.prescaler.clone())) - } else { - Ok(prescaler as u16) - } + let max_tolerance = if self.allow_fractional { + self.bitrate.to_Hz() / 2000 // 0.05% tolerance } else { - Err(BitTimingError::NoValidPrescaler { + 0 + }; + match f_can.to_Hz().checked_rem(f_q.to_Hz()) { + Some(x) if x <= max_tolerance => { + let prescaler = f_can / f_q; + if !valid.prescaler.contains(&prescaler) { + Err(BitTimingError::PrescalerOutOfRange(valid.prescaler.clone())) + } else { + Ok(prescaler as u16) + } + } + _ => Err(BitTimingError::NoValidPrescaler { can_clock: f_can, bitrate: f_out, bit_time_quanta, - }) + }), } } }