commit
864202a23a
@ -1,3 +1,4 @@
|
|||||||
|
use core::cell::{RefCell, RefMut};
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ops::{Deref, DerefMut};
|
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> {
|
pub struct Can<'d, T: Instance> {
|
||||||
can: bxcan::Can<BxcanInstance<'d, T>>,
|
pub can: RefCell<bxcan::Can<BxcanInstance<'d, T>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -147,19 +148,24 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||||
|
|
||||||
let can = bxcan::Can::builder(BxcanInstance(peri)).leave_disabled();
|
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) {
|
pub fn set_bitrate(&mut self, bitrate: u32) {
|
||||||
let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
|
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
|
/// Queues the message to be sent but exerts backpressure
|
||||||
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
|
pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
T::state().tx_waker.register(cx.waker());
|
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);
|
return Poll::Ready(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,6 +347,79 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
// Pack into BTR register values
|
// Pack into BTR register values
|
||||||
Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler as u32 - 1))
|
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 {
|
enum RxFifo {
|
||||||
@ -358,7 +437,7 @@ impl<'d, T: Instance> Drop for Can<'d, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Deref 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 {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.can
|
&self.can
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
use cortex_m_rt::entry;
|
|
||||||
use defmt::*;
|
use defmt::*;
|
||||||
|
use embassy_executor::Spawner;
|
||||||
use embassy_stm32::bind_interrupts;
|
use embassy_stm32::bind_interrupts;
|
||||||
use embassy_stm32::can::bxcan::filter::Mask32;
|
use embassy_stm32::can::bxcan::filter::Mask32;
|
||||||
use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
|
use embassy_stm32::can::bxcan::{Fifo, Frame, StandardId};
|
||||||
@ -19,8 +19,8 @@ bind_interrupts!(struct Irqs {
|
|||||||
CAN1_TX => TxInterruptHandler<CAN1>;
|
CAN1_TX => TxInterruptHandler<CAN1>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[entry]
|
#[embassy_executor::main]
|
||||||
fn main() -> ! {
|
async fn main(_spawner: Spawner) {
|
||||||
info!("Hello World!");
|
info!("Hello World!");
|
||||||
|
|
||||||
let mut p = embassy_stm32::init(Default::default());
|
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);
|
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_bit_timing(0x001c0003) // http://www.bittiming.can-wiki.info/
|
||||||
.set_loopback(true) // Receive own frames
|
.set_loopback(true) // Receive own frames
|
||||||
.set_silent(true)
|
.set_silent(true)
|
||||||
@ -45,9 +48,8 @@ fn main() -> ! {
|
|||||||
let mut i: u8 = 0;
|
let mut i: u8 = 0;
|
||||||
loop {
|
loop {
|
||||||
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
|
let tx_frame = Frame::new_data(unwrap!(StandardId::new(i as _)), [i]);
|
||||||
unwrap!(nb::block!(can.transmit(&tx_frame)));
|
can.write(&tx_frame).await;
|
||||||
while !can.is_transmitter_idle() {}
|
let (_, rx_frame) = can.read().await.unwrap();
|
||||||
let rx_frame = unwrap!(nb::block!(can.receive()));
|
|
||||||
info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
|
info!("loopback frame {=u8}", unwrap!(rx_frame.data())[0]);
|
||||||
i += 1;
|
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...");
|
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.set_bitrate(1_000_000);
|
||||||
can.modify_config()
|
can.as_mut()
|
||||||
|
.modify_config()
|
||||||
.set_loopback(true) // Receive own frames
|
.set_loopback(true) // Receive own frames
|
||||||
.set_silent(true)
|
.set_silent(true)
|
||||||
// .set_bit_timing(0x001c0003)
|
// .set_bit_timing(0x001c0003)
|
||||||
|
Loading…
Reference in New Issue
Block a user