embassy_stm32/can/fd/
config.rs

1//! Configuration for FDCAN Module
2// Note: This file is copied and modified from fdcan crate by Richard Meadows
3
4use core::num::{NonZeroU16, NonZeroU8};
5
6/// Configures the bit timings.
7///
8/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
9/// parameters as follows:
10///
11/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
12///   This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
13/// - *Sample Point*: Should normally be left at the default value of 87.5%.
14/// - *SJW*: Should normally be left at the default value of 1.
15///
16/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
17/// parameter to this method.
18#[derive(Clone, Copy, Debug)]
19pub struct NominalBitTiming {
20    /// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
21    /// time is built up from a multiple of this quanta. Valid values are 1 to 512.
22    pub prescaler: NonZeroU16,
23    /// Valid values are 1 to 128.
24    pub seg1: NonZeroU8,
25    /// Valid values are 1 to 255.
26    pub seg2: NonZeroU8,
27    /// Valid values are 1 to 128.
28    pub sync_jump_width: NonZeroU8,
29}
30impl NominalBitTiming {
31    #[inline]
32    pub(crate) fn nbrp(&self) -> u16 {
33        u16::from(self.prescaler) & 0x1FF
34    }
35    #[inline]
36    pub(crate) fn ntseg1(&self) -> u8 {
37        u8::from(self.seg1)
38    }
39    #[inline]
40    pub(crate) fn ntseg2(&self) -> u8 {
41        u8::from(self.seg2) & 0x7F
42    }
43    #[inline]
44    pub(crate) fn nsjw(&self) -> u8 {
45        u8::from(self.sync_jump_width) & 0x7F
46    }
47}
48
49impl Default for NominalBitTiming {
50    #[inline]
51    fn default() -> Self {
52        // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a NBTP
53        // register value of 0x0600_0A03
54        Self {
55            prescaler: NonZeroU16::new(1).unwrap(),
56            seg1: NonZeroU8::new(11).unwrap(),
57            seg2: NonZeroU8::new(4).unwrap(),
58            sync_jump_width: NonZeroU8::new(4).unwrap(),
59        }
60    }
61}
62
63/// Configures the data bit timings for the FdCan Variable Bitrates.
64/// This is not used when frame_transmit is set to anything other than AllowFdCanAndBRS.
65#[derive(Clone, Copy, Debug)]
66pub struct DataBitTiming {
67    /// Tranceiver Delay Compensation
68    pub transceiver_delay_compensation: bool,
69    ///  The value by which the oscillator frequency is divided to generate the bit time quanta. The bit
70    ///  time is built up from a multiple of this quanta. Valid values for the Baud Rate Prescaler are 1
71    ///  to 31.
72    pub prescaler: NonZeroU16,
73    /// Valid values are 1 to 31.
74    pub seg1: NonZeroU8,
75    /// Valid values are 1 to 15.
76    pub seg2: NonZeroU8,
77    /// Must always be smaller than DTSEG2, valid values are 1 to 15.
78    pub sync_jump_width: NonZeroU8,
79}
80impl DataBitTiming {
81    // #[inline]
82    // fn tdc(&self) -> u8 {
83    //     let tsd = self.transceiver_delay_compensation as u8;
84    //     //TODO: stm32g4 does not export the TDC field
85    //     todo!()
86    // }
87    #[inline]
88    pub(crate) fn dbrp(&self) -> u8 {
89        (u16::from(self.prescaler) & 0x001F) as u8
90    }
91    #[inline]
92    pub(crate) fn dtseg1(&self) -> u8 {
93        u8::from(self.seg1) & 0x1F
94    }
95    #[inline]
96    pub(crate) fn dtseg2(&self) -> u8 {
97        u8::from(self.seg2) & 0x0F
98    }
99    #[inline]
100    pub(crate) fn dsjw(&self) -> u8 {
101        u8::from(self.sync_jump_width) & 0x0F
102    }
103}
104
105impl Default for DataBitTiming {
106    #[inline]
107    fn default() -> Self {
108        // Kernel Clock 8MHz, Bit rate: 500kbit/s. Corresponds to a DBTP
109        // register value of 0x0000_0A33
110        Self {
111            transceiver_delay_compensation: false,
112            prescaler: NonZeroU16::new(1).unwrap(),
113            seg1: NonZeroU8::new(11).unwrap(),
114            seg2: NonZeroU8::new(4).unwrap(),
115            sync_jump_width: NonZeroU8::new(4).unwrap(),
116        }
117    }
118}
119
120/// Configures which modes to use
121/// Individual headers can contain a desire to be send via FdCan
122/// or use Bit rate switching. But if this general setting does not allow
123/// that, only classic CAN is used instead.
124#[derive(Clone, Copy, Debug)]
125pub enum FrameTransmissionConfig {
126    /// Only allow Classic CAN message Frames
127    ClassicCanOnly,
128    /// Allow (non-brs) FdCAN Message Frames
129    AllowFdCan,
130    /// Allow FdCAN Message Frames and allow Bit Rate Switching
131    AllowFdCanAndBRS,
132}
133
134///
135#[derive(Clone, Copy, Debug)]
136pub enum ClockDivider {
137    /// Divide by 1
138    _1 = 0b0000,
139    /// Divide by 2
140    _2 = 0b0001,
141    /// Divide by 4
142    _4 = 0b0010,
143    /// Divide by 6
144    _6 = 0b0011,
145    /// Divide by 8
146    _8 = 0b0100,
147    /// Divide by 10
148    _10 = 0b0101,
149    /// Divide by 12
150    _12 = 0b0110,
151    /// Divide by 14
152    _14 = 0b0111,
153    /// Divide by 16
154    _16 = 0b1000,
155    /// Divide by 18
156    _18 = 0b1001,
157    /// Divide by 20
158    _20 = 0b1010,
159    /// Divide by 22
160    _22 = 0b1011,
161    /// Divide by 24
162    _24 = 0b1100,
163    /// Divide by 26
164    _26 = 0b1101,
165    /// Divide by 28
166    _28 = 0b1110,
167    /// Divide by 30
168    _30 = 0b1111,
169}
170
171/// Prescaler of the Timestamp counter
172#[derive(Clone, Copy, Debug)]
173pub enum TimestampPrescaler {
174    /// 1
175    _1 = 1,
176    /// 2
177    _2 = 2,
178    /// 3
179    _3 = 3,
180    /// 4
181    _4 = 4,
182    /// 5
183    _5 = 5,
184    /// 6
185    _6 = 6,
186    /// 7
187    _7 = 7,
188    /// 8
189    _8 = 8,
190    /// 9
191    _9 = 9,
192    /// 10
193    _10 = 10,
194    /// 11
195    _11 = 11,
196    /// 12
197    _12 = 12,
198    /// 13
199    _13 = 13,
200    /// 14
201    _14 = 14,
202    /// 15
203    _15 = 15,
204    /// 16
205    _16 = 16,
206}
207
208/// Selects the source of the Timestamp counter
209#[derive(Clone, Copy, Debug)]
210pub enum TimestampSource {
211    /// The Timestamp counter is disabled
212    None,
213    /// Using the FdCan input clock as the Timstamp counter's source,
214    /// and using a specific prescaler
215    Prescaler(TimestampPrescaler),
216    /// Using TIM3 as a source
217    FromTIM3,
218}
219
220/// How to handle frames in the global filter
221#[derive(Clone, Copy, Debug)]
222pub enum NonMatchingFilter {
223    /// Frames will go to Fifo0 when they do no match any specific filter
224    IntoRxFifo0 = 0b00,
225    /// Frames will go to Fifo1 when they do no match any specific filter
226    IntoRxFifo1 = 0b01,
227    /// Frames will be rejected when they do not match any specific filter
228    Reject = 0b11,
229}
230
231/// How to handle frames which do not match a specific filter
232#[derive(Clone, Copy, Debug)]
233pub struct GlobalFilter {
234    /// How to handle non-matching standard frames
235    pub handle_standard_frames: NonMatchingFilter,
236
237    /// How to handle non-matching extended frames
238    pub handle_extended_frames: NonMatchingFilter,
239
240    /// How to handle remote standard frames
241    pub reject_remote_standard_frames: bool,
242
243    /// How to handle remote extended frames
244    pub reject_remote_extended_frames: bool,
245}
246impl GlobalFilter {
247    /// Reject all non-matching and remote frames
248    pub const fn reject_all() -> Self {
249        Self {
250            handle_standard_frames: NonMatchingFilter::Reject,
251            handle_extended_frames: NonMatchingFilter::Reject,
252            reject_remote_standard_frames: true,
253            reject_remote_extended_frames: true,
254        }
255    }
256
257    /// How to handle non-matching standard frames
258    pub const fn set_handle_standard_frames(mut self, filter: NonMatchingFilter) -> Self {
259        self.handle_standard_frames = filter;
260        self
261    }
262    /// How to handle non-matching exteded frames
263    pub const fn set_handle_extended_frames(mut self, filter: NonMatchingFilter) -> Self {
264        self.handle_extended_frames = filter;
265        self
266    }
267    /// How to handle remote standard frames
268    pub const fn set_reject_remote_standard_frames(mut self, filter: bool) -> Self {
269        self.reject_remote_standard_frames = filter;
270        self
271    }
272    /// How to handle remote extended frames
273    pub const fn set_reject_remote_extended_frames(mut self, filter: bool) -> Self {
274        self.reject_remote_extended_frames = filter;
275        self
276    }
277}
278impl Default for GlobalFilter {
279    #[inline]
280    fn default() -> Self {
281        Self {
282            handle_standard_frames: NonMatchingFilter::IntoRxFifo0,
283            handle_extended_frames: NonMatchingFilter::IntoRxFifo0,
284            reject_remote_standard_frames: false,
285            reject_remote_extended_frames: false,
286        }
287    }
288}
289
290/// TX buffer operation mode
291#[derive(Clone, Copy, PartialEq, Eq, Debug)]
292pub enum TxBufferMode {
293    /// TX FIFO operation - In this mode CAN frames are trasmitted strictly in write order.
294    Fifo,
295    /// TX priority queue operation - In this mode CAN frames are transmitted according to CAN priority.
296    Priority,
297}
298
299impl From<TxBufferMode> for crate::pac::can::vals::Tfqm {
300    fn from(value: TxBufferMode) -> Self {
301        match value {
302            TxBufferMode::Priority => Self::QUEUE,
303            TxBufferMode::Fifo => Self::FIFO,
304        }
305    }
306}
307
308impl From<crate::pac::can::vals::Tfqm> for TxBufferMode {
309    fn from(value: crate::pac::can::vals::Tfqm) -> Self {
310        match value {
311            crate::pac::can::vals::Tfqm::QUEUE => Self::Priority,
312            crate::pac::can::vals::Tfqm::FIFO => Self::Fifo,
313        }
314    }
315}
316
317/// FdCan Config Struct
318#[derive(Clone, Copy, Debug)]
319pub struct FdCanConfig {
320    /// Nominal Bit Timings
321    pub nbtr: NominalBitTiming,
322    /// (Variable) Data Bit Timings
323    pub dbtr: DataBitTiming,
324    /// Enables or disables automatic retransmission of messages
325    ///
326    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
327    /// util it can be sent. Otherwise, it will try only once to send each frame.
328    ///
329    /// Automatic retransmission is enabled by default.
330    pub automatic_retransmit: bool,
331    /// Enabled or disables the pausing between transmissions
332    ///
333    /// This feature looses up burst transmissions coming from a single node and it protects against
334    /// "babbling idiot" scenarios where the application program erroneously requests too many
335    /// transmissions.
336    pub transmit_pause: bool,
337    /// Enabled or disables the pausing between transmissions
338    ///
339    /// This feature looses up burst transmissions coming from a single node and it protects against
340    /// "babbling idiot" scenarios where the application program erroneously requests too many
341    /// transmissions.
342    pub frame_transmit: FrameTransmissionConfig,
343    /// Non Isoe Mode
344    /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
345    /// FD Specification V1.0.
346    pub non_iso_mode: bool,
347    /// Edge Filtering: Two consecutive dominant tq required to detect an edge for hard synchronization
348    pub edge_filtering: bool,
349    /// Enables protocol exception handling
350    pub protocol_exception_handling: bool,
351    /// Sets the general clock divider for this FdCAN instance
352    pub clock_divider: ClockDivider,
353    /// Sets the timestamp source
354    pub timestamp_source: TimestampSource,
355    /// Configures the Global Filter
356    pub global_filter: GlobalFilter,
357    /// TX buffer mode (FIFO or priority queue)
358    pub tx_buffer_mode: TxBufferMode,
359}
360
361impl FdCanConfig {
362    /// Configures the bit timings.
363    #[inline]
364    pub const fn set_nominal_bit_timing(mut self, btr: NominalBitTiming) -> Self {
365        self.nbtr = btr;
366        self
367    }
368
369    /// Configures the bit timings.
370    #[inline]
371    pub const fn set_data_bit_timing(mut self, btr: DataBitTiming) -> Self {
372        self.dbtr = btr;
373        self
374    }
375
376    /// Enables or disables automatic retransmission of messages
377    ///
378    /// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
379    /// util it can be sent. Otherwise, it will try only once to send each frame.
380    ///
381    /// Automatic retransmission is enabled by default.
382    #[inline]
383    pub const fn set_automatic_retransmit(mut self, enabled: bool) -> Self {
384        self.automatic_retransmit = enabled;
385        self
386    }
387
388    /// Enabled or disables the pausing between transmissions
389    ///
390    /// This feature looses up burst transmissions coming from a single node and it protects against
391    /// "babbling idiot" scenarios where the application program erroneously requests too many
392    /// transmissions.
393    #[inline]
394    pub const fn set_transmit_pause(mut self, enabled: bool) -> Self {
395        self.transmit_pause = enabled;
396        self
397    }
398
399    /// If this is set, the FDCAN uses the CAN FD frame format as specified by the Bosch CAN
400    /// FD Specification V1.0.
401    #[inline]
402    pub const fn set_non_iso_mode(mut self, enabled: bool) -> Self {
403        self.non_iso_mode = enabled;
404        self
405    }
406
407    /// Two consecutive dominant tq required to detect an edge for hard synchronization
408    #[inline]
409    pub const fn set_edge_filtering(mut self, enabled: bool) -> Self {
410        self.edge_filtering = enabled;
411        self
412    }
413
414    /// Sets the allowed transmission types for messages.
415    #[inline]
416    pub const fn set_frame_transmit(mut self, fts: FrameTransmissionConfig) -> Self {
417        self.frame_transmit = fts;
418        self
419    }
420
421    /// Enables protocol exception handling
422    #[inline]
423    pub const fn set_protocol_exception_handling(mut self, peh: bool) -> Self {
424        self.protocol_exception_handling = peh;
425        self
426    }
427
428    /// Sets the general clock divider for this FdCAN instance
429    #[inline]
430    pub const fn set_clock_divider(mut self, div: ClockDivider) -> Self {
431        self.clock_divider = div;
432        self
433    }
434
435    /// Sets the timestamp source
436    #[inline]
437    pub const fn set_timestamp_source(mut self, tss: TimestampSource) -> Self {
438        self.timestamp_source = tss;
439        self
440    }
441
442    /// Sets the global filter settings
443    #[inline]
444    pub const fn set_global_filter(mut self, filter: GlobalFilter) -> Self {
445        self.global_filter = filter;
446        self
447    }
448
449    /// Sets the TX buffer mode (FIFO or priority queue)
450    #[inline]
451    pub const fn set_tx_buffer_mode(mut self, txbm: TxBufferMode) -> Self {
452        self.tx_buffer_mode = txbm;
453        self
454    }
455}
456
457impl Default for FdCanConfig {
458    #[inline]
459    fn default() -> Self {
460        Self {
461            nbtr: NominalBitTiming::default(),
462            dbtr: DataBitTiming::default(),
463            automatic_retransmit: true,
464            transmit_pause: false,
465            frame_transmit: FrameTransmissionConfig::ClassicCanOnly,
466            non_iso_mode: false,
467            edge_filtering: false,
468            protocol_exception_handling: true,
469            clock_divider: ClockDivider::_1,
470            timestamp_source: TimestampSource::None,
471            global_filter: GlobalFilter::default(),
472            tx_buffer_mode: TxBufferMode::Priority,
473        }
474    }
475}