Merge pull request #1578 from schphil/can-split

stm32 can split method
This commit is contained in:
xoviat 2023-07-05 23:27:53 +00:00 committed by GitHub
commit 864202a23a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 165 additions and 15 deletions

View File

@ -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

View File

@ -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;
} }

View 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);
}
}

View File

@ -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)