@@ -1,3 +1,4 @@
 | 
			
		||||
use core::cell::{RefCell, RefMut};
 | 
			
		||||
use core::future::poll_fn;
 | 
			
		||||
use core::marker::PhantomData;
 | 
			
		||||
use core::ops::{Deref, DerefMut};
 | 
			
		||||
@@ -72,7 +73,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct Can<'d, T: Instance> {
 | 
			
		||||
    can: bxcan::Can<BxcanInstance<'d, T>>,
 | 
			
		||||
    pub can: RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
@@ -147,19 +148,24 @@ impl<'d, T: Instance> Can<'d, T> {
 | 
			
		||||
        tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
 | 
			
		||||
 | 
			
		||||
        let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
 | 
			
		||||
        Self { can }
 | 
			
		||||
        let can_ref_cell = RefCell::new(can);
 | 
			
		||||
        Self { can: can_ref_cell }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_bitrate(&mut self, bitrate: u32) {
 | 
			
		||||
        let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
 | 
			
		||||
        self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
 | 
			
		||||
        self.can
 | 
			
		||||
            .borrow_mut()
 | 
			
		||||
            .modify_config()
 | 
			
		||||
            .set_bit_timing(bit_timing)
 | 
			
		||||
            .leave_disabled();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Queues the message to be sent but exerts backpressure
 | 
			
		||||
    pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
 | 
			
		||||
        poll_fn(|cx| {
 | 
			
		||||
            T::state().tx_waker.register(cx.waker());
 | 
			
		||||
            if let Ok(status) = self.can.transmit(frame) {
 | 
			
		||||
            if let Ok(status) = self.can.borrow_mut().transmit(frame) {
 | 
			
		||||
                return Poll::Ready(status);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -341,6 +347,79 @@ impl<'d, T: Instance> Can<'d, T> {
 | 
			
		||||
        // Pack into BTR register values
 | 
			
		||||
        Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn split<'c>(&'c self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
 | 
			
		||||
        (CanTx { can: &self.can }, CanRx { can: &self.can })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn as_mut(&self) -> RefMut<'_, bxcan::Can<BxcanInstance<'d, T>>> {
 | 
			
		||||
        self.can.borrow_mut()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct CanTx<'c, 'd, T: Instance> {
 | 
			
		||||
    can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
 | 
			
		||||
    pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
 | 
			
		||||
        poll_fn(|cx| {
 | 
			
		||||
            T::state().tx_waker.register(cx.waker());
 | 
			
		||||
            if let Ok(status) = self.can.borrow_mut().transmit(frame) {
 | 
			
		||||
                return Poll::Ready(status);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Poll::Pending
 | 
			
		||||
        })
 | 
			
		||||
        .await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn flush(&self, mb: bxcan::Mailbox) {
 | 
			
		||||
        poll_fn(|cx| {
 | 
			
		||||
            T::state().tx_waker.register(cx.waker());
 | 
			
		||||
            if T::regs().tsr().read().tme(mb.index()) {
 | 
			
		||||
                return Poll::Ready(());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Poll::Pending
 | 
			
		||||
        })
 | 
			
		||||
        .await;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
pub struct CanRx<'c, 'd, T: Instance> {
 | 
			
		||||
    can: &'c RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
 | 
			
		||||
    pub async fn read(&mut self) -> Result<(u16, bxcan::Frame), BusError> {
 | 
			
		||||
        poll_fn(|cx| {
 | 
			
		||||
            T::state().err_waker.register(cx.waker());
 | 
			
		||||
            if let Poll::Ready((time, frame)) = T::state().rx_queue.recv().poll_unpin(cx) {
 | 
			
		||||
                return Poll::Ready(Ok((time, frame)));
 | 
			
		||||
            } else if let Some(err) = self.curr_error() {
 | 
			
		||||
                return Poll::Ready(Err(err));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            Poll::Pending
 | 
			
		||||
        })
 | 
			
		||||
        .await
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn curr_error(&self) -> Option<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);
 | 
			
		||||
        }
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum RxFifo {
 | 
			
		||||
@@ -358,7 +437,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<'d, T: Instance> Deref for Can<'d, T> {
 | 
			
		||||
    type Target = bxcan::Can<BxcanInstance<'d, T>>;
 | 
			
		||||
    type Target = RefCell<bxcan::Can<BxcanInstance<'d, T>>>;
 | 
			
		||||
 | 
			
		||||
    fn deref(&self) -> &Self::Target {
 | 
			
		||||
        &self.can
 | 
			
		||||
 
 | 
			
		||||
@@ -2,8 +2,8 @@
 | 
			
		||||
#![no_main]
 | 
			
		||||
#![feature(type_alias_impl_trait)]
 | 
			
		||||
 | 
			
		||||
use cortex_m_rt::entry;
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::bind_interrupts;
 | 
			
		||||
use embassy_stm32::can::bxcan::filter::Mask32;
 | 
			
		||||
use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
 | 
			
		||||
@@ -19,8 +19,8 @@ bind_interrupts!(struct Irqs {
 | 
			
		||||
    CAN1_TX => TxInterruptHandler<CAN1>;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
#[entry]
 | 
			
		||||
fn main() -> ! {
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(_spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let mut p = embassy_stm32::init(Default::default());
 | 
			
		||||
@@ -34,9 +34,12 @@ fn main() -> ! {
 | 
			
		||||
 | 
			
		||||
    let mut can = Can::new(p.CAN1, p.PA11, p.PA12, Irqs);
 | 
			
		||||
 | 
			
		||||
    can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 | 
			
		||||
    can.as_mut()
 | 
			
		||||
        .modify_filters()
 | 
			
		||||
        .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 | 
			
		||||
 | 
			
		||||
    can.modify_config()
 | 
			
		||||
    can.as_mut()
 | 
			
		||||
        .modify_config()
 | 
			
		||||
        .set_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/
 | 
			
		||||
        .set_loopback(true) // Receive own frames
 | 
			
		||||
        .set_silent(true)
 | 
			
		||||
@@ -45,9 +48,8 @@ fn main() -> ! {
 | 
			
		||||
    let mut i: u8 = 0;
 | 
			
		||||
    loop {
 | 
			
		||||
        let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
 | 
			
		||||
        unwrap!(nb::block!(can.transmit(&tx_frame)));
 | 
			
		||||
        while !can.is_transmitter_idle() {}
 | 
			
		||||
        let rx_frame = unwrap!(nb::block!(can.receive()));
 | 
			
		||||
        can.write(&tx_frame).await;
 | 
			
		||||
        let (_, rx_frame) = can.read().await.unwrap();
 | 
			
		||||
        info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
 | 
			
		||||
        i += 1;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										66
									
								
								examples/stm32f7/src/bin/can.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								examples/stm32f7/src/bin/can.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
			
		||||
#![no_std]
 | 
			
		||||
#![no_main]
 | 
			
		||||
#![feature(type_alias_impl_trait)]
 | 
			
		||||
 | 
			
		||||
use defmt::*;
 | 
			
		||||
use embassy_executor::Spawner;
 | 
			
		||||
use embassy_stm32::bind_interrupts;
 | 
			
		||||
use embassy_stm32::can::bxcan::filter::Mask32;
 | 
			
		||||
use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
 | 
			
		||||
use embassy_stm32::can::{
 | 
			
		||||
    Can, CanTx, Rx0InterruptHandler, Rx1InterruptHandler, SceInterruptHandler, TxInterruptHandler,
 | 
			
		||||
};
 | 
			
		||||
use embassy_stm32::gpio::{Input, Pull};
 | 
			
		||||
use embassy_stm32::peripherals::CAN3;
 | 
			
		||||
use {defmt_rtt as _, panic_probe as _};
 | 
			
		||||
 | 
			
		||||
bind_interrupts!(struct Irqs {
 | 
			
		||||
    CAN3_RX0 => Rx0InterruptHandler<CAN3>;
 | 
			
		||||
    CAN3_RX1 => Rx1InterruptHandler<CAN3>;
 | 
			
		||||
    CAN3_SCE => SceInterruptHandler<CAN3>;
 | 
			
		||||
    CAN3_TX => TxInterruptHandler<CAN3>;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::task]
 | 
			
		||||
pub async fn send_can_message(tx: &'static mut CanTx<'static, 'static, CAN3>) {
 | 
			
		||||
    loop {
 | 
			
		||||
        let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), [0]);
 | 
			
		||||
        tx.write(&frame).await;
 | 
			
		||||
        embassy_time::Timer::after(embassy_time::Duration::from_secs(1)).await;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[embassy_executor::main]
 | 
			
		||||
async fn main(spawner: Spawner) {
 | 
			
		||||
    info!("Hello World!");
 | 
			
		||||
 | 
			
		||||
    let mut p = embassy_stm32::init(Default::default());
 | 
			
		||||
 | 
			
		||||
    // The next two lines are a workaround for testing without transceiver.
 | 
			
		||||
    // To synchronise to the bus the RX input needs to see a high level.
 | 
			
		||||
    // Use `mem::forget()` to release the borrow on the pin but keep the
 | 
			
		||||
    // pull-up resistor enabled.
 | 
			
		||||
    let rx_pin = Input::new(&mut p.PA15, Pull::Up);
 | 
			
		||||
    core::mem::forget(rx_pin);
 | 
			
		||||
 | 
			
		||||
    let can: &'static mut Can<'static, CAN3> = static_cell::make_static!(Can::new(p.CAN3, p.PA8, p.PA15, Irqs));
 | 
			
		||||
    can.as_mut()
 | 
			
		||||
        .modify_filters()
 | 
			
		||||
        .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 | 
			
		||||
 | 
			
		||||
    can.as_mut()
 | 
			
		||||
        .modify_config()
 | 
			
		||||
        .set_bit_timing(0x001c0001) // http://www.bittiming.can-wiki.info/
 | 
			
		||||
        .set_loopback(true)
 | 
			
		||||
        .enable();
 | 
			
		||||
 | 
			
		||||
    let (tx, mut rx) = can.split();
 | 
			
		||||
 | 
			
		||||
    let tx: &'static mut CanTx<'static, 'static, CAN3> = static_cell::make_static!(tx);
 | 
			
		||||
    spawner.spawn(send_can_message(tx)).unwrap();
 | 
			
		||||
 | 
			
		||||
    loop {
 | 
			
		||||
        let frame = rx.read().await.unwrap();
 | 
			
		||||
        println!("Received: {:?}", frame);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -43,10 +43,13 @@ async fn main(_spawner: Spawner) {
 | 
			
		||||
 | 
			
		||||
    info!("Configuring can...");
 | 
			
		||||
 | 
			
		||||
    can.modify_filters().enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 | 
			
		||||
    can.as_mut()
 | 
			
		||||
        .modify_filters()
 | 
			
		||||
        .enable_bank(0, Fifo::Fifo0, Mask32::accept_all());
 | 
			
		||||
 | 
			
		||||
    can.set_bitrate(1_000_000);
 | 
			
		||||
    can.modify_config()
 | 
			
		||||
    can.as_mut()
 | 
			
		||||
        .modify_config()
 | 
			
		||||
        .set_loopback(true) // Receive own frames
 | 
			
		||||
        .set_silent(true)
 | 
			
		||||
        // .set_bit_timing(0x001c0003)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user