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}