From 5ecf9ec7bcd785555563d8f5006fd24414bbc17f Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Thu, 22 Jun 2023 17:17:51 +0200 Subject: [PATCH 01/10] split can --- embassy-stm32/src/can/bxcan.rs | 101 +++++++++++++++++++++++++++------ 1 file changed, 85 insertions(+), 16 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 88eef528..7b664a11 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -2,7 +2,7 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::Poll; - +use core::cell::RefCell; pub use bxcan; use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -72,7 +72,7 @@ impl interrupt::typelevel::Handler for SceInterrup } pub struct Can<'d, T: Instance> { - can: bxcan::Can>, + pub can: RefCell>>, } #[derive(Debug)] @@ -147,19 +147,20 @@ impl<'d, T: Instance> Can<'d, T> { tx.set_as_af(tx.af_num(), AFType::OutputPushPull); let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled(); - Self { can } + let can_ref_cell = RefCell::new(can); + Self { can: can_ref_cell } } pub fn set_bitrate(&mut self, bitrate: u32) { let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); - self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); + self.can.borrow_mut().modify_config().set_bit_timing(bit_timing).leave_disabled(); } /// Queues the message to be sent but exerts backpressure pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { poll_fn(|cx| { T::state().tx_waker.register(cx.waker()); - if let Ok(status) = self.can.transmit(frame) { + if let Ok(status) = self.can.borrow_mut().transmit(frame) { return Poll::Ready(status); } @@ -341,6 +342,74 @@ impl<'d, T: Instance> Can<'d, T> { // Pack into BTR register values Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1)) } + + pub fn split<'c>(&'c self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { + (CanTx { can: &self.can }, CanRx { can: &self.can }) + } +} + +pub struct CanTx<'c, 'd, T: Instance> { + can: &'c RefCell>>, +} + +impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { + pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + if let Ok(status) = self.can.borrow_mut().transmit(frame) { + return Poll::Ready(status); + } + + Poll::Pending + }) + .await + } + + pub async fn flush(&self, mb: bxcan::Mailbox) { + poll_fn(|cx| { + T::state().tx_waker.register(cx.waker()); + if T::regs().tsr().read().tme(mb.index()) { + return Poll::Ready(()); + } + + Poll::Pending + }) + .await; + } +} + +pub struct CanRx<'c, 'd, T: Instance> { + can: &'c RefCell>>, +} + +impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { + pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> { + poll_fn(|cx| { + T::state().err_waker.register(cx.waker()); + if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) { + return Poll::Ready(Ok((time, frame))); + } else if let Some(err) = self.curr_error() { + return Poll::Ready(Err(err)); + } + + Poll::Pending + }) + .await + } + + fn curr_error(&self) -> Option { + let err = { T::regs().esr().read() }; + if err.boff() { + return Some(BusError::BusOff); + } else if err.epvf() { + return Some(BusError::BusPassive); + } else if err.ewgf() { + return Some(BusError::BusWarning); + } else if let Some(err) = err.lec().into_bus_err() { + return Some(err); + } + None + } } enum RxFifo { @@ -357,19 +426,19 @@ impl<'d, T: Instance> Drop for Can<'d, T> { } } -impl<'d, T: Instance> Deref for Can<'d, T> { - type Target = bxcan::Can>; +// impl<'d, T: Instance> Deref for Can<'d, T> { +// type Target = bxcan::Can>; - fn deref(&self) -> &Self::Target { - &self.can - } -} +// fn deref(&self) -> &Self::Target { +// self.can.borrow() +// } +// } -impl<'d, T: Instance> DerefMut for Can<'d, T> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.can - } -} +// impl<'d, T: Instance> DerefMut for Can<'d, T> { +// fn deref_mut(&mut self) -> &mut Self::Target { +// self.can.borrow_mut() +// } +// } pub(crate) mod sealed { use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; From f47a148f51c7c0de52a1c202fefe6f863c669854 Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Thu, 22 Jun 2023 17:18:55 +0200 Subject: [PATCH 02/10] add stm32f7 can example --- examples/stm32f7/src/bin/can.rs | 63 +++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 examples/stm32f7/src/bin/can.rs diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs new file mode 100644 index 00000000..cf027cc3 --- /dev/null +++ b/examples/stm32f7/src/bin/can.rs @@ -0,0 +1,63 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use core::borrow::BorrowMut; +use core::borrow::Borrow; +use cortex_m_rt::entry; +use defmt::*; +use embassy_executor::Spawner; +use embassy_stm32::bind_interrupts; +use embassy_stm32::can::bxcan::filter::Mask32; +use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId, Data}; +use embassy_stm32::can::{Can,CanTx,CanRx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; +use embassy_stm32::gpio::{Input, Pull}; +use embassy_stm32::peripherals::CAN3; +use {defmt_rtt as _, panic_probe as _}; + +bind_interrupts!(struct Irqs { + CAN3_RX0 => Rx0InterruptHandler; + CAN3_RX1 => Rx1InterruptHandler; + CAN3_SCE => SceInterruptHandler; + CAN3_TX => TxInterruptHandler; +}); + +#[embassy_executor::task] +pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) { + loop { + let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]); + tx.write(&frame).await; + embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await; + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + info!("Hello World!"); + + let mut p = embassy_stm32::init(Default::default()); + + // The next two lines are a workaround for testing without transceiver. + // To synchronise to the bus the RX input needs to see a high level. + // Use `mem::forget()` to release the borrow on the pin but keep the + // pull-up resistor enabled. + let rx_pin = Input::new(&mut p.PA15, Pull::Up); + core::mem::forget(rx_pin); + + let CAN: &'static mut Can<'static,CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); + CAN.can.borrow_mut().modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + + CAN.can.borrow_mut() + .modify_config() + .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/ + .enable(); + + let (tx, mut rx) = CAN.split(); + let TX: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx); + spawner.spawn(send_can_message(TX)).unwrap(); + + loop { + let frame = rx.read().await.unwrap(); + println!("Received: {:?}", frame); + } +} From 76a334bd7c402f530825352b9c12f2a6d749a42c Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Thu, 22 Jun 2023 17:47:58 +0200 Subject: [PATCH 03/10] add as_mut & set loopback true in example --- examples/stm32f7/src/bin/can.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index cf027cc3..d821039c 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -45,14 +45,16 @@ async fn main(spawner: Spawner) { core::mem::forget(rx_pin); let CAN: &'static mut Can<'static,CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); - CAN.can.borrow_mut().modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + CAN.as_mut().modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - CAN.can.borrow_mut() + CAN.as_mut() .modify_config() .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/ + .set_loopback(true) .enable(); let (tx, mut rx) = CAN.split(); + let TX: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx); spawner.spawn(send_can_message(TX)).unwrap(); From 89fbb02979c0abfac99b32e3676c140055f31c1e Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Thu, 22 Jun 2023 17:49:33 +0200 Subject: [PATCH 04/10] add as_mut --- embassy-stm32/src/can/bxcan.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 7b664a11..4afbb568 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -2,7 +2,9 @@ use core::future::poll_fn; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::Poll; +use core::cell::RefMut; use core::cell::RefCell; + pub use bxcan; use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; use embassy_hal_common::{into_ref, PeripheralRef}; @@ -346,6 +348,10 @@ impl<'d, T: Instance> Can<'d, T> { pub fn split<'c>(&'c self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { (CanTx { can: &self.can }, CanRx { can: &self.can }) } + + pub fn as_mut(&self) -> RefMut<'_, bxcan::Can>> { + self.can.borrow_mut() + } } pub struct CanTx<'c, 'd, T: Instance> { From af15b49bfe30d82b7fcb17511d7e1830b2216f03 Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Mon, 3 Jul 2023 22:57:33 +0200 Subject: [PATCH 05/10] fmt --- embassy-stm32/src/can/bxcan.rs | 31 +++++++++++++++++-------------- examples/stm32f7/src/bin/can.rs | 16 ++++++++++------ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 4afbb568..260f567b 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -1,9 +1,8 @@ +use core::cell::{RefCell, RefMut}; use core::future::poll_fn; use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use core::task::Poll; -use core::cell::RefMut; -use core::cell::RefCell; pub use bxcan; use bxcan::{Data, ExtendedId, Frame, Id, StandardId}; @@ -155,7 +154,11 @@ impl<'d, T: Instance> Can<'d, T> { pub fn set_bitrate(&mut self, bitrate: u32) { let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); - self.can.borrow_mut().modify_config().set_bit_timing(bit_timing).leave_disabled(); + self.can + .borrow_mut() + .modify_config() + .set_bit_timing(bit_timing) + .leave_disabled(); } /// Queues the message to be sent but exerts backpressure @@ -432,19 +435,19 @@ impl<'d, T: Instance> Drop for Can<'d, T> { } } -// impl<'d, T: Instance> Deref for Can<'d, T> { -// type Target = bxcan::Can>; +impl<'d, T: Instance> Deref for Can<'d, T> { + type Target = RefCell>>; -// fn deref(&self) -> &Self::Target { -// self.can.borrow() -// } -// } + fn deref(&self) -> &Self::Target { + &self.can + } +} -// impl<'d, T: Instance> DerefMut for Can<'d, T> { -// fn deref_mut(&mut self) -> &mut Self::Target { -// self.can.borrow_mut() -// } -// } +impl<'d, T: Instance> DerefMut for Can<'d, T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.can + } +} pub(crate) mod sealed { use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index d821039c..65af9845 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -2,15 +2,17 @@ #![no_main] #![feature(type_alias_impl_trait)] -use core::borrow::BorrowMut; -use core::borrow::Borrow; +use core::borrow::{Borrow, BorrowMut}; + use cortex_m_rt::entry; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId, Data}; -use embassy_stm32::can::{Can,CanTx,CanRx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler}; +use embassy_stm32::can::bxcan::{Data, Fifo, Frame, StandardId}; +use embassy_stm32::can::{ + Can, CanRx, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, +}; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN3; use {defmt_rtt as _, panic_probe as _}; @@ -44,8 +46,10 @@ async fn main(spawner: Spawner) { let rx_pin = Input::new(&mut p.PA15, Pull::Up); core::mem::forget(rx_pin); - let CAN: &'static mut Can<'static,CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); - CAN.as_mut().modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + let CAN: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); + CAN.as_mut() + .modify_filters() + .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); CAN.as_mut() .modify_config() From a96f30edf45533cb0e41711556106d1583977081 Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Mon, 3 Jul 2023 23:48:07 +0200 Subject: [PATCH 06/10] allow deed code can rx & clippy --- embassy-stm32/src/can/bxcan.rs | 1 + examples/stm32f7/src/bin/can.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 260f567b..fbb4113e 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -387,6 +387,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { } } +#[allow(dead_code)] pub struct CanRx<'c, 'd, T: Instance> { can: &'c RefCell>>, } diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 65af9845..2383c23d 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -11,7 +11,7 @@ use embassy_stm32::bind_interrupts; use embassy_stm32::can::bxcan::filter::Mask32; use embassy_stm32::can::bxcan::{Data, Fifo, Frame, StandardId}; use embassy_stm32::can::{ - Can, CanRx, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, + Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, }; use embassy_stm32::gpio::{Input, Pull}; use embassy_stm32::peripherals::CAN3; @@ -46,21 +46,21 @@ async fn main(spawner: Spawner) { let rx_pin = Input::new(&mut p.PA15, Pull::Up); core::mem::forget(rx_pin); - let CAN: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); - CAN.as_mut() + let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs)); + can.as_mut() .modify_filters() .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - CAN.as_mut() + can.as_mut() .modify_config() .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/ .set_loopback(true) .enable(); - let (tx, mut rx) = CAN.split(); + let (tx, mut rx) = can.split(); - let TX: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx); - spawner.spawn(send_can_message(TX)).unwrap(); + let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx); + spawner.spawn(send_can_message(tx)).unwrap(); loop { let frame = rx.read().await.unwrap(); From e3e8d829330b58d7c6964e761d63cb718267f862 Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Mon, 3 Jul 2023 23:52:52 +0200 Subject: [PATCH 07/10] remove unused imports from example --- examples/stm32f7/src/bin/can.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/examples/stm32f7/src/bin/can.rs b/examples/stm32f7/src/bin/can.rs index 2383c23d..1b5b377e 100644 --- a/examples/stm32f7/src/bin/can.rs +++ b/examples/stm32f7/src/bin/can.rs @@ -2,14 +2,11 @@ #![no_main] #![feature(type_alias_impl_trait)] -use core::borrow::{Borrow, BorrowMut}; - -use cortex_m_rt::entry; use defmt::*; use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::can::bxcan::filter::Mask32; -use embassy_stm32::can::bxcan::{Data, Fifo, Frame, StandardId}; +use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; use embassy_stm32::can::{ Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler, }; From 1869fe02ba8b7dfb503206977d8c70698038c3af Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Tue, 4 Jul 2023 00:21:08 +0200 Subject: [PATCH 08/10] make stm32f4 example work --- examples/stm32f4/src/bin/can.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/examples/stm32f4/src/bin/can.rs b/examples/stm32f4/src/bin/can.rs index da895505..08bed88d 100644 --- a/examples/stm32f4/src/bin/can.rs +++ b/examples/stm32f4/src/bin/can.rs @@ -2,8 +2,8 @@ #![no_main] #![feature(type_alias_impl_trait)] -use cortex_m_rt::entry; use defmt::*; +use embassy_executor::Spawner; use embassy_stm32::bind_interrupts; use embassy_stm32::can::bxcan::filter::Mask32; use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId}; @@ -19,8 +19,8 @@ bind_interrupts!(struct Irqs { CAN1_TX => TxInterruptHandler; }); -#[entry] -fn main() -> ! { +#[embassy_executor::main] +async fn main(_spawner: Spawner) { info!("Hello World!"); let mut p = embassy_stm32::init(Default::default()); @@ -34,9 +34,12 @@ fn main() -> ! { let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs); - can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + can.as_mut() + .modify_filters() + .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - can.modify_config() + can.as_mut() + .modify_config() .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/ .set_loopback(true) // Receive own frames .set_silent(true) @@ -45,9 +48,8 @@ fn main() -> ! { let mut i: u8 = 0; loop { let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]); - unwrap!(nb::block!(can.transmit(&tx_frame))); - while !can.is_transmitter_idle() {} - let rx_frame = unwrap!(nb::block!(can.receive())); + can.write(&tx_frame).await; + let (_, rx_frame) = can.read().await.unwrap(); info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]); i += 1; } From 8359d8c020fc44f795e2230b8ba12fe780f1960b Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Tue, 4 Jul 2023 00:34:24 +0200 Subject: [PATCH 09/10] make stm32 can test work --- tests/stm32/src/bin/can.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 33d63d54..05adfe89 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -43,10 +43,13 @@ async fn main(_spawner: Spawner) { info!("Configuring can..."); - can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); + can.as_mut() + .modify_filters() + .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - can.set_bitrate(1_000_000); - can.modify_config() + can.as_mut().set_bitrate(1_000_000); + can.as_mut() + .modify_config() .set_loopback(true) // Receive own frames .set_silent(true) // .set_bit_timing(0x001c0003) From a088c4bee6e26947fd8e4d32a5604e47de293ba1 Mon Sep 17 00:00:00 2001 From: Philipp Scheff Date: Tue, 4 Jul 2023 00:39:10 +0200 Subject: [PATCH 10/10] fix stm32 can test --- tests/stm32/src/bin/can.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/stm32/src/bin/can.rs b/tests/stm32/src/bin/can.rs index 05adfe89..8bdd3c24 100644 --- a/tests/stm32/src/bin/can.rs +++ b/tests/stm32/src/bin/can.rs @@ -47,7 +47,7 @@ async fn main(_spawner: Spawner) { .modify_filters() .enable_bank(0, Fifo::Fifo0, Mask32::accept_all()); - can.as_mut().set_bitrate(1_000_000); + can.set_bitrate(1_000_000); can.as_mut() .modify_config() .set_loopback(true) // Receive own frames