1049 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			1049 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| pub mod filter;
 | |
| mod registers;
 | |
| 
 | |
| use core::future::poll_fn;
 | |
| use core::marker::PhantomData;
 | |
| use core::task::Poll;
 | |
| 
 | |
| use embassy_hal_internal::{into_ref, PeripheralRef};
 | |
| use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
 | |
| use embassy_sync::channel::Channel;
 | |
| use embassy_sync::waitqueue::AtomicWaker;
 | |
| pub use embedded_can::{ExtendedId, Id, StandardId};
 | |
| 
 | |
| use self::filter::MasterFilters;
 | |
| use self::registers::{Registers, RxFifo};
 | |
| pub use super::common::{BufferedCanReceiver, BufferedCanSender};
 | |
| use super::frame::{Envelope, Frame};
 | |
| use super::util;
 | |
| use crate::can::enums::{BusError, TryReadError};
 | |
| use crate::gpio::AFType;
 | |
| use crate::interrupt::typelevel::Interrupt;
 | |
| use crate::rcc::{self, RccPeripheral};
 | |
| use crate::{interrupt, peripherals, Peripheral};
 | |
| 
 | |
| /// Interrupt handler.
 | |
| pub struct TxInterruptHandler<T: Instance> {
 | |
|     _phantom: PhantomData<T>,
 | |
| }
 | |
| 
 | |
| impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptHandler<T> {
 | |
|     unsafe fn on_interrupt() {
 | |
|         T::regs().tsr().write(|v| {
 | |
|             v.set_rqcp(0, true);
 | |
|             v.set_rqcp(1, true);
 | |
|             v.set_rqcp(2, true);
 | |
|         });
 | |
|         T::state().tx_mode.on_interrupt::<T>();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// RX0 interrupt handler.
 | |
| pub struct Rx0InterruptHandler<T: Instance> {
 | |
|     _phantom: PhantomData<T>,
 | |
| }
 | |
| 
 | |
| impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0InterruptHandler<T> {
 | |
|     unsafe fn on_interrupt() {
 | |
|         T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// RX1 interrupt handler.
 | |
| pub struct Rx1InterruptHandler<T: Instance> {
 | |
|     _phantom: PhantomData<T>,
 | |
| }
 | |
| 
 | |
| impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1InterruptHandler<T> {
 | |
|     unsafe fn on_interrupt() {
 | |
|         T::state().rx_mode.on_interrupt::<T>(RxFifo::Fifo1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// SCE interrupt handler.
 | |
| pub struct SceInterruptHandler<T: Instance> {
 | |
|     _phantom: PhantomData<T>,
 | |
| }
 | |
| 
 | |
| impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterruptHandler<T> {
 | |
|     unsafe fn on_interrupt() {
 | |
|         info!("sce irq");
 | |
|         let msr = T::regs().msr();
 | |
|         let msr_val = msr.read();
 | |
| 
 | |
|         if msr_val.slaki() {
 | |
|             msr.modify(|m| m.set_slaki(true));
 | |
|             T::state().err_waker.wake();
 | |
|         } else if msr_val.erri() {
 | |
|             info!("Error interrupt");
 | |
|             // Disable the interrupt, but don't acknowledge the error, so that it can be
 | |
|             // forwarded off the the bus message consumer. If we don't provide some way for
 | |
|             // downstream code to determine that it has already provided this bus error instance
 | |
|             // to the bus message consumer, we are doomed to re-provide a single error instance for
 | |
|             // an indefinite amount of time.
 | |
|             let ier = T::regs().ier();
 | |
|             ier.modify(|i| i.set_errie(false));
 | |
| 
 | |
|             T::state().err_waker.wake();
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Configuration proxy returned by [`Can::modify_config`].
 | |
| pub struct CanConfig<'a, T: Instance> {
 | |
|     can: PhantomData<&'a mut T>,
 | |
| }
 | |
| 
 | |
| impl<T: Instance> CanConfig<'_, T> {
 | |
|     /// 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 {
 | |
|         Registers(T::regs()).set_bit_timing(bt);
 | |
|         self
 | |
|     }
 | |
| 
 | |
|     /// Configure the CAN bit rate.
 | |
|     ///
 | |
|     /// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing].
 | |
|     pub fn set_bitrate(self, bitrate: u32) -> Self {
 | |
|         let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
 | |
|         self.set_bit_timing(bit_timing)
 | |
|     }
 | |
| 
 | |
|     /// Enables or disables loopback mode: Internally connects the TX and RX
 | |
|     /// signals together.
 | |
|     pub fn set_loopback(self, enabled: bool) -> Self {
 | |
|         Registers(T::regs()).set_loopback(enabled);
 | |
|         self
 | |
|     }
 | |
| 
 | |
|     /// Enables or disables silent mode: Disconnects the TX signal from the pin.
 | |
|     pub fn set_silent(self, enabled: bool) -> Self {
 | |
|         Registers(T::regs()).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 {
 | |
|         Registers(T::regs()).set_automatic_retransmit(enabled);
 | |
|         self
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<T: Instance> Drop for CanConfig<'_, T> {
 | |
|     #[inline]
 | |
|     fn drop(&mut self) {
 | |
|         Registers(T::regs()).leave_init_mode();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// CAN driver
 | |
| pub struct Can<'d, T: Instance> {
 | |
|     peri: PeripheralRef<'d, T>,
 | |
| }
 | |
| 
 | |
| /// Error returned by `try_write`
 | |
| #[derive(Debug)]
 | |
| #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | |
| pub enum TryWriteError {
 | |
|     /// All transmit mailboxes are full
 | |
|     Full,
 | |
| }
 | |
| 
 | |
| impl<'d, T: Instance> Can<'d, T> {
 | |
|     /// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
 | |
|     /// You must call [Can::enable_non_blocking] to use the peripheral.
 | |
|     pub fn new(
 | |
|         peri: impl Peripheral<P = T> + 'd,
 | |
|         rx: impl Peripheral<P = impl RxPin<T>> + 'd,
 | |
|         tx: impl Peripheral<P = impl TxPin<T>> + 'd,
 | |
|         _irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
 | |
|             + interrupt::typelevel::Binding<T::RX0Interrupt, Rx0InterruptHandler<T>>
 | |
|             + interrupt::typelevel::Binding<T::RX1Interrupt, Rx1InterruptHandler<T>>
 | |
|             + interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
 | |
|             + 'd,
 | |
|     ) -> Self {
 | |
|         into_ref!(peri, rx, tx);
 | |
| 
 | |
|         rx.set_as_af(rx.af_num(), AFType::Input);
 | |
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | |
| 
 | |
|         rcc::enable_and_reset::<T>();
 | |
| 
 | |
|         {
 | |
|             T::regs().ier().write(|w| {
 | |
|                 w.set_errie(true);
 | |
|                 w.set_fmpie(0, true);
 | |
|                 w.set_fmpie(1, true);
 | |
|                 w.set_tmeie(true);
 | |
|                 w.set_bofie(true);
 | |
|                 w.set_epvie(true);
 | |
|                 w.set_ewgie(true);
 | |
|                 w.set_lecie(true);
 | |
|             });
 | |
| 
 | |
|             T::regs().mcr().write(|w| {
 | |
|                 // Enable timestamps on rx messages
 | |
| 
 | |
|                 w.set_ttcm(true);
 | |
|             });
 | |
|         }
 | |
| 
 | |
|         unsafe {
 | |
|             T::TXInterrupt::unpend();
 | |
|             T::TXInterrupt::enable();
 | |
| 
 | |
|             T::RX0Interrupt::unpend();
 | |
|             T::RX0Interrupt::enable();
 | |
| 
 | |
|             T::RX1Interrupt::unpend();
 | |
|             T::RX1Interrupt::enable();
 | |
| 
 | |
|             T::SCEInterrupt::unpend();
 | |
|             T::SCEInterrupt::enable();
 | |
|         }
 | |
| 
 | |
|         rx.set_as_af(rx.af_num(), AFType::Input);
 | |
|         tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | |
| 
 | |
|         Registers(T::regs()).leave_init_mode();
 | |
| 
 | |
|         Self { peri }
 | |
|     }
 | |
| 
 | |
|     /// Set CAN bit rate.
 | |
|     pub fn set_bitrate(&mut self, bitrate: u32) {
 | |
|         let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
 | |
|         self.modify_config().set_bit_timing(bit_timing);
 | |
|     }
 | |
| 
 | |
|     /// Configure bit timings and silent/loop-back mode.
 | |
|     ///
 | |
|     /// Calling this method will enter initialization mode. You must enable the peripheral
 | |
|     /// again afterwards with [`enable`](Self::enable).
 | |
|     pub fn modify_config(&mut self) -> CanConfig<'_, T> {
 | |
|         Registers(T::regs()).enter_init_mode();
 | |
| 
 | |
|         CanConfig { can: PhantomData }
 | |
|     }
 | |
| 
 | |
|     /// Enables the peripheral and synchronizes with the bus.
 | |
|     ///
 | |
|     /// 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 Registers(T::regs()).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;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus
 | |
|     /// while the peripheral is in sleep mode
 | |
|     pub fn set_automatic_wakeup(&mut self, enabled: bool) {
 | |
|         Registers(T::regs()).set_automatic_wakeup(enabled);
 | |
|     }
 | |
| 
 | |
|     /// Manually wake the peripheral from sleep mode.
 | |
|     ///
 | |
|     /// Waking the peripheral manually does not trigger a wake-up interrupt.
 | |
|     /// This will wait until the peripheral has acknowledged it has awoken from sleep mode
 | |
|     pub fn wakeup(&mut self) {
 | |
|         Registers(T::regs()).wakeup()
 | |
|     }
 | |
| 
 | |
|     /// Check if the peripheral is currently in sleep mode
 | |
|     pub fn is_sleeping(&self) -> bool {
 | |
|         T::regs().msr().read().slak()
 | |
|     }
 | |
| 
 | |
|     /// Put the peripheral in sleep mode
 | |
|     ///
 | |
|     /// When the peripherial is in sleep mode, messages can still be queued for transmission
 | |
|     /// and any previously received messages can be read from the receive FIFOs, however
 | |
|     /// no messages will be transmitted and no additional messages will be received.
 | |
|     ///
 | |
|     /// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
 | |
|     /// the peripheral will automatically wake and receive the incoming message.
 | |
|     pub async fn sleep(&mut self) {
 | |
|         T::regs().ier().modify(|i| i.set_slkie(true));
 | |
|         T::regs().mcr().modify(|m| m.set_sleep(true));
 | |
| 
 | |
|         poll_fn(|cx| {
 | |
|             T::state().err_waker.register(cx.waker());
 | |
|             if self.is_sleeping() {
 | |
|                 Poll::Ready(())
 | |
|             } else {
 | |
|                 Poll::Pending
 | |
|             }
 | |
|         })
 | |
|         .await;
 | |
| 
 | |
|         T::regs().ier().modify(|i| i.set_slkie(false));
 | |
|     }
 | |
| 
 | |
|     /// Queues the message to be sent.
 | |
|     ///
 | |
|     /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
 | |
|     pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
 | |
|         self.split().0.write(frame).await
 | |
|     }
 | |
| 
 | |
|     /// Attempts to transmit a frame without blocking.
 | |
|     ///
 | |
|     /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
 | |
|     pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
 | |
|         self.split().0.try_write(frame)
 | |
|     }
 | |
| 
 | |
|     /// Waits for a specific transmit mailbox to become empty
 | |
|     pub async fn flush(&self, mb: Mailbox) {
 | |
|         CanTx::<T>::flush_inner(mb).await
 | |
|     }
 | |
| 
 | |
|     /// Waits until any of the transmit mailboxes become empty
 | |
|     pub async fn flush_any(&self) {
 | |
|         CanTx::<T>::flush_any_inner().await
 | |
|     }
 | |
| 
 | |
|     /// Waits until all of the transmit mailboxes become empty
 | |
|     pub async fn flush_all(&self) {
 | |
|         CanTx::<T>::flush_all_inner().await
 | |
|     }
 | |
| 
 | |
|     /// 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 {
 | |
|         Registers(T::regs()).abort(mailbox)
 | |
|     }
 | |
| 
 | |
|     /// Returns `true` if no frame is pending for transmission.
 | |
|     pub fn is_transmitter_idle(&self) -> bool {
 | |
|         Registers(T::regs()).is_idle()
 | |
|     }
 | |
| 
 | |
|     /// Read a CAN frame.
 | |
|     ///
 | |
|     /// If no CAN frame is in the RX buffer, this will wait until there is one.
 | |
|     ///
 | |
|     /// Returns a tuple of the time the message was received and the message frame
 | |
|     pub async fn read(&mut self) -> Result<Envelope, BusError> {
 | |
|         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> {
 | |
|         T::state().rx_mode.try_read::<T>()
 | |
|     }
 | |
| 
 | |
|     /// Waits while receive queue is empty.
 | |
|     pub async fn wait_not_empty(&mut self) {
 | |
|         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>) {
 | |
|         (
 | |
|             CanTx {
 | |
|                 _peri: unsafe { self.peri.clone_unchecked() },
 | |
|             },
 | |
|             CanRx {
 | |
|                 peri: unsafe { self.peri.clone_unchecked() },
 | |
|             },
 | |
|         )
 | |
|     }
 | |
| 
 | |
|     /// 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),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'d, T: FilterOwner> Can<'d, T> {
 | |
|     /// 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<'_, T> {
 | |
|         unsafe { MasterFilters::new(T::regs()) }
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// 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> {
 | |
|     _peri: PeripheralRef<'d, T>,
 | |
| }
 | |
| 
 | |
| impl<'d, T: Instance> CanTx<'d, T> {
 | |
|     /// Queues the message to be sent.
 | |
|     ///
 | |
|     /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
 | |
|     pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
 | |
|         poll_fn(|cx| {
 | |
|             T::state().tx_mode.register(cx.waker());
 | |
|             if let Ok(status) = Registers(T::regs()).transmit(frame) {
 | |
|                 return Poll::Ready(status);
 | |
|             }
 | |
| 
 | |
|             Poll::Pending
 | |
|         })
 | |
|         .await
 | |
|     }
 | |
| 
 | |
|     /// Attempts to transmit a frame without blocking.
 | |
|     ///
 | |
|     /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
 | |
|     pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
 | |
|         Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full)
 | |
|     }
 | |
| 
 | |
|     async fn flush_inner(mb: Mailbox) {
 | |
|         poll_fn(|cx| {
 | |
|             T::state().tx_mode.register(cx.waker());
 | |
|             if T::regs().tsr().read().tme(mb.index()) {
 | |
|                 return Poll::Ready(());
 | |
|             }
 | |
| 
 | |
|             Poll::Pending
 | |
|         })
 | |
|         .await;
 | |
|     }
 | |
| 
 | |
|     /// Waits for a specific transmit mailbox to become empty
 | |
|     pub async fn flush(&self, mb: Mailbox) {
 | |
|         Self::flush_inner(mb).await
 | |
|     }
 | |
| 
 | |
|     async fn flush_any_inner() {
 | |
|         poll_fn(|cx| {
 | |
|             T::state().tx_mode.register(cx.waker());
 | |
| 
 | |
|             let tsr = T::regs().tsr().read();
 | |
|             if tsr.tme(Mailbox::Mailbox0.index())
 | |
|                 || tsr.tme(Mailbox::Mailbox1.index())
 | |
|                 || tsr.tme(Mailbox::Mailbox2.index())
 | |
|             {
 | |
|                 return Poll::Ready(());
 | |
|             }
 | |
| 
 | |
|             Poll::Pending
 | |
|         })
 | |
|         .await;
 | |
|     }
 | |
| 
 | |
|     /// Waits until any of the transmit mailboxes become empty
 | |
|     pub async fn flush_any(&self) {
 | |
|         Self::flush_any_inner().await
 | |
|     }
 | |
| 
 | |
|     async fn flush_all_inner() {
 | |
|         poll_fn(|cx| {
 | |
|             T::state().tx_mode.register(cx.waker());
 | |
| 
 | |
|             let tsr = T::regs().tsr().read();
 | |
|             if tsr.tme(Mailbox::Mailbox0.index())
 | |
|                 && tsr.tme(Mailbox::Mailbox1.index())
 | |
|                 && tsr.tme(Mailbox::Mailbox2.index())
 | |
|             {
 | |
|                 return Poll::Ready(());
 | |
|             }
 | |
| 
 | |
|             Poll::Pending
 | |
|         })
 | |
|         .await;
 | |
|     }
 | |
| 
 | |
|     /// Waits until all of the transmit mailboxes become empty
 | |
|     pub async fn flush_all(&self) {
 | |
|         Self::flush_all_inner().await
 | |
|     }
 | |
| 
 | |
|     /// 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 {
 | |
|         Registers(T::regs()).abort(mailbox)
 | |
|     }
 | |
| 
 | |
|     /// Returns `true` if no frame is pending for transmission.
 | |
|     pub fn is_idle(&self) -> bool {
 | |
|         Registers(T::regs()).is_idle()
 | |
|     }
 | |
| 
 | |
|     /// 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, 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: CanTx<'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: CanTx<'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 = super::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> {
 | |
|     peri: PeripheralRef<'d, T>,
 | |
| }
 | |
| 
 | |
| impl<'d, T: Instance> CanRx<'d, T> {
 | |
|     /// Read a CAN frame.
 | |
|     ///
 | |
|     /// If no CAN frame is in the RX buffer, this will wait until there is one.
 | |
|     ///
 | |
|     /// Returns a tuple of the time the message was received and the message frame
 | |
|     pub async fn read(&mut self) -> Result<Envelope, BusError> {
 | |
|         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> {
 | |
|         T::state().rx_mode.try_read::<T>()
 | |
|     }
 | |
| 
 | |
|     /// Waits while receive queue is empty.
 | |
|     pub async fn wait_not_empty(&mut self) {
 | |
|         T::state().rx_mode.wait_not_empty::<T>().await
 | |
|     }
 | |
| 
 | |
|     /// 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, 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: CanRx<'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: CanRx<'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 = super::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 {
 | |
|                     if let Some(err) = Registers(T::regs()).curr_error() {
 | |
|                         return Err(TryReadError::BusError(err));
 | |
|                     } else {
 | |
|                         Err(TryReadError::Empty)
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             _ => {
 | |
|                 panic!("Bad Mode")
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// 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()
 | |
|     }
 | |
| }
 | |
| 
 | |
| 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());
 | |
|         });
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'d, T: Instance> Drop for Can<'d, T> {
 | |
|     fn drop(&mut self) {
 | |
|         // Cannot call `free()` because it moves the instance.
 | |
|         // Manually reset the peripheral.
 | |
|         T::regs().mcr().write(|w| w.set_reset(true));
 | |
|         rcc::disable::<T>();
 | |
|     }
 | |
| }
 | |
| 
 | |
| /// Identifies one of the two receive FIFOs.
 | |
| #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 | |
| #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | |
| pub enum Fifo {
 | |
|     /// First receive FIFO
 | |
|     Fifo0 = 0,
 | |
|     /// Second receive FIFO
 | |
|     Fifo1 = 1,
 | |
| }
 | |
| 
 | |
| /// Identifies one of the three transmit mailboxes.
 | |
| #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
 | |
| #[cfg_attr(feature = "defmt", derive(defmt::Format))]
 | |
| pub enum Mailbox {
 | |
|     /// Transmit mailbox 0
 | |
|     Mailbox0 = 0,
 | |
|     /// Transmit mailbox 1
 | |
|     Mailbox1 = 1,
 | |
|     /// Transmit mailbox 2
 | |
|     Mailbox2 = 2,
 | |
| }
 | |
| 
 | |
| /// Contains information about a frame enqueued for transmission via [`Can::transmit`] or
 | |
| /// [`Tx::transmit`].
 | |
| pub struct TransmitStatus {
 | |
|     dequeued_frame: Option<Frame>,
 | |
|     mailbox: Mailbox,
 | |
| }
 | |
| 
 | |
| impl TransmitStatus {
 | |
|     /// Returns the lower-priority frame that was dequeued to make space for the new frame.
 | |
|     #[inline]
 | |
|     pub fn dequeued_frame(&self) -> Option<&Frame> {
 | |
|         self.dequeued_frame.as_ref()
 | |
|     }
 | |
| 
 | |
|     /// Returns the [`Mailbox`] the frame was enqueued in.
 | |
|     #[inline]
 | |
|     pub fn mailbox(&self) -> Mailbox {
 | |
|         self.mailbox
 | |
|     }
 | |
| }
 | |
| 
 | |
| pub(crate) enum RxMode {
 | |
|     NonBuffered(AtomicWaker),
 | |
|     Buffered(super::common::ClassicBufferedRxInner),
 | |
| }
 | |
| 
 | |
| impl RxMode {
 | |
|     pub fn on_interrupt<T: Instance>(&self, fifo: RxFifo) {
 | |
|         match self {
 | |
|             Self::NonBuffered(waker) => {
 | |
|                 // Disable interrupts until read
 | |
|                 let fifo_idx = match fifo {
 | |
|                     RxFifo::Fifo0 => 0usize,
 | |
|                     RxFifo::Fifo1 => 1usize,
 | |
|                 };
 | |
|                 T::regs().ier().write(|w| {
 | |
|                     w.set_fmpie(fifo_idx, false);
 | |
|                 });
 | |
|                 waker.wake();
 | |
|             }
 | |
|             Self::Buffered(buf) => {
 | |
|                 loop {
 | |
|                     match Registers(T::regs()).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 = Registers(T::regs());
 | |
|                 if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
 | |
|                     T::regs().ier().write(|w| {
 | |
|                         w.set_fmpie(0, true);
 | |
|                     });
 | |
|                     Ok(msg)
 | |
|                 } else if let Some(msg) = registers.receive_fifo(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());
 | |
|                     if Registers(T::regs()).receive_frame_available() {
 | |
|                         Poll::Ready(())
 | |
|                     } else {
 | |
|                         Poll::Pending
 | |
|                     }
 | |
|                 })
 | |
|                 .await
 | |
|             }
 | |
|             _ => {
 | |
|                 panic!("Bad Mode")
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| enum TxMode {
 | |
|     NonBuffered(AtomicWaker),
 | |
|     Buffered(super::common::ClassicBufferedTxInner),
 | |
| }
 | |
| 
 | |
| impl TxMode {
 | |
|     pub fn buffer_free<T: Instance>(&self) -> bool {
 | |
|         let tsr = T::regs().tsr().read();
 | |
|         tsr.tme(Mailbox::Mailbox0.index()) || tsr.tme(Mailbox::Mailbox1.index()) || tsr.tme(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) => {
 | |
|                             _ = Registers(T::regs()).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(crate) rx_mode: RxMode,
 | |
|     pub(crate) tx_mode: TxMode,
 | |
|     pub err_waker: AtomicWaker,
 | |
| }
 | |
| 
 | |
| impl State {
 | |
|     pub const fn new() -> Self {
 | |
|         Self {
 | |
|             rx_mode: RxMode::NonBuffered(AtomicWaker::new()),
 | |
|             tx_mode: TxMode::NonBuffered(AtomicWaker::new()),
 | |
|             err_waker: AtomicWaker::new(),
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| trait SealedInstance {
 | |
|     fn regs() -> crate::pac::can::Can;
 | |
|     fn state() -> &'static State;
 | |
|     unsafe fn mut_state() -> &'static mut State;
 | |
| }
 | |
| 
 | |
| /// CAN instance trait.
 | |
| #[allow(private_bounds)]
 | |
| pub trait Instance: Peripheral<P = Self> + SealedInstance + RccPeripheral + 'static {
 | |
|     /// TX interrupt for this instance.
 | |
|     type TXInterrupt: crate::interrupt::typelevel::Interrupt;
 | |
|     /// RX0 interrupt for this instance.
 | |
|     type RX0Interrupt: crate::interrupt::typelevel::Interrupt;
 | |
|     /// RX1 interrupt for this instance.
 | |
|     type RX1Interrupt: crate::interrupt::typelevel::Interrupt;
 | |
|     /// SCE interrupt for this instance.
 | |
|     type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
 | |
| }
 | |
| 
 | |
| /// A bxCAN instance that owns filter banks.
 | |
| ///
 | |
| /// In master-slave-instance setups, only the master instance owns the filter banks, and needs to
 | |
| /// split some of them off for use by the slave instance. In that case, the master instance should
 | |
| /// implement [`FilterOwner`] and [`MasterInstance`], while the slave instance should only implement
 | |
| /// [`Instance`].
 | |
| ///
 | |
| /// In single-instance configurations, the instance owns all filter banks and they can not be split
 | |
| /// off. In that case, the instance should implement [`Instance`] and [`FilterOwner`].
 | |
| ///
 | |
| /// # Safety
 | |
| ///
 | |
| /// This trait must only be implemented if the instance does, in fact, own its associated filter
 | |
| /// banks, and `NUM_FILTER_BANKS` must be correct.
 | |
| pub unsafe trait FilterOwner: Instance {
 | |
|     /// The total number of filter banks available to the instance.
 | |
|     ///
 | |
|     /// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet.
 | |
|     const NUM_FILTER_BANKS: u8;
 | |
| }
 | |
| 
 | |
| /// A bxCAN master instance that shares filter banks with a slave instance.
 | |
| ///
 | |
| /// In master-slave-instance setups, this trait should be implemented for the master instance.
 | |
| ///
 | |
| /// # Safety
 | |
| ///
 | |
| /// This trait must only be implemented when there is actually an associated slave instance.
 | |
| pub unsafe trait MasterInstance: FilterOwner {}
 | |
| 
 | |
| foreach_peripheral!(
 | |
|     (can, $inst:ident) => {
 | |
|         impl SealedInstance for peripherals::$inst {
 | |
| 
 | |
|             fn regs() -> crate::pac::can::Can {
 | |
|                 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 {
 | |
|                 unsafe { peripherals::$inst::mut_state() }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         impl Instance for peripherals::$inst {
 | |
|             type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX;
 | |
|             type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0;
 | |
|             type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1;
 | |
|             type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE;
 | |
|         }
 | |
|     };
 | |
| );
 | |
| 
 | |
| foreach_peripheral!(
 | |
|     (can, CAN) => {
 | |
|         unsafe impl FilterOwner for peripherals::CAN {
 | |
|             const NUM_FILTER_BANKS: u8 = 14;
 | |
|         }
 | |
|     };
 | |
|     // CAN1 and CAN2 is a combination of master and slave instance.
 | |
|     // CAN1 owns the filter bank and needs to be enabled in order
 | |
|     // for CAN2 to receive messages.
 | |
|     (can, CAN1) => {
 | |
|         cfg_if::cfg_if! {
 | |
|             if #[cfg(all(
 | |
|                 any(stm32l4, stm32f72, stm32f73),
 | |
|                 not(any(stm32l49, stm32l4a))
 | |
|             ))] {
 | |
|                 // Most L4 devices and some F7 devices use the name "CAN1"
 | |
|                 // even if there is no "CAN2" peripheral.
 | |
|                 unsafe impl FilterOwner for peripherals::CAN1 {
 | |
|                     const NUM_FILTER_BANKS: u8 = 14;
 | |
|                 }
 | |
|             } else {
 | |
|                 unsafe impl FilterOwner for peripherals::CAN1 {
 | |
|                     const NUM_FILTER_BANKS: u8 = 28;
 | |
|                 }
 | |
|                 unsafe impl MasterInstance for peripherals::CAN1 {}
 | |
|             }
 | |
|         }
 | |
|     };
 | |
|     (can, CAN3) => {
 | |
|         unsafe impl FilterOwner for peripherals::CAN3 {
 | |
|             const NUM_FILTER_BANKS: u8 = 14;
 | |
|         }
 | |
|     };
 | |
| );
 | |
| 
 | |
| pin_trait!(RxPin, Instance);
 | |
| pin_trait!(TxPin, Instance);
 | |
| 
 | |
| trait Index {
 | |
|     fn index(&self) -> usize;
 | |
| }
 | |
| 
 | |
| impl Index for Mailbox {
 | |
|     fn index(&self) -> usize {
 | |
|         match self {
 | |
|             Mailbox::Mailbox0 => 0,
 | |
|             Mailbox::Mailbox1 => 1,
 | |
|             Mailbox::Mailbox2 => 2,
 | |
|         }
 | |
|     }
 | |
| }
 |