aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/can/fdcan.rs714
-rw-r--r--embassy-stm32/src/rcc/h.rs7
2 files changed, 706 insertions, 15 deletions
diff --git a/embassy-stm32/src/can/fdcan.rs b/embassy-stm32/src/can/fdcan.rs
index 0cc2559cf..faf4af73f 100644
--- a/embassy-stm32/src/can/fdcan.rs
+++ b/embassy-stm32/src/can/fdcan.rs
@@ -1,14 +1,577 @@
1use crate::peripherals; 1use core::future::poll_fn;
2use core::marker::PhantomData;
3use core::ops::{Deref, DerefMut};
4use core::task::Poll;
5
6use cfg_if::cfg_if;
7use embassy_hal_internal::{into_ref, PeripheralRef};
8pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader};
9pub use fdcan::id::{ExtendedId, Id, StandardId};
10use fdcan::message_ram::RegisterBlock;
11use fdcan::{self, LastErrorCode};
12pub use fdcan::{config, filter};
13
14use crate::gpio::sealed::AFType;
15use crate::interrupt::typelevel::Interrupt;
16use crate::rcc::RccPeripheral;
17use crate::{interrupt, peripherals, Peripheral};
18
19pub mod enums;
20use enums::*;
21pub mod util;
22
23/// CAN Frame returned by read
24pub struct RxFrame {
25 /// CAN Header info: frame ID, data length and other meta
26 pub header: RxFrameInfo,
27 /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
28 pub data: Data,
29 /// Reception time.
30 #[cfg(feature = "time")]
31 pub timestamp: embassy_time::Instant,
32}
33
34/// CAN frame used for write
35pub struct TxFrame {
36 /// CAN Header info: frame ID, data length and other meta
37 pub header: TxFrameHeader,
38 /// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
39 pub data: Data,
40}
41
42impl TxFrame {
43 /// Create new TX frame from header and data
44 pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> {
45 if data.len() < header.len as usize {
46 return None;
47 }
48
49 let Some(data) = Data::new(data) else { return None };
50
51 Some(TxFrame { header, data })
52 }
53
54 fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> {
55 let mut data = [0u8; 64];
56
57 for i in 0..data32.len() {
58 data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes());
59 }
60
61 let Some(data) = Data::new(&data) else { return None };
62
63 Some(TxFrame { header, data })
64 }
65
66 /// Access frame data. Slice length will match header.
67 pub fn data(&self) -> &[u8] {
68 &self.data.bytes[..(self.header.len as usize)]
69 }
70}
71
72impl RxFrame {
73 pub(crate) fn new(
74 header: RxFrameInfo,
75 data: &[u8],
76 #[cfg(feature = "time")] timestamp: embassy_time::Instant,
77 ) -> Self {
78 let data = Data::new(&data).unwrap_or_else(|| Data::empty());
79
80 RxFrame {
81 header,
82 data,
83 #[cfg(feature = "time")]
84 timestamp,
85 }
86 }
87
88 /// Access frame data. Slice length will match header.
89 pub fn data(&self) -> &[u8] {
90 &self.data.bytes[..(self.header.len as usize)]
91 }
92}
93
94/// Payload of a (FD)CAN data frame.
95///
96/// Contains 0 to 64 Bytes of data.
97#[derive(Debug, Copy, Clone)]
98pub struct Data {
99 pub(crate) bytes: [u8; 64],
100}
101
102impl Data {
103 /// Creates a data payload from a raw byte slice.
104 ///
105 /// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
106 /// cannot be represented with an FDCAN DLC.
107 pub fn new(data: &[u8]) -> Option<Self> {
108 if !Data::is_valid_len(data.len()) {
109 return None;
110 }
111
112 let mut bytes = [0; 64];
113 bytes[..data.len()].copy_from_slice(data);
114
115 Some(Self { bytes })
116 }
117
118 /// Raw read access to data.
119 pub fn raw(&self) -> &[u8] {
120 &self.bytes
121 }
122
123 /// Checks if the length can be encoded in FDCAN DLC field.
124 pub const fn is_valid_len(len: usize) -> bool {
125 match len {
126 0..=8 => true,
127 12 => true,
128 16 => true,
129 20 => true,
130 24 => true,
131 32 => true,
132 48 => true,
133 64 => true,
134 _ => false,
135 }
136 }
137
138 /// Creates an empty data payload containing 0 bytes.
139 #[inline]
140 pub const fn empty() -> Self {
141 Self { bytes: [0; 64] }
142 }
143}
144
145/// Interrupt handler channel 0.
146pub struct IT0InterruptHandler<T: Instance> {
147 _phantom: PhantomData<T>,
148}
149
150// We use IT0 for everything currently
151impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
152 unsafe fn on_interrupt() {
153 let regs = T::regs();
154
155 let ir = regs.ir().read();
156
157 if ir.tc() {
158 regs.ir().write(|w| w.set_tc(true));
159 T::state().tx_waker.wake();
160 }
161
162 if ir.tefn() {
163 regs.ir().write(|w| w.set_tefn(true));
164 T::state().tx_waker.wake();
165 }
166
167 if ir.ped() || ir.pea() {
168 regs.ir().write(|w| {
169 w.set_ped(true);
170 w.set_pea(true);
171 });
172 }
173
174 if ir.rfn(0) {
175 regs.ir().write(|w| w.set_rfn(0, true));
176 T::state().rx_waker.wake();
177 }
178
179 if ir.rfn(1) {
180 regs.ir().write(|w| w.set_rfn(1, true));
181 T::state().rx_waker.wake();
182 }
183 }
184}
185
186/// Interrupt handler channel 1.
187pub struct IT1InterruptHandler<T: Instance> {
188 _phantom: PhantomData<T>,
189}
190
191impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1InterruptHandler<T> {
192 unsafe fn on_interrupt() {}
193}
194
195impl BusError {
196 fn try_from(lec: LastErrorCode) -> Option<BusError> {
197 match lec {
198 LastErrorCode::AckError => Some(BusError::Acknowledge),
199 // `0` data bit encodes a dominant state. `1` data bit is recessive.
200 // Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1
201 LastErrorCode::Bit0Error => Some(BusError::BitRecessive),
202 LastErrorCode::Bit1Error => Some(BusError::BitDominant),
203 LastErrorCode::CRCError => Some(BusError::Crc),
204 LastErrorCode::FormError => Some(BusError::Form),
205 LastErrorCode::StuffError => Some(BusError::Stuff),
206 _ => None,
207 }
208 }
209}
210
211/// Operating modes trait
212pub trait FdcanOperatingMode {}
213impl FdcanOperatingMode for fdcan::PoweredDownMode {}
214impl FdcanOperatingMode for fdcan::ConfigMode {}
215impl FdcanOperatingMode for fdcan::InternalLoopbackMode {}
216impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {}
217impl FdcanOperatingMode for fdcan::NormalOperationMode {}
218impl FdcanOperatingMode for fdcan::RestrictedOperationMode {}
219impl FdcanOperatingMode for fdcan::BusMonitoringMode {}
220impl FdcanOperatingMode for fdcan::TestMode {}
221
222/// FDCAN Instance
223pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> {
224 /// Reference to internals.
225 pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>,
226 ns_per_timer_tick: u64, // For FDCAN internal timer
227}
228
229fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 {
230 match mode {
231 // Use timestamp from Rx FIFO to adjust timestamp reported to user
232 config::FrameTransmissionConfig::ClassicCanOnly => {
233 let freq = T::frequency();
234 let prescale: u64 =
235 ({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
236 1_000_000_000 as u64 / (freq.0 as u64 * prescale)
237 }
238 // For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
239 // timer3 instead which is too hard to do from this module.
240 _ => 0,
241 }
242}
243
244#[cfg(feature = "time")]
245fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant {
246 let now_embassy = embassy_time::Instant::now();
247 if ns_per_timer_tick == 0 {
248 return now_embassy;
249 }
250 let now_can = { T::regs().tscv().read().tsc() };
251 let delta = now_can.overflowing_sub(ts_val).0 as u64;
252 let ns = ns_per_timer_tick * delta as u64;
253 now_embassy - embassy_time::Duration::from_nanos(ns)
254}
255
256fn curr_error<T: Instance>() -> Option<BusError> {
257 let err = { T::regs().psr().read() };
258 if err.bo() {
259 return Some(BusError::BusOff);
260 } else if err.ep() {
261 return Some(BusError::BusPassive);
262 } else if err.ew() {
263 return Some(BusError::BusWarning);
264 } else {
265 cfg_if! {
266 if #[cfg(stm32h7)] {
267 let lec = err.lec();
268 } else {
269 let lec = err.lec().to_bits();
270 }
271 }
272 if let Ok(err) = LastErrorCode::try_from(lec) {
273 return BusError::try_from(err);
274 }
275 }
276 None
277}
278
279impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
280 /// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
281 /// You must call [Fdcan::enable_non_blocking] to use the peripheral.
282 pub fn new(
283 peri: impl Peripheral<P = T> + 'd,
284 rx: impl Peripheral<P = impl RxPin<T>> + 'd,
285 tx: impl Peripheral<P = impl TxPin<T>> + 'd,
286 _irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
287 + interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
288 + 'd,
289 ) -> Fdcan<'d, T, fdcan::ConfigMode> {
290 into_ref!(peri, rx, tx);
291
292 rx.set_as_af(rx.af_num(), AFType::Input);
293 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
294
295 T::enable_and_reset();
296
297 rx.set_as_af(rx.af_num(), AFType::Input);
298 tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
299
300 let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode();
301
302 T::configure_msg_ram();
303 unsafe {
304 // Enable timestamping
305 #[cfg(not(stm32h7))]
306 T::regs()
307 .tscc()
308 .write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
309 #[cfg(stm32h7)]
310 T::regs().tscc().write(|w| w.set_tss(0x01));
311
312 T::IT0Interrupt::unpend(); // Not unsafe
313 T::IT0Interrupt::enable();
314
315 T::IT1Interrupt::unpend(); // Not unsafe
316 T::IT1Interrupt::enable();
317
318 // this isn't really documented in the reference manual
319 // but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire
320 T::regs().txbtie().write(|w| w.0 = 0xffff_ffff);
321 }
322
323 can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg);
324 can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg);
325 can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete);
326 can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true);
327 can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true);
328
329 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit);
330 Self { can, ns_per_timer_tick }
331 }
332
333 /// Configures the bit timings calculated from supplied bitrate.
334 pub fn set_bitrate(&mut self, bitrate: u32) {
335 let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
336 self.can.set_nominal_bit_timing(config::NominalBitTiming {
337 sync_jump_width: bit_timing.sync_jump_width,
338 prescaler: bit_timing.prescaler,
339 seg1: bit_timing.seg1,
340 seg2: bit_timing.seg2,
341 });
342 }
343}
344
345macro_rules! impl_transition {
346 ($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => {
347 impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> {
348 /// Transition from $from_mode:ident mode to $to_mode:ident mode
349 pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> {
350 let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit);
351 Fdcan {
352 can: self.can.$func(),
353 ns_per_timer_tick,
354 }
355 }
356 }
357 };
358}
359
360impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode);
361impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode);
362
363impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal);
364impl_transition!(
365 ConfigMode,
366 ExternalLoopbackMode,
367 into_external_loopback_mode,
368 into_external_loopback
369);
370impl_transition!(
371 ConfigMode,
372 InternalLoopbackMode,
373 into_internal_loopback_mode,
374 into_internal_loopback
375);
376
377impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M>
378where
379 M: fdcan::Transmit,
380 M: fdcan::Receive,
381{
382 /// Queues the message to be sent but exerts backpressure. If a lower-priority
383 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
384 /// can be replaced, this call asynchronously waits for a frame to be successfully
385 /// transmitted, then tries again.
386 pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> {
387 poll_fn(|cx| {
388 T::state().tx_waker.register(cx.waker());
389 if let Ok(dropped) = self
390 .can
391 .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| {
392 TxFrame::from_preserved(hdr, data32)
393 })
394 {
395 return Poll::Ready(dropped.flatten());
396 }
397
398 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
399 // to clear.
400 Poll::Pending
401 })
402 .await
403 }
404
405 /// Flush one of the TX mailboxes.
406 pub async fn flush(&self, mb: fdcan::Mailbox) {
407 poll_fn(|cx| {
408 T::state().tx_waker.register(cx.waker());
409
410 let idx: u8 = mb.into();
411 let idx = 1 << idx;
412 if !T::regs().txbrp().read().trp(idx) {
413 return Poll::Ready(());
414 }
415
416 Poll::Pending
417 })
418 .await;
419 }
420
421 /// Returns the next received message frame
422 pub async fn read(&mut self) -> Result<RxFrame, BusError> {
423 poll_fn(|cx| {
424 T::state().err_waker.register(cx.waker());
425 T::state().rx_waker.register(cx.waker());
426
427 let mut buffer: [u8; 64] = [0; 64];
428 if let Ok(rx) = self.can.receive0(&mut buffer) {
429 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
430 // TODO: report overrun?
431 // for now we just drop it
432
433 let frame: RxFrame = RxFrame::new(
434 rx.unwrap(),
435 &buffer,
436 #[cfg(feature = "time")]
437 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
438 );
439 return Poll::Ready(Ok(frame));
440 } else if let Ok(rx) = self.can.receive1(&mut buffer) {
441 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
442 // TODO: report overrun?
443 // for now we just drop it
444
445 let frame: RxFrame = RxFrame::new(
446 rx.unwrap(),
447 &buffer,
448 #[cfg(feature = "time")]
449 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
450 );
451 return Poll::Ready(Ok(frame));
452 } else if let Some(err) = curr_error::<T>() {
453 // TODO: this is probably wrong
454 return Poll::Ready(Err(err));
455 }
456 Poll::Pending
457 })
458 .await
459 }
460
461 /// Split instance into separate Tx(write) and Rx(read) portions
462 pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) {
463 let (mut _control, tx, rx0, rx1) = self.can.split_by_ref();
464 (
465 FdcanTx { _control, tx },
466 FdcanRx {
467 rx0,
468 rx1,
469 ns_per_timer_tick: self.ns_per_timer_tick,
470 },
471 )
472 }
473}
474
475/// FDCAN Tx only Instance
476pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> {
477 _control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>,
478 tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>,
479}
480
481impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> {
482 /// Queues the message to be sent but exerts backpressure. If a lower-priority
483 /// frame is dropped from the mailbox, it is returned. If no lower-priority frames
484 /// can be replaced, this call asynchronously waits for a frame to be successfully
485 /// transmitted, then tries again.
486 pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> {
487 poll_fn(|cx| {
488 T::state().tx_waker.register(cx.waker());
489 if let Ok(dropped) = self
490 .tx
491 .transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| {
492 TxFrame::from_preserved(hdr, data32)
493 })
494 {
495 return Poll::Ready(dropped.flatten());
496 }
497
498 // Couldn't replace any lower priority frames. Need to wait for some mailboxes
499 // to clear.
500 Poll::Pending
501 })
502 .await
503 }
504}
505
506/// FDCAN Rx only Instance
507#[allow(dead_code)]
508pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> {
509 rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>,
510 rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>,
511 ns_per_timer_tick: u64, // For FDCAN internal timer
512}
513
514impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> {
515 /// Returns the next received message frame
516 pub async fn read(&mut self) -> Result<RxFrame, BusError> {
517 poll_fn(|cx| {
518 T::state().err_waker.register(cx.waker());
519 T::state().rx_waker.register(cx.waker());
520
521 let mut buffer: [u8; 64] = [0; 64];
522 if let Ok(rx) = self.rx0.receive(&mut buffer) {
523 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
524 // TODO: report overrun?
525 // for now we just drop it
526 let frame: RxFrame = RxFrame::new(
527 rx.unwrap(),
528 &buffer,
529 #[cfg(feature = "time")]
530 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
531 );
532 return Poll::Ready(Ok(frame));
533 } else if let Ok(rx) = self.rx1.receive(&mut buffer) {
534 // rx: fdcan::ReceiveOverrun<RxFrameInfo>
535 // TODO: report overrun?
536 // for now we just drop it
537 let frame: RxFrame = RxFrame::new(
538 rx.unwrap(),
539 &buffer,
540 #[cfg(feature = "time")]
541 calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
542 );
543 return Poll::Ready(Ok(frame));
544 } else if let Some(err) = curr_error::<T>() {
545 // TODO: this is probably wrong
546 return Poll::Ready(Err(err));
547 }
548
549 Poll::Pending
550 })
551 .await
552 }
553}
554impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> {
555 type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>;
556
557 fn deref(&self) -> &Self::Target {
558 &self.can
559 }
560}
561
562impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> {
563 fn deref_mut(&mut self) -> &mut Self::Target {
564 &mut self.can
565 }
566}
2 567
3pub(crate) mod sealed { 568pub(crate) mod sealed {
4 use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
5 use embassy_sync::channel::Channel;
6 use embassy_sync::waitqueue::AtomicWaker; 569 use embassy_sync::waitqueue::AtomicWaker;
7 570
8 pub struct State { 571 pub struct State {
9 pub tx_waker: AtomicWaker, 572 pub tx_waker: AtomicWaker,
10 pub err_waker: AtomicWaker, 573 pub err_waker: AtomicWaker,
11 pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>, 574 pub rx_waker: AtomicWaker,
12 } 575 }
13 576
14 impl State { 577 impl State {
@@ -16,25 +579,122 @@ pub(crate) mod sealed {
16 Self { 579 Self {
17 tx_waker: AtomicWaker::new(), 580 tx_waker: AtomicWaker::new(),
18 err_waker: AtomicWaker::new(), 581 err_waker: AtomicWaker::new(),
19 rx_queue: Channel::new(), 582 rx_waker: AtomicWaker::new(),
20 } 583 }
21 } 584 }
22 } 585 }
23 586
24 pub trait Instance { 587 pub trait Instance {
588 const REGISTERS: *mut fdcan::RegisterBlock;
589 const MSG_RAM: *mut fdcan::message_ram::RegisterBlock;
590 const MSG_RAM_OFFSET: usize;
591
25 fn regs() -> &'static crate::pac::can::Fdcan; 592 fn regs() -> &'static crate::pac::can::Fdcan;
26 fn state() -> &'static State; 593 fn state() -> &'static State;
594
595 #[cfg(not(stm32h7))]
596 fn configure_msg_ram() {}
597
598 #[cfg(stm32h7)]
599 fn configure_msg_ram() {
600 let r = Self::regs();
601
602 use fdcan::message_ram::*;
603 let mut offset_words = Self::MSG_RAM_OFFSET as u16;
604
605 // 11-bit filter
606 r.sidfc().modify(|w| w.set_flssa(offset_words));
607 offset_words += STANDARD_FILTER_MAX as u16;
608
609 // 29-bit filter
610 r.xidfc().modify(|w| w.set_flesa(offset_words));
611 offset_words += 2 * EXTENDED_FILTER_MAX as u16;
612
613 // Rx FIFO 0 and 1
614 for i in 0..=1 {
615 r.rxfc(i).modify(|w| {
616 w.set_fsa(offset_words);
617 w.set_fs(RX_FIFO_MAX);
618 w.set_fwm(RX_FIFO_MAX);
619 });
620 offset_words += 18 * RX_FIFO_MAX as u16;
621 }
622
623 // Rx buffer - see below
624 // Tx event FIFO
625 r.txefc().modify(|w| {
626 w.set_efsa(offset_words);
627 w.set_efs(TX_EVENT_MAX);
628 w.set_efwm(TX_EVENT_MAX);
629 });
630 offset_words += 2 * TX_EVENT_MAX as u16;
631
632 // Tx buffers
633 r.txbc().modify(|w| {
634 w.set_tbsa(offset_words);
635 w.set_tfqs(TX_FIFO_MAX);
636 });
637 offset_words += 18 * TX_FIFO_MAX as u16;
638
639 // Rx Buffer - not used
640 r.rxbc().modify(|w| {
641 w.set_rbsa(offset_words);
642 });
643
644 // TX event FIFO?
645 // Trigger memory?
646
647 // Set the element sizes to 16 bytes
648 r.rxesc().modify(|w| {
649 w.set_rbds(0b111);
650 for i in 0..=1 {
651 w.set_fds(i, 0b111);
652 }
653 });
654 r.txesc().modify(|w| {
655 w.set_tbds(0b111);
656 })
657 }
27 } 658 }
28} 659}
29 660
30/// Interruptable FDCAN instance. 661/// Trait for FDCAN interrupt channel 0
31pub trait InterruptableInstance {} 662pub trait IT0Instance {
32/// FDCAN instance. 663 /// Type for FDCAN interrupt channel 0
33pub trait Instance: sealed::Instance + InterruptableInstance + 'static {} 664 type IT0Interrupt: crate::interrupt::typelevel::Interrupt;
665}
34 666
35foreach_peripheral!( 667/// Trait for FDCAN interrupt channel 1
36 (can, $inst:ident) => { 668pub trait IT1Instance {
669 /// Type for FDCAN interrupt channel 1
670 type IT1Interrupt: crate::interrupt::typelevel::Interrupt;
671}
672
673/// InterruptableInstance trait
674pub trait InterruptableInstance: IT0Instance + IT1Instance {}
675/// Instance trait
676pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
677/// Fdcan Instance struct
678pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
679
680unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> {
681 const MSG_RAM: *mut RegisterBlock = T::MSG_RAM;
682}
683
684unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T>
685where
686 FdcanInstance<'d, T>: fdcan::message_ram::Instance,
687{
688 const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS;
689}
690
691macro_rules! impl_fdcan {
692 ($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
37 impl sealed::Instance for peripherals::$inst { 693 impl sealed::Instance for peripherals::$inst {
694 const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
695 const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _;
696 const MSG_RAM_OFFSET: usize = $msg_ram_offset;
697
38 fn regs() -> &'static crate::pac::can::Fdcan { 698 fn regs() -> &'static crate::pac::can::Fdcan {
39 &crate::pac::$inst 699 &crate::pac::$inst
40 } 700 }
@@ -47,8 +707,40 @@ foreach_peripheral!(
47 707
48 impl Instance for peripherals::$inst {} 708 impl Instance for peripherals::$inst {}
49 709
710 foreach_interrupt!(
711 ($inst,can,FDCAN,IT0,$irq:ident) => {
712 impl IT0Instance for peripherals::$inst {
713 type IT0Interrupt = crate::interrupt::typelevel::$irq;
714 }
715 };
716 ($inst,can,FDCAN,IT1,$irq:ident) => {
717 impl IT1Instance for peripherals::$inst {
718 type IT1Interrupt = crate::interrupt::typelevel::$irq;
719 }
720 };
721 );
722
50 impl InterruptableInstance for peripherals::$inst {} 723 impl InterruptableInstance for peripherals::$inst {}
51 }; 724 };
725
726 ($inst:ident, $msg_ram_inst:ident) => {
727 impl_fdcan!($inst, $msg_ram_inst, 0);
728 };
729}
730
731#[cfg(not(stm32h7))]
732foreach_peripheral!(
733 (can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); };
734 (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); };
735 (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM2); };
736 (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); };
737);
738
739#[cfg(stm32h7)]
740foreach_peripheral!(
741 (can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); };
742 (can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); };
743 (can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM, 0x1800); };
52); 744);
53 745
54pin_trait!(RxPin, Instance); 746pin_trait!(RxPin, Instance);
diff --git a/embassy-stm32/src/rcc/h.rs b/embassy-stm32/src/rcc/h.rs
index 85e12637e..dcaf2dced 100644
--- a/embassy-stm32/src/rcc/h.rs
+++ b/embassy-stm32/src/rcc/h.rs
@@ -6,10 +6,9 @@ use crate::pac::pwr::vals::Vos;
6pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource; 6pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
7#[cfg(stm32h7)] 7#[cfg(stm32h7)]
8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource; 8pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
9pub use crate::pac::rcc::vals::Fdcansel as FdCanClockSource;
10pub use crate::pac::rcc::vals::{ 9pub use crate::pac::rcc::vals::{
11 Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul, 10 Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv,
12 Pllsrc as PllSource, Sw as Sysclk, 11 Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
13}; 12};
14use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre}; 13use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
15use crate::pac::{FLASH, PWR, RCC}; 14use crate::pac::{FLASH, PWR, RCC};
@@ -591,7 +590,7 @@ pub(crate) unsafe fn init(config: Config) {
591 RCC.ccipr5().modify(|w| { 590 RCC.ccipr5().modify(|w| {
592 w.set_ckpersel(config.per_clock_source); 591 w.set_ckpersel(config.per_clock_source);
593 w.set_adcdacsel(config.adc_clock_source); 592 w.set_adcdacsel(config.adc_clock_source);
594 w.set_fdcan1sel(config.fdcan_clock_source) 593 w.set_fdcan12sel(config.fdcan_clock_source)
595 }); 594 });
596 } 595 }
597 596