commit
864202a23a
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user