Add a buffered mode.

This commit is contained in:
Corey Schuhen 2024-02-17 18:12:47 +10:00
parent 91c75c92a0
commit 5ad291b708
2 changed files with 323 additions and 7 deletions

View File

@ -5,6 +5,8 @@ use core::task::Poll;
pub mod fd;
use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use fd::config::*;
use fd::filter::*;
@ -49,6 +51,26 @@ impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0Interrup
match &T::state().tx_mode {
sealed::TxMode::NonBuffered(waker) => waker.wake(),
sealed::TxMode::ClassicBuffered(buf) => {
if !T::registers().tx_queue_is_full() {
match buf.tx_receiver.try_receive() {
Ok(frame) => {
_ = T::registers().write_classic(&frame);
}
Err(_) => {}
}
}
}
sealed::TxMode::FdBuffered(buf) => {
if !T::registers().tx_queue_is_full() {
match buf.tx_receiver.try_receive() {
Ok(frame) => {
_ = T::registers().write_fd(&frame);
}
Err(_) => {}
}
}
}
}
}
@ -405,6 +427,179 @@ where
)
}
/// Return a buffered instance of driver without CAN FD support. User must supply Buffers
pub fn buffered<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
&self,
tx_buf: &'static mut TxBuf<TX_BUF_SIZE>,
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
) -> BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> {
BufferedCan::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
}
/// Return a buffered instance of driver with CAN FD support. User must supply Buffers
pub fn buffered_fd<const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>(
&self,
tx_buf: &'static mut TxFdBuf<TX_BUF_SIZE>,
rxb: &'static mut RxFdBuf<RX_BUF_SIZE>,
) -> BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE> {
BufferedCanFd::new(PhantomData::<T>, T::regs(), self._mode, tx_buf, rxb)
}
}
/// User supplied buffer for RX Buffering
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, (ClassicFrame, Timestamp), BUF_SIZE>;
/// User supplied buffer for TX buffering
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, ClassicFrame, BUF_SIZE>;
/// Buffered FDCAN Instance
#[allow(dead_code)]
pub struct BufferedCan<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: PhantomData<M>,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
}
impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
where
M: FdcanOperatingMode,
{
fn new(
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: PhantomData<M>,
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
) -> Self {
BufferedCan {
_instance1,
_instance2,
_mode,
tx_buf,
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 = sealed::ClassicBufferedRxInner {
rx_sender: self.rx_buf.sender().into(),
};
let tx_inner = sealed::ClassicBufferedTxInner {
tx_receiver: self.tx_buf.receiver().into(),
};
T::mut_state().rx_mode = sealed::RxMode::ClassicBuffered(rx_inner);
T::mut_state().tx_mode = sealed::TxMode::ClassicBuffered(tx_inner);
});
self
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: ClassicFrame) {
self.tx_buf.send(frame).await;
T::IT0Interrupt::pend(); // Wake for Tx
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(ClassicFrame, Timestamp), BusError> {
Ok(self.rx_buf.receive().await)
}
}
impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
for BufferedCan<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
where
M: FdcanOperatingMode,
{
fn drop(&mut self) {
critical_section::with(|_| unsafe {
T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
});
}
}
/// User supplied buffer for RX Buffering
pub type RxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, (FdFrame, Timestamp), BUF_SIZE>;
/// User supplied buffer for TX buffering
pub type TxFdBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, FdFrame, BUF_SIZE>;
/// Buffered FDCAN Instance
#[allow(dead_code)]
pub struct BufferedCanFd<'d, T: Instance, M: FdcanOperatingMode, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: PhantomData<M>,
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
}
impl<'c, 'd, T: Instance, M: Transmit, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
where
M: FdcanOperatingMode,
{
fn new(
_instance1: PhantomData<T>,
_instance2: &'d crate::pac::can::Fdcan,
_mode: PhantomData<M>,
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
) -> Self {
BufferedCanFd {
_instance1,
_instance2,
_mode,
tx_buf,
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 = sealed::FdBufferedRxInner {
rx_sender: self.rx_buf.sender().into(),
};
let tx_inner = sealed::FdBufferedTxInner {
tx_receiver: self.tx_buf.receiver().into(),
};
T::mut_state().rx_mode = sealed::RxMode::FdBuffered(rx_inner);
T::mut_state().tx_mode = sealed::TxMode::FdBuffered(tx_inner);
});
self
}
/// Async write frame to TX buffer.
pub async fn write(&mut self, frame: FdFrame) {
self.tx_buf.send(frame).await;
T::IT0Interrupt::pend(); // Wake for Tx
}
/// Async read frame from RX buffer.
pub async fn read(&mut self) -> Result<(FdFrame, Timestamp), BusError> {
Ok(self.rx_buf.receive().await)
}
}
impl<'c, 'd, T: Instance, M, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Drop
for BufferedCanFd<'d, T, M, TX_BUF_SIZE, RX_BUF_SIZE>
where
M: FdcanOperatingMode,
{
fn drop(&mut self) {
critical_section::with(|_| unsafe {
T::mut_state().rx_mode = sealed::RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
T::mut_state().tx_mode = sealed::TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
});
}
}
/// FDCAN Rx only Instance
@ -456,18 +651,39 @@ pub(crate) mod sealed {
use core::future::poll_fn;
use core::task::Poll;
use embassy_sync::channel::{DynamicReceiver, DynamicSender};
use embassy_sync::waitqueue::AtomicWaker;
use crate::can::_version::{BusError, Timestamp};
use crate::can::frame::{ClassicFrame, FdFrame};
pub struct ClassicBufferedRxInner {
pub rx_sender: DynamicSender<'static, (ClassicFrame, Timestamp)>,
}
pub struct ClassicBufferedTxInner {
pub tx_receiver: DynamicReceiver<'static, ClassicFrame>,
}
pub struct FdBufferedRxInner {
pub rx_sender: DynamicSender<'static, (FdFrame, Timestamp)>,
}
pub struct FdBufferedTxInner {
pub tx_receiver: DynamicReceiver<'static, FdFrame>,
}
pub enum RxMode {
NonBuffered(AtomicWaker),
ClassicBuffered(ClassicBufferedRxInner),
FdBuffered(FdBufferedRxInner),
}
impl RxMode {
pub fn register(&self, arg: &core::task::Waker) {
match self {
RxMode::NonBuffered(waker) => waker.register(arg),
_ => {
panic!("Bad Mode")
}
}
}
@ -477,6 +693,18 @@ pub(crate) mod sealed {
RxMode::NonBuffered(waker) => {
waker.wake();
}
RxMode::ClassicBuffered(buf) => {
if let Some(r) = T::registers().read_classic(fifonr) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1);
let _ = buf.rx_sender.try_send((r.0, ts));
}
}
RxMode::FdBuffered(buf) => {
if let Some(r) = T::registers().read_fd(fifonr) {
let ts = T::calc_timestamp(T::state().ns_per_timer_tick, r.1);
let _ = buf.rx_sender.try_send((r.0, ts));
}
}
}
}
@ -523,6 +751,8 @@ pub(crate) mod sealed {
pub enum TxMode {
NonBuffered(AtomicWaker),
ClassicBuffered(ClassicBufferedTxInner),
FdBuffered(FdBufferedTxInner),
}
impl TxMode {
@ -531,6 +761,9 @@ pub(crate) mod sealed {
TxMode::NonBuffered(waker) => {
waker.register(arg);
}
_ => {
panic!("Bad mode");
}
}
}

View File

@ -5,6 +5,7 @@ use embassy_executor::Spawner;
use embassy_stm32::peripherals::*;
use embassy_stm32::{bind_interrupts, can, Config};
use embassy_time::Timer;
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
@ -28,13 +29,17 @@ async fn main(_spawner: Spawner) {
// 250k bps
can.set_bitrate(250_000);
let use_fd = false;
// 1M bps
if use_fd {
can.set_fd_data_bitrate(1_000_000, false);
}
info!("Configured");
//let mut can = can.into_normal_mode();
let mut can = can.into_internal_loopback_mode();
let mut can = can.into_normal_mode();
//let mut can = can.into_internal_loopback_mode();
let mut i = 0;
let mut last_read_ts = embassy_time::Instant::now();
@ -68,11 +73,17 @@ async fn main(_spawner: Spawner) {
}
// Use the FD API's even if we don't get FD packets.
loop {
if use_fd {
let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
info!("Writing frame using FD API");
_ = can.write_fd(&frame).await;
} else {
let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame using FD API");
_ = can.write_fd(&frame).await;
}
match can.read_fd().await {
Ok((rx_frame, ts)) => {
@ -96,6 +107,7 @@ async fn main(_spawner: Spawner) {
}
}
i = 0;
let (mut tx, mut rx) = can.split();
// With split
loop {
@ -120,5 +132,76 @@ async fn main(_spawner: Spawner) {
Timer::after_millis(250).await;
i += 1;
if i > 2 {
break;
}
}
let can = can::Fdcan::join(tx, rx);
info!("\n\n\nBuffered\n");
if use_fd {
static TX_BUF: StaticCell<can::TxFdBuf<8>> = StaticCell::new();
static RX_BUF: StaticCell<can::RxFdBuf<10>> = StaticCell::new();
let mut can = can.buffered_fd(
TX_BUF.init(can::TxFdBuf::<8>::new()),
RX_BUF.init(can::RxFdBuf::<10>::new()),
);
loop {
let frame = can::frame::FdFrame::new_extended(0x123456F, &[i; 16]).unwrap();
info!("Writing frame");
_ = can.write(frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {} {:02x} --- {}ms",
rx_frame.header().len(),
rx_frame.data()[0..rx_frame.header().len() as usize],
delta,
)
}
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
}
} else {
static TX_BUF: StaticCell<can::TxBuf<8>> = StaticCell::new();
static RX_BUF: StaticCell<can::RxBuf<10>> = StaticCell::new();
let mut can = can.buffered(
TX_BUF.init(can::TxBuf::<8>::new()),
RX_BUF.init(can::RxBuf::<10>::new()),
);
loop {
let frame = can::frame::ClassicFrame::new_extended(0x123456F, &[i; 8]).unwrap();
info!("Writing frame");
_ = can.write(frame).await;
match can.read().await {
Ok((rx_frame, ts)) => {
let delta = (ts - last_read_ts).as_millis();
last_read_ts = ts;
info!(
"Rx: {} {:02x} --- {}ms",
rx_frame.header().len(),
rx_frame.data()[0..rx_frame.header().len() as usize],
delta,
)
}
Err(_err) => error!("Error in frame"),
}
Timer::after_millis(250).await;
i += 1;
}
}
}