Merge pull request #2744 from cschuhen/feature/bxcan_use_fdcan_api

Synchronise the feature sets and API between BXCAN and FDCAN.
This commit is contained in:
Dario Nieuwenhuis 2024-03-28 00:10:11 +00:00 committed by GitHub
commit 393de9e19f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1321 additions and 910 deletions

View File

@ -40,10 +40,37 @@ pub type Header = crate::can::frame::Header;
/// Data for a CAN Frame
pub type Data = crate::can::frame::ClassicData;
/// CAN Frame
pub type Frame = crate::can::frame::ClassicFrame;
use crate::can::_version::Envelope;
use crate::can::bx::filter::MasterFilters;
use crate::can::enums::BusError;
/// CAN Frame
pub use crate::can::frame::Frame;
use crate::pac::can::vals::Lec;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) enum RxFifo {
Fifo0,
Fifo1,
}
trait IntoBusError {
fn into_bus_err(self) -> Option<BusError>;
}
impl IntoBusError for Lec {
fn into_bus_err(self) -> Option<BusError> {
match self {
Lec::STUFF => Some(BusError::Stuff),
Lec::FORM => Some(BusError::Form),
Lec::ACK => Some(BusError::Acknowledge),
Lec::BITRECESSIVE => Some(BusError::BitRecessive),
Lec::BITDOMINANT => Some(BusError::BitDominant),
Lec::CRC => Some(BusError::Crc),
Lec::CUSTOM => Some(BusError::Software),
_ => None,
}
}
}
/// A bxCAN peripheral instance.
///
@ -233,229 +260,36 @@ impl PartialOrd for IdReg {
}
}
/// Configuration proxy returned by [`Can::modify_config`].
#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"]
pub struct CanConfig<'a, I: Instance> {
can: &'a mut Can<I>,
pub(crate) struct Registers {
pub canregs: crate::pac::can::Can,
}
impl<I: Instance> CanConfig<'_, I> {
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
/// parameters as follows:
///
/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
/// - *Sample Point*: Should normally be left at the default value of 87.5%.
/// - *SJW*: Should normally be left at the default value of 1.
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self {
self.can.set_bit_timing(bt);
self
}
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(self, enabled: bool) -> Self {
self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled));
self
}
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(self, enabled: bool) -> Self {
let mode = match enabled {
false => stm32_metapac::can::vals::Silm::NORMAL,
true => stm32_metapac::can::vals::Silm::SILENT,
};
self.can.canregs.btr().modify(|reg| reg.set_silm(mode));
self
}
/// Enables or disables automatic retransmission of messages.
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// until it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled));
self
}
/// Leaves initialization mode and enables the peripheral.
///
/// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected
/// on the bus.
///
/// If you want to finish configuration without enabling the peripheral, you can call
/// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead.
pub fn enable(mut self) {
self.leave_init_mode();
match nb::block!(self.can.enable_non_blocking()) {
Ok(()) => {}
Err(void) => match void {},
}
// Don't run the destructor.
mem::forget(self);
}
/// Leaves initialization mode, but keeps the peripheral in sleep mode.
///
/// Before the [`Can`] instance can be used, you have to enable it by calling
/// [`Can::enable_non_blocking`].
pub fn leave_disabled(mut self) {
self.leave_init_mode();
}
/// Leaves initialization mode, enters sleep mode.
fn leave_init_mode(&mut self) {
self.can.canregs.mcr().modify(|reg| {
reg.set_sleep(true);
reg.set_inrq(false);
});
loop {
let msr = self.can.canregs.msr().read();
if msr.slak() && !msr.inak() {
break;
}
}
}
}
impl<I: Instance> Drop for CanConfig<'_, I> {
#[inline]
fn drop(&mut self) {
self.leave_init_mode();
}
}
/// Builder returned by [`Can::builder`].
#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"]
pub struct CanBuilder<I: Instance> {
can: Can<I>,
}
impl<I: Instance> CanBuilder<I> {
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
/// parameters as follows:
///
/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
/// - *Sample Point*: Should normally be left at the default value of 87.5%.
/// - *SJW*: Should normally be left at the default value of 1.
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self {
self.can.set_bit_timing(bt);
self
}
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(self, enabled: bool) -> Self {
self.can.canregs.btr().modify(|reg| reg.set_lbkm(enabled));
self
}
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(self, enabled: bool) -> Self {
let mode = match enabled {
false => stm32_metapac::can::vals::Silm::NORMAL,
true => stm32_metapac::can::vals::Silm::SILENT,
};
self.can.canregs.btr().modify(|reg| reg.set_silm(mode));
self
}
/// Enables or disables automatic retransmission of messages.
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// until it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
self.can.canregs.mcr().modify(|reg| reg.set_nart(enabled));
self
}
/// Leaves initialization mode and enables the peripheral.
///
/// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected
/// on the bus.
///
/// If you want to finish configuration without enabling the peripheral, you can call
/// [`CanBuilder::leave_disabled`] instead.
pub fn enable(mut self) -> Can<I> {
self.leave_init_mode();
match nb::block!(self.can.enable_non_blocking()) {
Ok(()) => self.can,
Err(void) => match void {},
}
}
/// Returns the [`Can`] interface without enabling it.
///
/// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling
/// it.
///
/// Before the [`Can`] instance can be used, you have to enable it by calling
/// [`Can::enable_non_blocking`].
pub fn leave_disabled(mut self) -> Can<I> {
self.leave_init_mode();
self.can
}
/// Leaves initialization mode, enters sleep mode.
fn leave_init_mode(&mut self) {
self.can.canregs.mcr().modify(|reg| {
reg.set_sleep(true);
reg.set_inrq(false);
});
loop {
let msr = self.can.canregs.msr().read();
if msr.slak() && !msr.inak() {
break;
}
}
}
}
/// Interface to a bxCAN peripheral.
pub struct Can<I: Instance> {
instance: I,
canregs: crate::pac::can::Can,
}
impl<I> Can<I>
where
I: Instance,
{
/// Creates a [`CanBuilder`] for constructing a CAN interface.
pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> {
let can_builder = CanBuilder {
can: Can { instance, canregs },
};
canregs.mcr().modify(|reg| {
impl Registers {
fn enter_init_mode(&mut self) {
self.canregs.mcr().modify(|reg| {
reg.set_sleep(false);
reg.set_inrq(true);
});
loop {
let msr = canregs.msr().read();
let msr = self.canregs.msr().read();
if !msr.slak() && msr.inak() {
break;
}
}
}
can_builder
// Leaves initialization mode, enters sleep mode.
fn leave_init_mode(&mut self) {
self.canregs.mcr().modify(|reg| {
reg.set_sleep(true);
reg.set_inrq(false);
});
loop {
let msr = self.canregs.msr().read();
if msr.slak() && !msr.inak() {
break;
}
}
}
fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) {
@ -471,38 +305,29 @@ where
});
}
/// Returns a reference to the peripheral instance.
///
/// This allows accessing HAL-specific data stored in the instance type.
pub fn instance(&mut self) -> &mut I {
&mut self.instance
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(&self, enabled: bool) {
let mode = match enabled {
false => stm32_metapac::can::vals::Silm::NORMAL,
true => stm32_metapac::can::vals::Silm::SILENT,
};
self.canregs.btr().modify(|reg| reg.set_silm(mode));
}
/// Disables the CAN interface and returns back the raw peripheral it was created from.
/// Enables or disables automatic retransmission of messages.
///
/// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to
/// enter sleep mode.
pub fn free(self) -> I {
self.canregs.mcr().write(|reg| reg.set_reset(true));
self.instance
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// until it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
pub fn set_automatic_retransmit(&self, enabled: bool) {
self.canregs.mcr().modify(|reg| reg.set_nart(enabled));
}
/// Configure bit timings and silent/loop-back mode.
///
/// Calling this method will enter initialization mode.
pub fn modify_config(&mut self) -> CanConfig<'_, I> {
self.canregs.mcr().modify(|reg| {
reg.set_sleep(false);
reg.set_inrq(true);
});
loop {
let msr = self.canregs.msr().read();
if !msr.slak() && msr.inak() {
break;
}
}
CanConfig { can: self }
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(&self, enabled: bool) {
self.canregs.btr().modify(|reg| reg.set_lbkm(enabled));
}
/// Configures the automatic wake-up feature.
@ -512,6 +337,7 @@ where
/// When turned on, an incoming frame will cause the peripheral to wake up from sleep and
/// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming
/// frame.
#[allow(dead_code)]
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
self.canregs.mcr().modify(|reg| reg.set_awum(enabled));
}
@ -540,6 +366,7 @@ where
/// Puts the peripheral in a sleep mode to save power.
///
/// While in sleep mode, an incoming CAN frame will trigger [`Interrupt::Wakeup`] if enabled.
#[allow(dead_code)]
pub fn sleep(&mut self) {
self.canregs.mcr().modify(|reg| {
reg.set_sleep(true);
@ -553,10 +380,19 @@ where
}
}
/// Disables the CAN interface.
///
/// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to
/// enter sleep mode.
pub fn reset(&self) {
self.canregs.mcr().write(|reg| reg.set_reset(true));
}
/// Wakes up from sleep mode.
///
/// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
/// frame will cause that interrupt.
#[allow(dead_code)]
pub fn wakeup(&mut self) {
self.canregs.mcr().modify(|reg| {
reg.set_sleep(false);
@ -570,113 +406,18 @@ where
}
}
/// Puts a CAN frame in a free transmit mailbox for transmission on the bus.
///
/// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
/// Transmit order is preserved for frames with identical priority.
///
/// If all transmit mailboxes are full, and `frame` has a higher priority than the
/// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
/// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
/// [`TransmitStatus::dequeued_frame`].
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
// Safety: We have a `&mut self` and have unique access to the peripheral.
unsafe { Tx::<I>::conjure(self.canregs).transmit(frame) }
}
/// Returns `true` if no frame is pending for transmission.
pub fn is_transmitter_idle(&self) -> bool {
// Safety: Read-only operation.
unsafe { Tx::<I>::conjure(self.canregs).is_idle() }
}
/// Attempts to abort the sending of a frame that is pending in a mailbox.
///
/// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
/// aborted, this function has no effect and returns `false`.
///
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`.
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
// Safety: We have a `&mut self` and have unique access to the peripheral.
unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) }
}
/// Returns a received frame if available.
///
/// This will first check FIFO 0 for a message or error. If none are available, FIFO 1 is
/// checked.
///
/// Returns `Err` when a frame was lost due to buffer overrun.
pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> {
// Safety: We have a `&mut self` and have unique access to the peripheral.
let mut rx0 = unsafe { Rx0::<I>::conjure(self.canregs) };
let mut rx1 = unsafe { Rx1::<I>::conjure(self.canregs) };
match rx0.receive() {
Err(nb::Error::WouldBlock) => rx1.receive(),
result => result,
}
}
/// Returns a reference to the RX FIFO 0.
pub fn rx0(&mut self) -> Rx0<I> {
// Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime.
unsafe { Rx0::conjure(self.canregs) }
}
/// Returns a reference to the RX FIFO 1.
pub fn rx1(&mut self) -> Rx1<I> {
// Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime.
unsafe { Rx1::conjure(self.canregs) }
}
pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx0<I>, Rx1<I>) {
// Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime.
let tx = unsafe { Tx::conjure(self.canregs) };
let rx0 = unsafe { Rx0::conjure(self.canregs) };
let rx1 = unsafe { Rx1::conjure(self.canregs) };
(tx, rx0, rx1)
}
/// Consumes this `Can` instance and splits it into transmitting and receiving halves.
pub fn split(self) -> (Tx<I>, Rx0<I>, Rx1<I>) {
// Safety: `Self` is not `Copy` and is destroyed by moving it into this method.
unsafe {
(
Tx::conjure(self.canregs),
Rx0::conjure(self.canregs),
Rx1::conjure(self.canregs),
)
}
}
}
impl<I: FilterOwner> Can<I> {
/// Accesses the filter banks owned by this CAN peripheral.
///
/// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
/// peripheral instead.
pub fn modify_filters(&mut self) -> MasterFilters<'_, I> {
unsafe { MasterFilters::new(self.canregs) }
}
}
/// Interface to the CAN transmitter part.
pub struct Tx<I> {
_can: PhantomData<I>,
canregs: crate::pac::can::Can,
}
impl<I> Tx<I>
where
I: Instance,
{
unsafe fn conjure(canregs: crate::pac::can::Can) -> Self {
Self {
_can: PhantomData,
canregs,
pub fn curr_error(&self) -> Option<BusError> {
let err = { self.canregs.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
}
/// Puts a CAN frame in a transmit mailbox for transmission on the bus.
@ -842,89 +583,387 @@ where
reg.set_rqcp(2, true);
});
}
pub fn receive_frame_available(&self) -> bool {
if self.canregs.rfr(0).read().fmp() != 0 {
true
} else if self.canregs.rfr(1).read().fmp() != 0 {
true
} else {
false
}
}
pub fn receive_fifo(&self, fifo: crate::can::_version::bx::RxFifo) -> Option<Envelope> {
// Generate timestamp as early as possible
#[cfg(feature = "time")]
let ts = embassy_time::Instant::now();
use crate::pac::can::vals::Ide;
let fifo_idx = match fifo {
crate::can::_version::bx::RxFifo::Fifo0 => 0usize,
crate::can::_version::bx::RxFifo::Fifo1 => 1usize,
};
let rfr = self.canregs.rfr(fifo_idx);
let fifo = self.canregs.rx(fifo_idx);
// If there are no pending messages, there is nothing to do
if rfr.read().fmp() == 0 {
return None;
}
let rir = fifo.rir().read();
let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
embedded_can::StandardId::new(rir.stid()).unwrap().into()
} else {
let stid = (rir.stid() & 0x7FF) as u32;
let exid = rir.exid() & 0x3FFFF;
let id = (stid << 18) | (exid);
embedded_can::ExtendedId::new(id).unwrap().into()
};
let rdtr = fifo.rdtr().read();
let data_len = rdtr.dlc();
let rtr = rir.rtr() == stm32_metapac::can::vals::Rtr::REMOTE;
#[cfg(not(feature = "time"))]
let ts = rdtr.time();
let mut data: [u8; 8] = [0; 8];
data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
let frame = Frame::new(Header::new(id, data_len, rtr), &data).unwrap();
let envelope = Envelope { ts, frame };
rfr.modify(|v| v.set_rfom(true));
Some(envelope)
}
}
/// Interface to receiver FIFO 0.
pub struct Rx0<I> {
_can: PhantomData<I>,
/// Configuration proxy returned by [`Can::modify_config`].
#[must_use = "`CanConfig` leaves the peripheral in uninitialized state, call `CanConfig::enable` or explicitly drop the value"]
pub struct CanConfig<'a, I: Instance> {
can: &'a mut Can<I>,
}
impl<I: Instance> CanConfig<'_, I> {
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
/// parameters as follows:
///
/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
/// - *Sample Point*: Should normally be left at the default value of 87.5%.
/// - *SJW*: Should normally be left at the default value of 1.
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
pub fn set_bit_timing(self, bt: crate::can::util::NominalBitTiming) -> Self {
self.can.registers.set_bit_timing(bt);
self
}
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(self, enabled: bool) -> Self {
self.can.registers.set_loopback(enabled);
self
}
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(self, enabled: bool) -> Self {
self.can.registers.set_silent(enabled);
self
}
/// Enables or disables automatic retransmission of messages.
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// until it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
self.can.registers.set_automatic_retransmit(enabled);
self
}
/// Leaves initialization mode and enables the peripheral.
///
/// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected
/// on the bus.
///
/// If you want to finish configuration without enabling the peripheral, you can call
/// [`CanConfig::leave_disabled`] or [`drop`] the [`CanConfig`] instead.
pub fn enable(self) {
self.can.registers.leave_init_mode();
match nb::block!(self.can.registers.enable_non_blocking()) {
Ok(()) => {}
Err(void) => match void {},
}
// Don't run the destructor.
mem::forget(self);
}
/// Leaves initialization mode, but keeps the peripheral in sleep mode.
///
/// Before the [`Can`] instance can be used, you have to enable it by calling
/// [`Can::enable_non_blocking`].
pub fn leave_disabled(self) {
self.can.registers.leave_init_mode();
}
}
impl<I: Instance> Drop for CanConfig<'_, I> {
#[inline]
fn drop(&mut self) {
self.can.registers.leave_init_mode();
}
}
/// Builder returned by [`Can::builder`].
#[must_use = "`CanBuilder` leaves the peripheral in uninitialized state, call `CanBuilder::enable` or `CanBuilder::leave_disabled`"]
pub struct CanBuilder<I: Instance> {
can: Can<I>,
}
impl<I: Instance> CanBuilder<I> {
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
/// parameters as follows:
///
/// - *Clock Rate*: The input clock speed to the CAN peripheral (*not* the CPU clock speed).
/// This is the clock rate of the peripheral bus the CAN peripheral is attached to (eg. APB1).
/// - *Sample Point*: Should normally be left at the default value of 87.5%.
/// - *SJW*: Should normally be left at the default value of 1.
///
/// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr`
/// parameter to this method.
pub fn set_bit_timing(mut self, bt: crate::can::util::NominalBitTiming) -> Self {
self.can.registers.set_bit_timing(bt);
self
}
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(self, enabled: bool) -> Self {
self.can.registers.set_loopback(enabled);
self
}
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(self, enabled: bool) -> Self {
self.can.registers.set_silent(enabled);
self
}
/// Enables or disables automatic retransmission of messages.
///
/// If this is enabled, the CAN peripheral will automatically try to retransmit each frame
/// until it can be sent. Otherwise, it will try only once to send each frame.
///
/// Automatic retransmission is enabled by default.
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
self.can.registers.set_automatic_retransmit(enabled);
self
}
/// Leaves initialization mode and enables the peripheral.
///
/// To sync with the CAN bus, this will block until 11 consecutive recessive bits are detected
/// on the bus.
///
/// If you want to finish configuration without enabling the peripheral, you can call
/// [`CanBuilder::leave_disabled`] instead.
pub fn enable(mut self) -> Can<I> {
self.leave_init_mode();
match nb::block!(self.can.registers.enable_non_blocking()) {
Ok(()) => self.can,
Err(void) => match void {},
}
}
/// Returns the [`Can`] interface without enabling it.
///
/// This leaves initialization mode, but keeps the peripheral in sleep mode instead of enabling
/// it.
///
/// Before the [`Can`] instance can be used, you have to enable it by calling
/// [`Can::enable_non_blocking`].
pub fn leave_disabled(mut self) -> Can<I> {
self.leave_init_mode();
self.can
}
/// Leaves initialization mode, enters sleep mode.
fn leave_init_mode(&mut self) {
self.can.registers.leave_init_mode();
}
}
/// Interface to a bxCAN peripheral.
pub struct Can<I: Instance> {
instance: I,
canregs: crate::pac::can::Can,
pub(crate) registers: Registers,
}
impl<I> Rx0<I>
impl<I> Can<I>
where
I: Instance,
{
/// Creates a [`CanBuilder`] for constructing a CAN interface.
pub fn builder(instance: I, canregs: crate::pac::can::Can) -> CanBuilder<I> {
let mut can_builder = CanBuilder {
can: Can {
instance,
canregs,
registers: Registers { canregs },
},
};
can_builder.can.registers.enter_init_mode();
can_builder
}
/// Disables the CAN interface and returns back the raw peripheral it was created from.
///
/// The peripheral is disabled by setting `RESET` in `CAN_MCR`, which causes the peripheral to
/// enter sleep mode.
pub fn free(self) -> I {
self.registers.reset();
self.instance
}
/// Configure bit timings and silent/loop-back mode.
///
/// Calling this method will enter initialization mode.
pub fn modify_config(&mut self) -> CanConfig<'_, I> {
self.registers.enter_init_mode();
CanConfig { can: self }
}
/// Puts a CAN frame in a free transmit mailbox for transmission on the bus.
///
/// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
/// Transmit order is preserved for frames with identical priority.
///
/// If all transmit mailboxes are full, and `frame` has a higher priority than the
/// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
/// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
/// [`TransmitStatus::dequeued_frame`].
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
// Safety: We have a `&mut self` and have unique access to the peripheral.
unsafe { Tx::<I>::conjure(self.canregs).transmit(frame) }
}
/// Returns `true` if no frame is pending for transmission.
pub fn is_transmitter_idle(&self) -> bool {
// Safety: Read-only operation.
unsafe { Tx::<I>::conjure(self.canregs).is_idle() }
}
/// Attempts to abort the sending of a frame that is pending in a mailbox.
///
/// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
/// aborted, this function has no effect and returns `false`.
///
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`.
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
// Safety: We have a `&mut self` and have unique access to the peripheral.
unsafe { Tx::<I>::conjure(self.canregs).abort(mailbox) }
}
pub(crate) fn split_by_ref(&mut self) -> (Tx<I>, Rx<I>) {
// Safety: We take `&mut self` and the return value lifetimes are tied to `self`'s lifetime.
let tx = unsafe { Tx::conjure(self.canregs) };
let rx0 = unsafe { Rx::conjure() };
(tx, rx0)
}
}
impl<I: FilterOwner> Can<I> {
/// Accesses the filter banks owned by this CAN peripheral.
///
/// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
/// peripheral instead.
pub fn modify_filters(&mut self) -> MasterFilters<'_, I> {
unsafe { MasterFilters::new(self.canregs) }
}
}
/// Marker for Tx half
pub struct Tx<I> {
_can: PhantomData<I>,
pub(crate) registers: Registers,
}
impl<I> Tx<I>
where
I: Instance,
{
unsafe fn conjure(canregs: crate::pac::can::Can) -> Self {
Self {
_can: PhantomData,
canregs,
registers: Registers { canregs }, //canregs,
}
}
/// Returns a received frame if available.
/// Puts a CAN frame in a transmit mailbox for transmission on the bus.
///
/// Returns `Err` when a frame was lost due to buffer overrun.
pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> {
receive_fifo(self.canregs, 0)
/// Frames are transmitted to the bus based on their priority (see [`FramePriority`]).
/// Transmit order is preserved for frames with identical priority.
///
/// If all transmit mailboxes are full, and `frame` has a higher priority than the
/// lowest-priority message in the transmit mailboxes, transmission of the enqueued frame is
/// cancelled and `frame` is enqueued instead. The frame that was replaced is returned as
/// [`TransmitStatus::dequeued_frame`].
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
self.registers.transmit(frame)
}
/// Attempts to abort the sending of a frame that is pending in a mailbox.
///
/// If there is no frame in the provided mailbox, or its transmission succeeds before it can be
/// aborted, this function has no effect and returns `false`.
///
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
/// returns `true`.
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
self.registers.abort(mailbox)
}
/// Returns `true` if no frame is pending for transmission.
pub fn is_idle(&self) -> bool {
self.registers.is_idle()
}
/// Clears the request complete flag for all mailboxes.
pub fn clear_interrupt_flags(&mut self) {
self.registers.clear_interrupt_flags()
}
}
/// Interface to receiver FIFO 1.
pub struct Rx1<I> {
/// Marker for Rx half
pub struct Rx<I> {
_can: PhantomData<I>,
canregs: crate::pac::can::Can,
}
impl<I> Rx1<I>
impl<I> Rx<I>
where
I: Instance,
{
unsafe fn conjure(canregs: crate::pac::can::Can) -> Self {
Self {
_can: PhantomData,
canregs,
}
unsafe fn conjure() -> Self {
Self { _can: PhantomData }
}
/// Returns a received frame if available.
///
/// Returns `Err` when a frame was lost due to buffer overrun.
pub fn receive(&mut self) -> nb::Result<Frame, OverrunError> {
receive_fifo(self.canregs, 1)
}
}
fn receive_fifo(canregs: crate::pac::can::Can, fifo_nr: usize) -> nb::Result<Frame, OverrunError> {
assert!(fifo_nr < 2);
let rfr = canregs.rfr(fifo_nr);
let rx = canregs.rx(fifo_nr);
//let rfr = &can.rfr[fifo_nr];
//let rx = &can.rx[fifo_nr];
// Check if a frame is available in the mailbox.
let rfr_read = rfr.read();
if rfr_read.fmp() == 0 {
return Err(nb::Error::WouldBlock);
}
// Check for RX FIFO overrun.
if rfr_read.fovr() {
rfr.write(|w| w.set_fovr(true));
return Err(nb::Error::Other(OverrunError { _priv: () }));
}
// Read the frame.
let id = IdReg(rx.rir().read().0);
let mut data = [0xff; 8];
data[0..4].copy_from_slice(&rx.rdlr().read().0.to_ne_bytes());
data[4..8].copy_from_slice(&rx.rdhr().read().0.to_ne_bytes());
let len = rx.rdtr().read().dlc();
// Release the mailbox.
rfr.write(|w| w.set_rfom(true));
Ok(Frame::new(Header::new(id.id(), len, id.rtr()), &data).unwrap())
}
/// Identifies one of the two receive FIFOs.

View File

@ -10,31 +10,19 @@ use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use embassy_sync::waitqueue::AtomicWaker;
use futures::FutureExt;
use crate::gpio::AFType;
use crate::interrupt::typelevel::Interrupt;
use crate::pac::can::vals::{Ide, Lec};
use crate::rcc::RccPeripheral;
use crate::{interrupt, peripherals, Peripheral};
pub mod enums;
use enums::*;
pub mod frame;
pub mod util;
pub use frame::Envelope;
/// Contains CAN frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Envelope {
/// Reception time.
#[cfg(feature = "time")]
pub ts: embassy_time::Instant,
/// The actual CAN frame.
pub frame: Frame,
}
mod common;
pub use self::common::{BufferedCanReceiver, BufferedCanSender};
/// Interrupt handler.
pub struct TxInterruptHandler<T: Instance> {
@ -48,8 +36,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH
v.set_rqcp(1, true);
v.set_rqcp(2, true);
});
T::state().tx_waker.wake();
T::state().tx_mode.on_interrupt::<T>();
}
}
@ -60,8 +47,7 @@ pub struct Rx0InterruptHandler<T: Instance> {
impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> {
unsafe fn on_interrupt() {
// info!("rx0 irq");
Can::<T>::receive_fifo(RxFifo::Fifo0);
T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo0);
}
}
@ -72,8 +58,7 @@ pub struct Rx1InterruptHandler<T: Instance> {
impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> {
unsafe fn on_interrupt() {
// info!("rx1 irq");
Can::<T>::receive_fifo(RxFifo::Fifo1);
T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo1);
}
}
@ -100,16 +85,6 @@ pub struct Can<'d, T: Instance> {
can: crate::can::bx::Can<BxcanInstance<'d, T>>,
}
/// Error returned by `try_read`
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TryReadError {
/// Bus error
BusError(BusError),
/// Receive buffer is empty
Empty,
}
/// Error returned by `try_write`
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@ -185,7 +160,7 @@ impl<'d, T: Instance> Can<'d, T> {
/// This will wait for 11 consecutive recessive bits (bus idle state).
/// Contrary to enable method from bxcan library, this will not freeze the executor while waiting.
pub async fn enable(&mut self) {
while self.enable_non_blocking().is_err() {
while self.registers.enable_non_blocking().is_err() {
// SCE interrupt is only generated for entering sleep mode, but not leaving.
// Yield to allow other tasks to execute while can bus is initializing.
embassy_futures::yield_now().await;
@ -227,77 +202,40 @@ impl<'d, T: Instance> Can<'d, T> {
///
/// Returns a tuple of the time the message was received and the message frame
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.split().1.read().await
T::state().rx_mode.read::<T>().await
}
/// Attempts to read a CAN frame without blocking.
///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
self.split().1.try_read()
T::state().rx_mode.try_read::<T>()
}
/// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) {
self.split().1.wait_not_empty().await
}
unsafe fn receive_fifo(fifo: RxFifo) {
// Generate timestamp as early as possible
#[cfg(feature = "time")]
let ts = embassy_time::Instant::now();
let state = T::state();
let regs = T::regs();
let fifo_idx = match fifo {
RxFifo::Fifo0 => 0usize,
RxFifo::Fifo1 => 1usize,
};
let rfr = regs.rfr(fifo_idx);
let fifo = regs.rx(fifo_idx);
loop {
// If there are no pending messages, there is nothing to do
if rfr.read().fmp() == 0 {
return;
}
let rir = fifo.rir().read();
let id: embedded_can::Id = if rir.ide() == Ide::STANDARD {
embedded_can::StandardId::new(rir.stid()).unwrap().into()
} else {
let stid = (rir.stid() & 0x7FF) as u32;
let exid = rir.exid() & 0x3FFFF;
let id = (stid << 18) | (exid);
embedded_can::ExtendedId::new(id).unwrap().into()
};
let data_len = fifo.rdtr().read().dlc();
let mut data: [u8; 8] = [0; 8];
data[0..4].copy_from_slice(&fifo.rdlr().read().0.to_ne_bytes());
data[4..8].copy_from_slice(&fifo.rdhr().read().0.to_ne_bytes());
let frame = Frame::new(Header::new(id, data_len, false), &data).unwrap();
let envelope = Envelope {
#[cfg(feature = "time")]
ts,
frame,
};
rfr.modify(|v| v.set_rfom(true));
/*
NOTE: consensus was reached that if rx_queue is full, packets should be dropped
*/
let _ = state.rx_queue.try_send(envelope);
}
T::state().rx_mode.wait_not_empty::<T>().await
}
/// Split the CAN driver into transmit and receive halves.
///
/// Useful for doing separate transmit/receive tasks.
pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) {
let (tx, rx0, rx1) = self.can.split_by_ref();
(CanTx { tx }, CanRx { rx0, rx1 })
let (tx, rx) = self.can.split_by_ref();
(CanTx { tx }, CanRx { rx })
}
/// Return a buffered instance of driver. User must supply Buffers
pub fn buffered<'c, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
&'c mut self,
txb: &'static mut TxBuf<TX_BUF_SIZE>,
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
let (tx, rx) = self.split();
BufferedCan {
tx: tx.buffered(txb),
rx: rx.buffered(rxb),
}
}
}
@ -308,6 +246,46 @@ impl<'d, T: Instance> AsMut<crate::can::bx::Can<BxcanInstance<'d, T>>> for Can<'
}
}
/// Buffered CAN driver.
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
tx: BufferedCanTx<'d, T, TX_BUF_SIZE>,
rx: BufferedCanRx<'d, T, RX_BUF_SIZE>,
}
impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: &Frame) {
self.tx.write(frame).await
}
/// Returns a sender that can be used for sending CAN frames.
pub fn writer(&self) -> BufferedCanSender {
self.tx.writer()
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.rx.read().await
}
/// Attempts to read a CAN frame without blocking.
///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
self.rx.try_read()
}
/// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) {
self.rx.wait_not_empty().await
}
/// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub fn reader(&self) -> BufferedCanReceiver {
self.rx.reader()
}
}
/// CAN driver, transmit half.
pub struct CanTx<'d, T: Instance> {
tx: crate::can::bx::Tx<BxcanInstance<'d, T>>,
@ -319,7 +297,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
pub async fn write(&mut self, frame: &Frame) -> crate::can::bx::TransmitStatus {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
T::state().tx_mode.register(cx.waker());
if let Ok(status) = self.tx.transmit(frame) {
return Poll::Ready(status);
}
@ -338,7 +316,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
async fn flush_inner(mb: crate::can::bx::Mailbox) {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
T::state().tx_mode.register(cx.waker());
if T::regs().tsr().read().tme(mb.index()) {
return Poll::Ready(());
}
@ -355,7 +333,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
async fn flush_any_inner() {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
T::state().tx_mode.register(cx.waker());
let tsr = T::regs().tsr().read();
if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index())
@ -377,7 +355,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
async fn flush_all_inner() {
poll_fn(|cx| {
T::state().tx_waker.register(cx.waker());
T::state().tx_mode.register(cx.waker());
let tsr = T::regs().tsr().read();
if tsr.tme(crate::can::bx::Mailbox::Mailbox0.index())
@ -396,13 +374,68 @@ impl<'d, T: Instance> CanTx<'d, T> {
pub async fn flush_all(&self) {
Self::flush_all_inner().await
}
/// Return a buffered instance of driver. User must supply Buffers
pub fn buffered<const TX_BUF_SIZE: usize>(
self,
txb: &'static mut TxBuf<TX_BUF_SIZE>,
) -> BufferedCanTx<'d, T, TX_BUF_SIZE> {
BufferedCanTx::new(self.tx, txb)
}
}
/// User supplied buffer for TX buffering
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
/// Buffered CAN driver, transmit half.
pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> {
_tx: crate::can::bx::Tx<BxcanInstance<'d, T>>,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
}
impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> {
fn new(_tx: crate::can::bx::Tx<BxcanInstance<'d, T>>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
Self { _tx, tx_buf }.setup()
}
fn setup(self) -> Self {
// We don't want interrupts being processed while we change modes.
critical_section::with(|_| unsafe {
let tx_inner = self::common::ClassicBufferedTxInner {
tx_receiver: self.tx_buf.receiver().into(),
};
T::mut_state().tx_mode = TxMode::Buffered(tx_inner);
});
self
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: &Frame) {
self.tx_buf.send(*frame).await;
T::TXInterrupt::pend(); // Wake for Tx
}
/// Returns a sender that can be used for sending CAN frames.
pub fn writer(&self) -> BufferedCanSender {
BufferedCanSender {
tx_buf: self.tx_buf.sender().into(),
waker: T::TXInterrupt::pend,
}
}
}
impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> {
fn drop(&mut self) {
critical_section::with(|_| unsafe {
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
});
}
}
/// CAN driver, receive half.
#[allow(dead_code)]
pub struct CanRx<'d, T: Instance> {
rx0: crate::can::bx::Rx0<BxcanInstance<'d, T>>,
rx1: crate::can::bx::Rx1<BxcanInstance<'d, T>>,
rx: crate::can::bx::Rx<BxcanInstance<'d, T>>,
}
impl<'d, T: Instance> CanRx<'d, T> {
@ -412,59 +445,107 @@ impl<'d, T: Instance> CanRx<'d, T> {
///
/// Returns a tuple of the time the message was received and the message frame
pub async fn read(&mut self) -> Result<Envelope, BusError> {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
if let Poll::Ready(envelope) = T::state().rx_queue.receive().poll_unpin(cx) {
return Poll::Ready(Ok(envelope));
} else if let Some(err) = self.curr_error() {
return Poll::Ready(Err(err));
}
Poll::Pending
})
.await
T::state().rx_mode.read::<T>().await
}
/// Attempts to read a CAN frame without blocking.
///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
if let Ok(envelope) = T::state().rx_queue.try_receive() {
return Ok(envelope);
}
if let Some(err) = self.curr_error() {
return Err(TryReadError::BusError(err));
}
Err(TryReadError::Empty)
T::state().rx_mode.try_read::<T>()
}
/// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) {
poll_fn(|cx| T::state().rx_queue.poll_ready_to_receive(cx)).await
T::state().rx_mode.wait_not_empty::<T>().await
}
fn curr_error(&self) -> Option<BusError> {
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);
/// Return a buffered instance of driver. User must supply Buffers
pub fn buffered<const RX_BUF_SIZE: usize>(
self,
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
) -> BufferedCanRx<'d, T, RX_BUF_SIZE> {
BufferedCanRx::new(self.rx, rxb)
}
}
/// User supplied buffer for RX Buffering
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
/// CAN driver, receive half in Buffered mode.
pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> {
_rx: crate::can::bx::Rx<BxcanInstance<'d, T>>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
}
impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> {
fn new(_rx: crate::can::bx::Rx<BxcanInstance<'d, T>>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
BufferedCanRx { _rx, rx_buf }.setup()
}
fn setup(self) -> Self {
// We don't want interrupts being processed while we change modes.
critical_section::with(|_| unsafe {
let rx_inner = self::common::ClassicBufferedRxInner {
rx_sender: self.rx_buf.sender().into(),
};
T::mut_state().rx_mode = RxMode::Buffered(rx_inner);
});
self
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.rx_buf.receive().await
}
/// Attempts to read a CAN frame without blocking.
///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
match &T::state().rx_mode {
RxMode::Buffered(_) => {
if let Ok(result) = self.rx_buf.try_receive() {
match result {
Ok(envelope) => Ok(envelope),
Err(e) => Err(TryReadError::BusError(e)),
}
} else {
let registers = crate::can::bx::Registers { canregs: T::regs() };
if let Some(err) = registers.curr_error() {
return Err(TryReadError::BusError(err));
} else {
Err(TryReadError::Empty)
}
}
}
_ => {
panic!("Bad Mode")
}
}
None
}
/// Waits while receive queue is empty.
pub async fn wait_not_empty(&mut self) {
poll_fn(|cx| self.rx_buf.poll_ready_to_receive(cx)).await
}
/// Returns a receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub fn reader(&self) -> BufferedCanReceiver {
self.rx_buf.receiver().into()
}
}
enum RxFifo {
Fifo0,
Fifo1,
impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> {
fn drop(&mut self) {
critical_section::with(|_| unsafe {
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
});
}
}
use crate::can::bx::RxFifo;
impl<'d, T: Instance> Drop for Can<'d, T> {
fn drop(&mut self) {
// Cannot call `free()` because it moves the instance.
@ -488,18 +569,163 @@ impl<'d, T: Instance> DerefMut for Can<'d, T> {
}
}
use crate::can::enums::{BusError, TryReadError};
pub(crate) enum RxMode {
NonBuffered(AtomicWaker),
Buffered(crate::can::_version::common::ClassicBufferedRxInner),
}
impl RxMode {
pub fn on_interrupt<T: Instance>(&self, fifo: crate::can::_version::bx::RxFifo) {
match self {
Self::NonBuffered(waker) => {
// Disable interrupts until read
let fifo_idx = match fifo {
crate::can::_version::bx::RxFifo::Fifo0 => 0usize,
crate::can::_version::bx::RxFifo::Fifo1 => 1usize,
};
T::regs().ier().write(|w| {
w.set_fmpie(fifo_idx, false);
});
waker.wake();
}
Self::Buffered(buf) => {
let regsisters = crate::can::bx::Registers { canregs: T::regs() };
loop {
match regsisters.receive_fifo(fifo) {
Some(envelope) => {
// NOTE: consensus was reached that if rx_queue is full, packets should be dropped
let _ = buf.rx_sender.try_send(Ok(envelope));
}
None => return,
};
}
}
}
}
pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> {
match self {
Self::NonBuffered(waker) => {
poll_fn(|cx| {
T::state().err_waker.register(cx.waker());
waker.register(cx.waker());
match self.try_read::<T>() {
Ok(result) => Poll::Ready(Ok(result)),
Err(TryReadError::Empty) => Poll::Pending,
Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)),
}
})
.await
}
_ => {
panic!("Bad Mode")
}
}
}
pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> {
match self {
Self::NonBuffered(_) => {
let registers = crate::can::bx::Registers { canregs: T::regs() };
if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo0) {
T::regs().ier().write(|w| {
w.set_fmpie(0, true);
});
Ok(msg)
} else if let Some(msg) = registers.receive_fifo(super::bx::RxFifo::Fifo1) {
T::regs().ier().write(|w| {
w.set_fmpie(1, true);
});
Ok(msg)
} else if let Some(err) = registers.curr_error() {
Err(TryReadError::BusError(err))
} else {
Err(TryReadError::Empty)
}
}
_ => {
panic!("Bad Mode")
}
}
}
pub async fn wait_not_empty<T: Instance>(&self) {
match &T::state().rx_mode {
Self::NonBuffered(waker) => {
poll_fn(|cx| {
waker.register(cx.waker());
let registers = crate::can::bx::Registers { canregs: T::regs() };
if registers.receive_frame_available() {
Poll::Ready(())
} else {
Poll::Pending
}
})
.await
}
_ => {
panic!("Bad Mode")
}
}
}
}
enum TxMode {
NonBuffered(AtomicWaker),
Buffered(self::common::ClassicBufferedTxInner),
}
impl TxMode {
pub fn buffer_free<T: Instance>(&self) -> bool {
let tsr = T::regs().tsr().read();
tsr.tme(crate::can::bx::Mailbox::Mailbox0.index())
|| tsr.tme(crate::can::bx::Mailbox::Mailbox1.index())
|| tsr.tme(crate::can::bx::Mailbox::Mailbox2.index())
}
pub fn on_interrupt<T: Instance>(&self) {
match &T::state().tx_mode {
TxMode::NonBuffered(waker) => waker.wake(),
TxMode::Buffered(buf) => {
while self.buffer_free::<T>() {
match buf.tx_receiver.try_receive() {
Ok(frame) => {
let mut registers = crate::can::bx::Registers { canregs: T::regs() };
_ = registers.transmit(&frame);
}
Err(_) => {
break;
}
}
}
}
}
}
fn register(&self, arg: &core::task::Waker) {
match self {
TxMode::NonBuffered(waker) => {
waker.register(arg);
}
_ => {
panic!("Bad mode");
}
}
}
}
struct State {
pub tx_waker: AtomicWaker,
pub(crate) rx_mode: RxMode,
pub(crate) tx_mode: TxMode,
pub err_waker: AtomicWaker,
pub rx_queue: Channel<CriticalSectionRawMutex, Envelope, 32>,
}
impl State {
pub const fn new() -> Self {
Self {
tx_waker: AtomicWaker::new(),
rx_mode: RxMode::NonBuffered(AtomicWaker::new()),
tx_mode: TxMode::NonBuffered(AtomicWaker::new()),
err_waker: AtomicWaker::new(),
rx_queue: Channel::new(),
}
}
}
@ -507,6 +733,7 @@ impl State {
trait SealedInstance {
fn regs() -> crate::pac::can::Can;
fn state() -> &'static State;
unsafe fn mut_state() -> &'static mut State;
}
/// CAN instance trait.
@ -535,9 +762,12 @@ foreach_peripheral!(
crate::pac::$inst
}
unsafe fn mut_state() -> & 'static mut State {
static mut STATE: State = State::new();
&mut *core::ptr::addr_of_mut!(STATE)
}
fn state() -> &'static State {
static STATE: State = State::new();
&STATE
unsafe { peripherals::$inst::mut_state() }
}
}
@ -601,22 +831,3 @@ impl Index for crate::can::bx::Mailbox {
}
}
}
trait IntoBusError {
fn into_bus_err(self) -> Option<BusError>;
}
impl IntoBusError for Lec {
fn into_bus_err(self) -> Option<BusError> {
match self {
Lec::STUFF => Some(BusError::Stuff),
Lec::FORM => Some(BusError::Form),
Lec::ACK => Some(BusError::Acknowledge),
Lec::BITRECESSIVE => Some(BusError::BitRecessive),
Lec::BITDOMINANT => Some(BusError::BitDominant),
Lec::CRC => Some(BusError::Crc),
Lec::CUSTOM => Some(BusError::Software),
_ => None,
}
}
}

View File

@ -0,0 +1,52 @@
use embassy_sync::channel::{DynamicReceiver, DynamicSender};
use crate::can::_version::enums::*;
use crate::can::_version::frame::*;
pub(crate) struct ClassicBufferedRxInner {
pub rx_sender: DynamicSender<'static, Result<Envelope, BusError>>,
}
pub(crate) struct ClassicBufferedTxInner {
pub tx_receiver: DynamicReceiver<'static, Frame>,
}
#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
pub(crate) struct FdBufferedRxInner {
pub rx_sender: DynamicSender<'static, Result<FdEnvelope, BusError>>,
}
#[cfg(any(can_fdcan_v1, can_fdcan_h7))]
pub(crate) struct FdBufferedTxInner {
pub tx_receiver: DynamicReceiver<'static, FdFrame>,
}
/// Sender that can be used for sending CAN frames.
#[derive(Copy, Clone)]
pub struct BufferedCanSender {
pub(crate) tx_buf: embassy_sync::channel::DynamicSender<'static, Frame>,
pub(crate) waker: fn(),
}
impl BufferedCanSender {
/// Async write frame to TX buffer.
pub fn try_write(&mut self, frame: Frame) -> Result<(), embassy_sync::channel::TrySendError<Frame>> {
self.tx_buf.try_send(frame)?;
(self.waker)();
Ok(())
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: Frame) {
self.tx_buf.send(frame).await;
(self.waker)();
}
/// Allows a poll_fn to poll until the channel is ready to write
pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
self.tx_buf.poll_ready_to_send(cx)
}
}
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub type BufferedCanReceiver = embassy_sync::channel::DynamicReceiver<'static, Result<Envelope, BusError>>;

View File

@ -40,3 +40,13 @@ pub enum FrameCreateError {
/// Invalid ID.
InvalidCanId,
}
/// Error returned by `try_read`
#[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TryReadError {
/// Bus error
BusError(BusError),
/// Receive buffer is empty
Empty,
}

View File

@ -397,13 +397,13 @@ impl Registers {
/// Moves out of ConfigMode and into specified mode
#[inline]
pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::FdcanOperatingMode) {
pub fn into_mode(mut self, config: FdCanConfig, mode: crate::can::_version::OperatingMode) {
match mode {
crate::can::FdcanOperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
crate::can::FdcanOperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
crate::can::FdcanOperatingMode::NormalOperationMode => self.set_normal_operations(true),
crate::can::FdcanOperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
crate::can::FdcanOperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
crate::can::OperatingMode::InternalLoopbackMode => self.set_loopback_mode(LoopbackMode::Internal),
crate::can::OperatingMode::ExternalLoopbackMode => self.set_loopback_mode(LoopbackMode::External),
crate::can::OperatingMode::NormalOperationMode => self.set_normal_operations(true),
crate::can::OperatingMode::RestrictedOperationMode => self.set_restricted_operations(true),
crate::can::OperatingMode::BusMonitoringMode => self.set_bus_monitoring_mode(true),
}
self.leave_init_mode(config);
}

View File

@ -14,6 +14,7 @@ use crate::interrupt::typelevel::Interrupt;
use crate::rcc::RccPeripheral;
use crate::{interrupt, peripherals, Peripheral};
mod common;
pub mod enums;
pub(crate) mod fd;
pub mod frame;
@ -25,6 +26,8 @@ use fd::filter::*;
pub use fd::{config, filter};
use frame::*;
pub use self::common::{BufferedCanReceiver, BufferedCanSender};
/// Timestamp for incoming packets. Use Embassy time when enabled.
#[cfg(feature = "time")]
pub type Timestamp = embassy_time::Instant;
@ -107,7 +110,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1Interrup
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
/// Different operating modes
pub enum FdcanOperatingMode {
pub enum OperatingMode {
//PoweredDownMode,
//ConfigMode,
/// This mode can be used for a “Hot Selftest”, meaning the FDCAN can be tested without
@ -145,7 +148,7 @@ pub enum FdcanOperatingMode {
/// FDCAN Configuration instance instance
/// Create instance of this first
pub struct FdcanConfigurator<'d, T: Instance> {
pub struct CanConfigurator<'d, T: Instance> {
config: crate::can::fd::config::FdCanConfig,
/// Reference to internals.
instance: FdcanInstance<'d, T>,
@ -166,7 +169,7 @@ fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransm
}
}
impl<'d, T: Instance> FdcanConfigurator<'d, T> {
impl<'d, T: Instance> CanConfigurator<'d, T> {
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
pub fn new(
@ -176,7 +179,7 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
_irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
+ 'd,
) -> FdcanConfigurator<'d, T> {
) -> CanConfigurator<'d, T> {
into_ref!(peri, rx, tx);
rx.set_as_af(rx.af_num(), AFType::Input);
@ -270,13 +273,13 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
}
/// Start in mode.
pub fn start(self, mode: FdcanOperatingMode) -> Fdcan<'d, T> {
pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
critical_section::with(|_| unsafe {
T::mut_state().ns_per_timer_tick = ns_per_timer_tick;
});
T::registers().into_mode(self.config, mode);
let ret = Fdcan {
let ret = Can {
config: self.config,
instance: self.instance,
_mode: mode,
@ -285,30 +288,30 @@ impl<'d, T: Instance> FdcanConfigurator<'d, T> {
}
/// Start, entering mode. Does same as start(mode)
pub fn into_normal_mode(self) -> Fdcan<'d, T> {
self.start(FdcanOperatingMode::NormalOperationMode)
pub fn into_normal_mode(self) -> Can<'d, T> {
self.start(OperatingMode::NormalOperationMode)
}
/// Start, entering mode. Does same as start(mode)
pub fn into_internal_loopback_mode(self) -> Fdcan<'d, T> {
self.start(FdcanOperatingMode::InternalLoopbackMode)
pub fn into_internal_loopback_mode(self) -> Can<'d, T> {
self.start(OperatingMode::InternalLoopbackMode)
}
/// Start, entering mode. Does same as start(mode)
pub fn into_external_loopback_mode(self) -> Fdcan<'d, T> {
self.start(FdcanOperatingMode::ExternalLoopbackMode)
pub fn into_external_loopback_mode(self) -> Can<'d, T> {
self.start(OperatingMode::ExternalLoopbackMode)
}
}
/// FDCAN Instance
pub struct Fdcan<'d, T: Instance> {
pub struct Can<'d, T: Instance> {
config: crate::can::fd::config::FdCanConfig,
/// Reference to internals.
instance: FdcanInstance<'d, T>,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
}
impl<'d, T: Instance> Fdcan<'d, T> {
impl<'d, T: Instance> Can<'d, T> {
/// Flush one of the TX mailboxes.
pub async fn flush(&self, idx: usize) {
poll_fn(|cx| {
@ -331,12 +334,12 @@ impl<'d, T: Instance> Fdcan<'d, T> {
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
T::state().tx_mode.write::<T>(frame).await
}
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
T::state().rx_mode.read_classic::<T>().await
}
@ -349,19 +352,19 @@ impl<'d, T: Instance> Fdcan<'d, T> {
}
/// Returns the next received message frame
pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
T::state().rx_mode.read_fd::<T>().await
}
/// Split instance into separate Tx(write) and Rx(read) portions
pub fn split(self) -> (FdcanTx<'d, T>, FdcanRx<'d, T>) {
pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) {
(
FdcanTx {
CanTx {
config: self.config,
_instance: self.instance,
_mode: self._mode,
},
FdcanRx {
CanRx {
_instance1: PhantomData::<T>,
_instance2: T::regs(),
_mode: self._mode,
@ -370,8 +373,8 @@ impl<'d, T: Instance> Fdcan<'d, T> {
}
/// Join split rx and tx portions back together
pub fn join(tx: FdcanTx<'d, T>, rx: FdcanRx<'d, T>) -> Self {
Fdcan {
pub fn join(tx: CanTx<'d, T>, rx: CanRx<'d, T>) -> Self {
Can {
config: tx.config,
//_instance2: T::regs(),
instance: tx._instance,
@ -399,59 +402,27 @@ impl<'d, T: Instance> Fdcan<'d, T> {
}
/// User supplied buffer for RX Buffering
pub type RxBuf<const BUF_SIZE: usize> =
Channel<CriticalSectionRawMutex, Result<(ClassicFrame, Timestamp), BusError>, BUF_SIZE>;
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
/// User supplied buffer for TX buffering
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>;
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
/// Buffered FDCAN Instance
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
}
/// Sender that can be used for sending CAN frames.
#[derive(Copy, Clone)]
pub struct BufferedCanSender {
tx_buf: embassy_sync::channel::DynamicSender<'static, ClassicFrame>,
waker: fn(),
}
impl BufferedCanSender {
/// Async write frame to TX buffer.
pub fn try_write(&mut self, frame: ClassicFrame) -> Result<(), embassy_sync::channel::TrySendError<ClassicFrame>> {
self.tx_buf.try_send(frame)?;
(self.waker)();
Ok(())
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: ClassicFrame) {
self.tx_buf.send(frame).await;
(self.waker)();
}
/// Allows a poll_fn to poll until the channel is ready to write
pub fn poll_ready_to_send(&self, cx: &mut core::task::Context<'_>) -> core::task::Poll<()> {
self.tx_buf.poll_ready_to_send(cx)
}
}
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub type BufferedCanReceiver =
embassy_sync::channel::DynamicReceiver<'static, Result<(ClassicFrame, Timestamp), BusError>>;
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
{
fn new(
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
) -> Self {
@ -468,10 +439,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
fn setup(self) -> Self {
// We don't want interrupts being processed while we change modes.
critical_section::with(|_| unsafe {
let rx_inner = ClassicBufferedRxInner {
let rx_inner = self::common::ClassicBufferedRxInner {
rx_sender: self.rx_buf.sender().into(),
};
let tx_inner = ClassicBufferedTxInner {
let tx_inner = self::common::ClassicBufferedTxInner {
tx_receiver: self.tx_buf.receiver().into(),
};
T::mut_state().rx_mode = RxMode::ClassicBuffered(rx_inner);
@ -481,13 +452,13 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: ClassicFrame) {
pub async fn write(&mut self, frame: Frame) {
self.tx_buf.send(frame).await;
T::IT0Interrupt::pend(); // Wake for Tx
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.rx_buf.receive().await
}
@ -517,8 +488,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr
}
/// User supplied buffer for RX Buffering
pub type RxFdBuf<const BUF_SIZE: usize> =
Channel<CriticalSectionRawMutex, Result<(FdFrame, Timestamp), BusError>, BUF_SIZE>;
pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<FdEnvelope, BusError>, BUF_SIZE>;
/// User supplied buffer for TX buffering
pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
@ -527,7 +497,7 @@ pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFra
pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
}
@ -535,7 +505,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF
/// Sender that can be used for sending CAN frames.
#[derive(Copy, Clone)]
pub struct BufferedFdCanSender {
tx_buf: embassy_sync::channel::DynamicSender<'static, FdFrame>,
tx_buf: DynamicSender<'static, FdFrame>,
waker: fn(),
}
@ -560,8 +530,7 @@ impl BufferedFdCanSender {
}
/// Receiver that can be used for receiving CAN frames. Note, each CAN frame will only be received by one receiver.
pub type BufferedFdCanReceiver =
embassy_sync::channel::DynamicReceiver<'static, Result<(FdFrame, Timestamp), BusError>>;
pub type BufferedFdCanReceiver = DynamicReceiver<'static, Result<FdEnvelope, BusError>>;
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
BufferedCanFd<'d, T, TX_BUF_SIZE, RX_BUF_SIZE>
@ -569,7 +538,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
fn new(
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
) -> Self {
@ -586,10 +555,10 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
fn setup(self) -> Self {
// We don't want interrupts being processed while we change modes.
critical_section::with(|_| unsafe {
let rx_inner = FdBufferedRxInner {
let rx_inner = self::common::FdBufferedRxInner {
rx_sender: self.rx_buf.sender().into(),
};
let tx_inner = FdBufferedTxInner {
let tx_inner = self::common::FdBufferedTxInner {
tx_receiver: self.tx_buf.receiver().into(),
};
T::mut_state().rx_mode = RxMode::FdBuffered(rx_inner);
@ -605,7 +574,7 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<FdEnvelope, BusError> {
self.rx_buf.receive().await
}
@ -635,25 +604,25 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Dr
}
/// FDCAN Rx only Instance
pub struct FdcanRx<'d, T: Instance> {
pub struct CanRx<'d, T: Instance> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: FdcanOperatingMode,
_mode: OperatingMode,
}
/// FDCAN Tx only Instance
pub struct FdcanTx<'d, T: Instance> {
pub struct CanTx<'d, T: Instance> {
config: crate::can::fd::config::FdCanConfig,
_instance: FdcanInstance<'d, T>, //(PeripheralRef<'a, T>);
_mode: FdcanOperatingMode,
_mode: OperatingMode,
}
impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
impl<'c, 'd, T: Instance> CanTx<'d, T> {
/// Queues the message to be sent but exerts backpressure. If a lower-priority
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
pub async fn write(&mut self, frame: &ClassicFrame) -> Option<ClassicFrame> {
pub async fn write(&mut self, frame: &Frame) -> Option<Frame> {
T::state().tx_mode.write::<T>(frame).await
}
@ -666,36 +635,22 @@ impl<'c, 'd, T: Instance> FdcanTx<'d, T> {
}
}
impl<'c, 'd, T: Instance> FdcanRx<'d, T> {
impl<'c, 'd, T: Instance> CanRx<'d, T> {
/// Returns the next received message frame
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
pub async fn read(&mut self) -> Result<Envelope, BusError> {
T::state().rx_mode.read_classic::<T>().await
}
/// Returns the next received message frame
pub async fn read_fd(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
pub async fn read_fd(&mut self) -> Result<FdEnvelope, BusError> {
T::state().rx_mode.read_fd::<T>().await
}
}
struct ClassicBufferedRxInner {
rx_sender: DynamicSender<'static, Result<(ClassicFrame, Timestamp), BusError>>,
}
struct ClassicBufferedTxInner {
tx_receiver: DynamicReceiver<'static, ClassicFrame>,
}
struct FdBufferedRxInner {
rx_sender: DynamicSender<'static, Result<(FdFrame, Timestamp), BusError>>,
}
struct FdBufferedTxInner {
tx_receiver: DynamicReceiver<'static, FdFrame>,
}
enum RxMode {
NonBuffered(AtomicWaker),
ClassicBuffered(ClassicBufferedRxInner),
FdBuffered(FdBufferedRxInner),
ClassicBuffered(self::common::ClassicBufferedRxInner),
FdBuffered(self::common::FdBufferedRxInner),
}
impl RxMode {
@ -715,18 +670,50 @@ impl RxMode {
waker.wake();
}
RxMode::ClassicBuffered(buf) => {
if let Some(result) = self.read::<T, _>() {
if let Some(result) = self.try_read::<T>() {
let _ = buf.rx_sender.try_send(result);
}
}
RxMode::FdBuffered(buf) => {
if let Some(result) = self.read::<T, _>() {
if let Some(result) = self.try_read_fd::<T>() {
let _ = buf.rx_sender.try_send(result);
}
}
}
}
//async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
fn try_read<T: Instance>(&self) -> Option<Result<Envelope, BusError>> {
if let Some((frame, ts)) = T::registers().read(0) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(Envelope { ts, frame }))
} else if let Some((frame, ts)) = T::registers().read(1) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(Envelope { ts, frame }))
} else if let Some(err) = T::registers().curr_error() {
// TODO: this is probably wrong
Some(Err(err))
} else {
None
}
}
//async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
fn try_read_fd<T: Instance>(&self) -> Option<Result<FdEnvelope, BusError>> {
if let Some((frame, ts)) = T::registers().read(0) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(FdEnvelope { ts, frame }))
} else if let Some((frame, ts)) = T::registers().read(1) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
Some(Ok(FdEnvelope { ts, frame }))
} else if let Some(err) = T::registers().curr_error() {
// TODO: this is probably wrong
Some(Err(err))
} else {
None
}
}
fn read<T: Instance, F: CanHeader>(&self) -> Option<Result<(F, Timestamp), BusError>> {
if let Some((msg, ts)) = T::registers().read(0) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, ts);
@ -754,19 +741,25 @@ impl RxMode {
.await
}
async fn read_classic<T: Instance>(&self) -> Result<(ClassicFrame, Timestamp), BusError> {
self.read_async::<T, _>().await
async fn read_classic<T: Instance>(&self) -> Result<Envelope, BusError> {
match self.read_async::<T, _>().await {
Ok((frame, ts)) => Ok(Envelope { ts, frame }),
Err(e) => Err(e),
}
}
async fn read_fd<T: Instance>(&self) -> Result<(FdFrame, Timestamp), BusError> {
self.read_async::<T, _>().await
async fn read_fd<T: Instance>(&self) -> Result<FdEnvelope, BusError> {
match self.read_async::<T, _>().await {
Ok((frame, ts)) => Ok(FdEnvelope { ts, frame }),
Err(e) => Err(e),
}
}
}
enum TxMode {
NonBuffered(AtomicWaker),
ClassicBuffered(ClassicBufferedTxInner),
FdBuffered(FdBufferedTxInner),
ClassicBuffered(self::common::ClassicBufferedTxInner),
FdBuffered(self::common::FdBufferedTxInner),
}
impl TxMode {
@ -804,7 +797,7 @@ impl TxMode {
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
/// can be replaced, this call asynchronously waits for a frame to be successfully
/// transmitted, then tries again.
async fn write<T: Instance>(&self, frame: &ClassicFrame) -> Option<ClassicFrame> {
async fn write<T: Instance>(&self, frame: &Frame) -> Option<Frame> {
self.write_generic::<T, _>(frame).await
}

View File

@ -3,6 +3,14 @@ use bit_field::BitField;
use crate::can::enums::FrameCreateError;
/// Calculate proper timestamp when available.
#[cfg(feature = "time")]
pub type Timestamp = embassy_time::Instant;
/// Raw register timestamp
#[cfg(not(feature = "time"))]
pub type Timestamp = u16;
/// CAN Header, without meta data
#[derive(Debug, Copy, Clone)]
pub struct Header {
@ -136,19 +144,20 @@ impl ClassicData {
}
}
/// Frame with up to 8 bytes of data payload as per Classic CAN
/// Frame with up to 8 bytes of data payload as per Classic(non-FD) CAN
/// For CAN-FD support use FdFrame
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct ClassicFrame {
pub struct Frame {
can_header: Header,
data: ClassicData,
}
impl ClassicFrame {
impl Frame {
/// Create a new CAN classic Frame
pub fn new(can_header: Header, raw_data: &[u8]) -> Result<Self, FrameCreateError> {
let data = ClassicData::new(raw_data)?;
Ok(ClassicFrame { can_header, data: data })
Ok(Frame { can_header, data: data })
}
/// Creates a new data frame.
@ -206,9 +215,9 @@ impl ClassicFrame {
}
}
impl embedded_can::Frame for ClassicFrame {
impl embedded_can::Frame for Frame {
fn new(id: impl Into<embedded_can::Id>, raw_data: &[u8]) -> Option<Self> {
let frameopt = ClassicFrame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
let frameopt = Frame::new(Header::new(id.into(), raw_data.len() as u8, false), raw_data);
match frameopt {
Ok(frame) => Some(frame),
Err(_) => None,
@ -216,7 +225,7 @@ impl embedded_can::Frame for ClassicFrame {
}
fn new_remote(id: impl Into<embedded_can::Id>, len: usize) -> Option<Self> {
if len <= 8 {
let frameopt = ClassicFrame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
let frameopt = Frame::new(Header::new(id.into(), len as u8, true), &[0; 8]);
match frameopt {
Ok(frame) => Some(frame),
Err(_) => None,
@ -245,7 +254,7 @@ impl embedded_can::Frame for ClassicFrame {
}
}
impl CanHeader for ClassicFrame {
impl CanHeader for Frame {
fn from_header(header: Header, data: &[u8]) -> Result<Self, FrameCreateError> {
Self::new(header, data)
}
@ -255,10 +264,31 @@ impl CanHeader for ClassicFrame {
}
}
/// Contains CAN frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
/// For CAN-FD support use FdEnvelope
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Envelope {
/// Reception time.
pub ts: Timestamp,
/// The actual CAN frame.
pub frame: Frame,
}
impl Envelope {
/// Convert into a tuple
pub fn parts(self) -> (Frame, Timestamp) {
(self.frame, self.ts)
}
}
/// Payload of a (FD)CAN data frame.
///
/// Contains 0 to 64 Bytes of data.
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdData {
pub(crate) bytes: [u8; 64],
}
@ -308,6 +338,7 @@ impl FdData {
/// Frame with up to 8 bytes of data payload as per Fd CAN
#[derive(Debug, Copy, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdFrame {
can_header: Header,
data: FdData,
@ -410,3 +441,23 @@ impl CanHeader for FdFrame {
self.header()
}
}
/// Contains CAN FD frame and additional metadata.
///
/// Timestamp is available if `time` feature is enabled.
#[derive(Debug, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct FdEnvelope {
/// Reception time.
pub ts: Timestamp,
/// The actual CAN frame.
pub frame: FdFrame,
}
impl FdEnvelope {
/// Convert into a tuple
pub fn parts(self) -> (FdFrame, Timestamp) {
(self.frame, self.ts)
}
}

View File

@ -23,6 +23,7 @@ panic-probe = { version = "0.3", features = ["print-defmt"] }
futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
heapless = { version = "0.8", default-features = false }
nb = "1.0.0"
static_cell = "2.0.0"
[profile.dev]
opt-level = "s"

View File

@ -4,11 +4,12 @@
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::can::{
filter, Can, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
filter, Can, Envelope, Fifo, Frame, Id, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, StandardId,
TxInterruptHandler,
};
use embassy_stm32::peripherals::CAN;
use embassy_stm32::{bind_interrupts, Config};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@ -21,6 +22,27 @@ bind_interrupts!(struct Irqs {
// This example is configured to work with real CAN transceivers on B8/B9.
// See other examples for loopback.
fn handle_frame(env: Envelope, read_mode: &str) {
match env.frame.id() {
Id::Extended(id) => {
defmt::println!(
"{} Extended Frame id={:x} {:02x}",
read_mode,
id.as_raw(),
env.frame.data()
);
}
Id::Standard(id) => {
defmt::println!(
"{} Standard Frame id={:x} {:02x}",
read_mode,
id.as_raw(),
env.frame.data()
);
}
}
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(Config::default());
@ -28,6 +50,9 @@ async fn main(_spawner: Spawner) {
// Set alternate pin mapping to B8/B9
embassy_stm32::pac::AFIO.mapr().modify(|w| w.set_can1_remap(2));
static RX_BUF: StaticCell<embassy_stm32::can::RxBuf<10>> = StaticCell::new();
static TX_BUF: StaticCell<embassy_stm32::can::TxBuf<10>> = StaticCell::new();
let mut can = Can::new(p.CAN, p.PB8, p.PB9, Irqs);
can.as_mut()
@ -43,21 +68,72 @@ async fn main(_spawner: Spawner) {
can.set_bitrate(250_000);
can.enable().await;
let mut i: u8 = 0;
/*
// Example for using buffered Tx and Rx without needing to
// split first as is done below.
let mut can = can.buffered(
TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()),
RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
loop {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
can.write(&tx_frame).await;
match can.read().await {
Ok((frame, ts)) => {
handle_frame(Envelope { ts, frame }, "Buf");
}
Err(err) => {
defmt::println!("Error {}", err);
}
}
i += 1;
}
*/
let (mut tx, mut rx) = can.split();
// This example shows using the wait_not_empty API before try read
while i < 3 {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
tx.write(&tx_frame).await;
rx.wait_not_empty().await;
let env = rx.try_read().unwrap();
handle_frame(env, "Wait");
i += 1;
}
// This example shows using the full async non-buffered API
while i < 6 {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
tx.write(&tx_frame).await;
match rx.read().await {
Ok(env) => {
handle_frame(env, "NoBuf");
}
Err(err) => {
defmt::println!("Error {}", err);
}
}
i += 1;
}
// This example shows using buffered RX and TX. User passes in desired buffer (size)
// It's possible this way to have just RX or TX buffered.
let mut rx = rx.buffered(RX_BUF.init(embassy_stm32::can::RxBuf::<10>::new()));
let mut tx = tx.buffered(TX_BUF.init(embassy_stm32::can::TxBuf::<10>::new()));
loop {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i, 0, 1, 2, 3, 4, 5, 6]).unwrap();
can.write(&tx_frame).await;
tx.write(&tx_frame).await;
match can.read().await {
Ok(env) => match env.frame.id() {
Id::Extended(id) => {
defmt::println!("Extended Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
}
Id::Standard(id) => {
defmt::println!("Standard Frame id={:x} {:02x}", id.as_raw(), env.frame.data());
}
},
match rx.read().await {
Ok(envelope) => {
handle_frame(envelope, "Buf");
}
Err(err) => {
defmt::println!("Error {}", err);
}

View File

@ -36,7 +36,7 @@ async fn main(_spawner: Spawner) {
}
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
can.set_extended_filter(
can::filter::ExtendedFilterSlot::_0,
@ -56,21 +56,22 @@ async fn main(_spawner: Spawner) {
info!("Configured");
let mut can = can.start(match use_fd {
true => can::FdcanOperatingMode::InternalLoopbackMode,
false => can::FdcanOperatingMode::NormalOperationMode,
true => can::OperatingMode::InternalLoopbackMode,
false => can::OperatingMode::NormalOperationMode,
});
let mut i = 0;
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -105,7 +106,8 @@ async fn main(_spawner: Spawner) {
}
match can.read_fd().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -129,12 +131,13 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -156,7 +159,7 @@ async fn main(_spawner: Spawner) {
}
}
let can = can::Fdcan::join(tx, rx);
let can = can::Can::join(tx, rx);
info!("\n\n\nBuffered\n");
if use_fd {
@ -173,7 +176,8 @@ async fn main(_spawner: Spawner) {
_ = can.write(frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -198,7 +202,7 @@ async fn main(_spawner: Spawner) {
RX_BUF.init(can::RxBuf::<10>::new()),
);
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
// You can use any of these approaches to send. The writer makes it
@ -208,7 +212,8 @@ async fn main(_spawner: Spawner) {
can.writer().write(frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (ts, rx_frame) = (envelope.ts, envelope.frame);
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(

View File

@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
// 250k bps
can.set_bitrate(250_000);
@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(

View File

@ -24,7 +24,7 @@ async fn main(_spawner: Spawner) {
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
// 250k bps
can.set_bitrate(250_000);
@ -38,12 +38,13 @@ async fn main(_spawner: Spawner) {
let mut last_read_ts = embassy_time::Instant::now();
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(&frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
@ -69,12 +70,13 @@ async fn main(_spawner: Spawner) {
let (mut tx, mut rx) = can.split();
// With split
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = tx.write(&frame).await;
match rx.read().await {
Ok((rx_frame, ts)) => {
Ok(envelope) => {
let (rx_frame, ts) = envelope.parts();
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(

View File

@ -6,17 +6,19 @@
#[path = "../common.rs"]
mod common;
use common::*;
use defmt::assert;
use embassy_executor::Spawner;
use embassy_stm32::bind_interrupts;
use embassy_stm32::can::bx::filter::Mask32;
use embassy_stm32::can::bx::{Fifo, Frame, StandardId};
use embassy_stm32::can::bx::Fifo;
use embassy_stm32::can::{Can, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler};
use embassy_stm32::gpio::{Input, Pull};
use embassy_stm32::peripherals::CAN1;
use embassy_time::{Duration, Instant};
use embassy_time::Duration;
use {defmt_rtt as _, panic_probe as _};
mod can_common;
use can_common::*;
bind_interrupts!(struct Irqs {
CAN1_RX0 => Rx0InterruptHandler<CAN1>;
CAN1_RX1 => Rx1InterruptHandler<CAN1>;
@ -29,6 +31,11 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config());
info!("Hello World!");
let options = TestOptions {
max_latency: Duration::from_micros(1200),
max_buffered: 2,
};
let can = peri!(p, CAN);
let tx = peri!(p, CAN_TX);
let mut rx = peri!(p, CAN_RX);
@ -58,40 +65,13 @@ async fn main(_spawner: Spawner) {
info!("Can configured");
let mut i: u8 = 0;
loop {
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), &[i]).unwrap();
run_can_tests(&mut can, &options).await;
info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let envelope = can.read().await.unwrap();
info!("Frame received!");
info!("loopback time {}", envelope.ts);
info!("loopback frame {=u8}", envelope.frame.data()[0]);
let latency = envelope.ts.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
const MAX_LATENCY: Duration = Duration::from_micros(150);
assert!(
MIN_LATENCY <= latency && latency <= MAX_LATENCY,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
MAX_LATENCY
);
i += 1;
if i > 10 {
break;
}
}
// Test again with a split
let (mut tx, mut rx) = can.split();
run_split_can_tests(&mut tx, &mut rx, &options).await;
info!("Test OK");
cortex_m::asm::bkpt();
}

View File

@ -0,0 +1,112 @@
use defmt::{assert, *};
use embassy_stm32::can;
use embassy_time::{Duration, Instant};
#[derive(Clone, Copy, Debug)]
pub struct TestOptions {
pub max_latency: Duration,
pub max_buffered: u8,
}
pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
let mut i: u8 = 0;
loop {
//let tx_frame = can::frame::Frame::new_standard(0x123, &[i, 0x12 as u8, 0x34 as u8, 0x56 as u8, 0x78 as u8, 0x9A as u8, 0xBC as u8 ]).unwrap();
let tx_frame = can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap();
//info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let (frame, timestamp) = can.read().await.unwrap().parts();
//info!("Frame received!");
// Check data.
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
//info!("loopback time {}", timestamp);
//info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 5 {
break;
}
}
// Below here, check that we can receive from both FIFO0 and FIFO1
// Above we configured FIFO1 for extended ID packets. There are only 3 slots
// in each FIFO so make sure we write enough to fill them both up before reading.
for i in 0..options.max_buffered {
// Try filling up the RX FIFO0 buffers
//let tx_frame = if 0 != (i & 0x01) {
let tx_frame = if i < options.max_buffered / 2 {
info!("Transmitting standard frame {}", i);
can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap()
} else {
info!("Transmitting extended frame {}", i);
can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap()
};
can.write(&tx_frame).await;
}
// Try and receive all 6 packets
for _i in 0..options.max_buffered {
let (frame, _ts) = can.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(_id) => {
info!("Extended received! {}", frame.data()[0]);
//info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
embedded_can::Id::Standard(_id) => {
info!("Standard received! {}", frame.data()[0]);
//info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
}
pub async fn run_split_can_tests<'d, T: can::Instance>(
tx: &mut can::CanTx<'d, T>,
rx: &mut can::CanRx<'d, T>,
options: &TestOptions,
) {
for i in 0..options.max_buffered {
// Try filling up the RX FIFO0 buffers
//let tx_frame = if 0 != (i & 0x01) {
let tx_frame = if i < options.max_buffered / 2 {
info!("Transmitting standard frame {}", i);
can::frame::Frame::new_standard(0x123, &[i; 1]).unwrap()
} else {
info!("Transmitting extended frame {}", i);
can::frame::Frame::new_extended(0x1232344, &[i; 1]).unwrap()
};
tx.write(&tx_frame).await;
}
// Try and receive all 6 packets
for _i in 0..options.max_buffered {
let (frame, _ts) = rx.read().await.unwrap().parts();
match frame.id() {
embedded_can::Id::Extended(_id) => {
info!("Extended received! {}", frame.data()[0]);
}
embedded_can::Id::Standard(_id) => {
info!("Standard received! {}", frame.data()[0]);
}
}
}
}

View File

@ -6,13 +6,15 @@
#[path = "../common.rs"]
mod common;
use common::*;
use defmt::assert;
use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, Config};
use embassy_time::{Duration, Instant};
use embassy_time::Duration;
use {defmt_rtt as _, panic_probe as _};
mod can_common;
use can_common::*;
bind_interrupts!(struct Irqs2 {
FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;
@ -22,14 +24,8 @@ bind_interrupts!(struct Irqs1 {
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
});
struct TestOptions {
config: Config,
max_latency: Duration,
second_fifo_working: bool,
}
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
fn options() -> TestOptions {
fn options() -> (Config, TestOptions) {
use embassy_stm32::rcc;
info!("H75 config");
let mut c = config();
@ -38,15 +34,17 @@ fn options() -> TestOptions {
mode: rcc::HseMode::Oscillator,
});
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(1200),
second_fifo_working: false,
}
(
c,
TestOptions {
max_latency: Duration::from_micros(1200),
max_buffered: 3,
},
)
}
#[cfg(any(feature = "stm32h7a3zi"))]
fn options() -> TestOptions {
fn options() -> (Config, TestOptions) {
use embassy_stm32::rcc;
info!("H7a config");
let mut c = config();
@ -55,32 +53,36 @@ fn options() -> TestOptions {
mode: rcc::HseMode::Oscillator,
});
c.rcc.mux.fdcansel = rcc::mux::Fdcansel::HSE;
TestOptions {
config: c,
max_latency: Duration::from_micros(1200),
second_fifo_working: false,
}
(
c,
TestOptions {
max_latency: Duration::from_micros(1200),
max_buffered: 3,
},
)
}
#[cfg(any(feature = "stm32g491re", feature = "stm32g431cb"))]
fn options() -> TestOptions {
fn options() -> (Config, TestOptions) {
info!("G4 config");
TestOptions {
config: config(),
max_latency: Duration::from_micros(500),
second_fifo_working: true,
}
(
config(),
TestOptions {
max_latency: Duration::from_micros(500),
max_buffered: 6,
},
)
}
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
//let peripherals = embassy_stm32::init(config());
let options = options();
let peripherals = embassy_stm32::init(options.config);
let (config, options) = options();
let peripherals = embassy_stm32::init(config);
let mut can = can::FdcanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
let mut can2 = can::FdcanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs1);
let mut can2 = can::CanConfigurator::new(peripherals.FDCAN2, peripherals.PB12, peripherals.PB13, Irqs2);
// 250k bps
can.set_bitrate(250_000);
@ -98,141 +100,16 @@ async fn main(_spawner: Spawner) {
let mut can = can.into_internal_loopback_mode();
let mut can2 = can2.into_internal_loopback_mode();
run_can_tests(&mut can, &options).await;
run_can_tests(&mut can2, &options).await;
info!("CAN Configured");
let mut i: u8 = 0;
loop {
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can.write(&tx_frame).await;
let (frame, timestamp) = can.read().await.unwrap();
info!("Frame received!");
// Check data.
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
info!("loopback time {}", timestamp);
info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 10 {
break;
}
}
let mut i: u8 = 0;
loop {
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame...");
let tx_ts = Instant::now();
can2.write(&tx_frame).await;
let (frame, timestamp) = can2.read().await.unwrap();
info!("Frame received!");
//print_regs().await;
// Check data.
assert!(i == frame.data()[0], "{} == {}", i, frame.data()[0]);
info!("loopback time {}", timestamp);
info!("loopback frame {=u8}", frame.data()[0]);
let latency = timestamp.saturating_duration_since(tx_ts);
info!("loopback latency {} us", latency.as_micros());
// Theoretical minimum latency is 55us, actual is usually ~80us
const MIN_LATENCY: Duration = Duration::from_micros(50);
// Was failing at 150 but we are not getting a real time stamp. I'm not
// sure if there are other delays
assert!(
MIN_LATENCY <= latency && latency <= options.max_latency,
"{} <= {} <= {}",
MIN_LATENCY,
latency,
options.max_latency
);
i += 1;
if i > 10 {
break;
}
}
let max_buffered = if options.second_fifo_working { 6 } else { 3 };
// Below here, check that we can receive from both FIFO0 and FIFO0
// Above we configured FIFO1 for extended ID packets. There are only 3 slots
// in each FIFO so make sure we write enough to fill them both up before reading.
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
can.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let (frame, _ts) = can.read().await.unwrap();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
embedded_can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
// Test again with a split
let (mut tx, mut rx) = can.split();
for i in 0..3 {
// Try filling up the RX FIFO0 buffers with standard packets
let tx_frame = can::frame::ClassicFrame::new_standard(0x123, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
for i in 3..max_buffered {
// Try filling up the RX FIFO0 buffers with extended packets
let tx_frame = can::frame::ClassicFrame::new_extended(0x1232344, &[i; 1]).unwrap();
info!("Transmitting frame {}", i);
tx.write(&tx_frame).await;
}
// Try and receive all 6 packets
for i in 0..max_buffered {
let (frame, _ts) = rx.read().await.unwrap();
match frame.id() {
embedded_can::Id::Extended(id) => {
info!("Extended received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
embedded_can::Id::Standard(id) => {
info!("Standard received! {:x} {} {}", id.as_raw(), frame.data()[0], i);
}
}
}
let (mut tx2, mut rx2) = can2.split();
run_split_can_tests(&mut tx, &mut rx, &options).await;
run_split_can_tests(&mut tx2, &mut rx2, &options).await;
info!("Test OK");
cortex_m::asm::bkpt();