mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-21 22:32:29 +00:00
Merge pull request #3020 from cschuhen/feature/bxcan_no_generics
Remove generics for BXCAN.
This commit is contained in:
commit
b378ec4558
@ -5,6 +5,7 @@ use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::interrupt::InterruptExt;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
@ -154,7 +155,9 @@ impl<T: Instance> Drop for CanConfig<'_, T> {
|
||||
|
||||
/// CAN driver
|
||||
pub struct Can<'d, T: Instance> {
|
||||
peri: PeripheralRef<'d, T>,
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
}
|
||||
|
||||
/// Error returned by `try_write`
|
||||
@ -179,6 +182,8 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
+ 'd,
|
||||
) -> Self {
|
||||
into_ref!(peri, rx, tx);
|
||||
let info = T::info();
|
||||
let regs = &T::info().regs;
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
@ -186,7 +191,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
rcc::enable_and_reset::<T>();
|
||||
|
||||
{
|
||||
T::regs().ier().write(|w| {
|
||||
regs.0.ier().write(|w| {
|
||||
w.set_errie(true);
|
||||
w.set_fmpie(0, true);
|
||||
w.set_fmpie(1, true);
|
||||
@ -197,7 +202,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
w.set_lecie(true);
|
||||
});
|
||||
|
||||
T::regs().mcr().write(|w| {
|
||||
regs.0.mcr().write(|w| {
|
||||
// Enable timestamps on rx messages
|
||||
|
||||
w.set_ttcm(true);
|
||||
@ -205,17 +210,14 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
}
|
||||
|
||||
unsafe {
|
||||
T::TXInterrupt::unpend();
|
||||
T::TXInterrupt::enable();
|
||||
|
||||
T::RX0Interrupt::unpend();
|
||||
T::RX0Interrupt::enable();
|
||||
|
||||
T::RX1Interrupt::unpend();
|
||||
T::RX1Interrupt::enable();
|
||||
|
||||
T::SCEInterrupt::unpend();
|
||||
T::SCEInterrupt::enable();
|
||||
info.tx_interrupt.unpend();
|
||||
info.tx_interrupt.enable();
|
||||
info.rx0_interrupt.unpend();
|
||||
info.rx0_interrupt.enable();
|
||||
info.rx1_interrupt.unpend();
|
||||
info.rx1_interrupt.enable();
|
||||
info.sce_interrupt.unpend();
|
||||
info.sce_interrupt.enable();
|
||||
}
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
@ -223,7 +225,11 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
|
||||
Registers(T::regs()).leave_init_mode();
|
||||
|
||||
Self { peri }
|
||||
Self {
|
||||
_peri: peri,
|
||||
info: T::info(),
|
||||
state: T::state(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set CAN bit rate.
|
||||
@ -265,12 +271,12 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// Waking the peripheral manually does not trigger a wake-up interrupt.
|
||||
/// This will wait until the peripheral has acknowledged it has awoken from sleep mode
|
||||
pub fn wakeup(&mut self) {
|
||||
Registers(T::regs()).wakeup()
|
||||
self.info.regs.wakeup()
|
||||
}
|
||||
|
||||
/// Check if the peripheral is currently in sleep mode
|
||||
pub fn is_sleeping(&self) -> bool {
|
||||
T::regs().msr().read().slak()
|
||||
self.info.regs.0.msr().read().slak()
|
||||
}
|
||||
|
||||
/// Put the peripheral in sleep mode
|
||||
@ -282,11 +288,11 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// If the peripheral has automatic wakeup enabled, when a Start-of-Frame is detected
|
||||
/// the peripheral will automatically wake and receive the incoming message.
|
||||
pub async fn sleep(&mut self) {
|
||||
T::regs().ier().modify(|i| i.set_slkie(true));
|
||||
T::regs().mcr().modify(|m| m.set_sleep(true));
|
||||
self.info.regs.0.ier().modify(|i| i.set_slkie(true));
|
||||
self.info.regs.0.mcr().modify(|m| m.set_sleep(true));
|
||||
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
self.state.err_waker.register(cx.waker());
|
||||
if self.is_sleeping() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
@ -295,7 +301,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
})
|
||||
.await;
|
||||
|
||||
T::regs().ier().modify(|i| i.set_slkie(false));
|
||||
self.info.regs.0.ier().modify(|i| i.set_slkie(false));
|
||||
}
|
||||
|
||||
/// Enable FIFO scheduling of outgoing frames.
|
||||
@ -337,7 +343,13 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: Mailbox) {
|
||||
CanTx::<T>::flush_inner(mb).await
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
}
|
||||
.flush_inner(mb)
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Waits until any of the transmit mailboxes become empty
|
||||
@ -347,12 +359,24 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// This will happen if FIFO scheduling of outgoing frames is not enabled,
|
||||
/// and a frame with equal priority is already queued for transmission.
|
||||
pub async fn flush_any(&self) {
|
||||
CanTx::<T>::flush_any_inner().await
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
}
|
||||
.flush_any_inner()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Waits until all of the transmit mailboxes become empty
|
||||
pub async fn flush_all(&self) {
|
||||
CanTx::<T>::flush_all_inner().await
|
||||
CanTx {
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
}
|
||||
.flush_all_inner()
|
||||
.await
|
||||
}
|
||||
|
||||
/// Attempts to abort the sending of a frame that is pending in a mailbox.
|
||||
@ -363,12 +387,12 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
|
||||
/// returns `true`.
|
||||
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
|
||||
Registers(T::regs()).abort(mailbox)
|
||||
self.info.regs.abort(mailbox)
|
||||
}
|
||||
|
||||
/// Returns `true` if no frame is pending for transmission.
|
||||
pub fn is_transmitter_idle(&self) -> bool {
|
||||
Registers(T::regs()).is_idle()
|
||||
self.info.regs.is_idle()
|
||||
}
|
||||
|
||||
/// Read a CAN frame.
|
||||
@ -377,31 +401,35 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
///
|
||||
/// Returns a tuple of the time the message was received and the message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
T::state().rx_mode.read::<T>().await
|
||||
self.state.rx_mode.read(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Attempts to read a CAN frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
T::state().rx_mode.try_read::<T>()
|
||||
self.state.rx_mode.try_read(self.info)
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
T::state().rx_mode.wait_not_empty::<T>().await
|
||||
self.state.rx_mode.wait_not_empty(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Split the CAN driver into transmit and receive halves.
|
||||
///
|
||||
/// Useful for doing separate transmit/receive tasks.
|
||||
pub fn split<'c>(&'c mut self) -> (CanTx<'d, T>, CanRx<'d, T>) {
|
||||
pub fn split<'c>(&'c mut self) -> (CanTx<'d>, CanRx<'d>) {
|
||||
(
|
||||
CanTx {
|
||||
_peri: unsafe { self.peri.clone_unchecked() },
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
},
|
||||
CanRx {
|
||||
peri: unsafe { self.peri.clone_unchecked() },
|
||||
_phantom: PhantomData,
|
||||
info: self.info,
|
||||
state: self.state,
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -411,7 +439,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
&'c mut self,
|
||||
txb: &'static mut TxBuf<TX_BUF_SIZE>,
|
||||
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
||||
) -> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
) -> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
let (tx, rx) = self.split();
|
||||
BufferedCan {
|
||||
tx: tx.buffered(txb),
|
||||
@ -426,17 +454,17 @@ impl<'d, T: FilterOwner> Can<'d, T> {
|
||||
/// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
|
||||
/// peripheral instead.
|
||||
pub fn modify_filters(&mut self) -> MasterFilters<'_, T> {
|
||||
unsafe { MasterFilters::new(T::regs()) }
|
||||
unsafe { MasterFilters::new(self.info.regs.0) }
|
||||
}
|
||||
}
|
||||
|
||||
/// Buffered CAN driver.
|
||||
pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
tx: BufferedCanTx<'d, T, TX_BUF_SIZE>,
|
||||
rx: BufferedCanRx<'d, T, RX_BUF_SIZE>,
|
||||
pub struct BufferedCan<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> {
|
||||
tx: BufferedCanTx<'d, TX_BUF_SIZE>,
|
||||
rx: BufferedCanRx<'d, RX_BUF_SIZE>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, T, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
impl<'d, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> BufferedCan<'d, TX_BUF_SIZE, RX_BUF_SIZE> {
|
||||
/// Async write frame to TX buffer.
|
||||
pub async fn write(&mut self, frame: &Frame) {
|
||||
self.tx.write(frame).await
|
||||
@ -471,18 +499,20 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize> Buffer
|
||||
}
|
||||
|
||||
/// CAN driver, transmit half.
|
||||
pub struct CanTx<'d, T: Instance> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
pub struct CanTx<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> CanTx<'d, T> {
|
||||
impl<'d> CanTx<'d> {
|
||||
/// Queues the message to be sent.
|
||||
///
|
||||
/// If the TX queue is full, this will wait until there is space, therefore exerting backpressure.
|
||||
pub async fn write(&mut self, frame: &Frame) -> TransmitStatus {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
if let Ok(status) = Registers(T::regs()).transmit(frame) {
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
if let Ok(status) = self.info.regs.transmit(frame) {
|
||||
return Poll::Ready(status);
|
||||
}
|
||||
|
||||
@ -501,13 +531,13 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
/// This is done to work around a hardware limitation that could lead to out-of-order delivery
|
||||
/// of frames with the same priority.
|
||||
pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> {
|
||||
Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full)
|
||||
self.info.regs.transmit(frame).map_err(|_| TryWriteError::Full)
|
||||
}
|
||||
|
||||
async fn flush_inner(mb: Mailbox) {
|
||||
async fn flush_inner(&self, mb: Mailbox) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
if T::regs().tsr().read().tme(mb.index()) {
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
if self.info.regs.0.tsr().read().tme(mb.index()) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
@ -518,14 +548,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
|
||||
/// Waits for a specific transmit mailbox to become empty
|
||||
pub async fn flush(&self, mb: Mailbox) {
|
||||
Self::flush_inner(mb).await
|
||||
self.flush_inner(mb).await
|
||||
}
|
||||
|
||||
async fn flush_any_inner() {
|
||||
async fn flush_any_inner(&self) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
|
||||
let tsr = T::regs().tsr().read();
|
||||
let tsr = self.info.regs.0.tsr().read();
|
||||
if tsr.tme(Mailbox::Mailbox0.index())
|
||||
|| tsr.tme(Mailbox::Mailbox1.index())
|
||||
|| tsr.tme(Mailbox::Mailbox2.index())
|
||||
@ -545,14 +575,14 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
/// This will happen if FIFO scheduling of outgoing frames is not enabled,
|
||||
/// and a frame with equal priority is already queued for transmission.
|
||||
pub async fn flush_any(&self) {
|
||||
Self::flush_any_inner().await
|
||||
self.flush_any_inner().await
|
||||
}
|
||||
|
||||
async fn flush_all_inner() {
|
||||
async fn flush_all_inner(&self) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_mode.register(cx.waker());
|
||||
self.state.tx_mode.register(cx.waker());
|
||||
|
||||
let tsr = T::regs().tsr().read();
|
||||
let tsr = self.info.regs.0.tsr().read();
|
||||
if tsr.tme(Mailbox::Mailbox0.index())
|
||||
&& tsr.tme(Mailbox::Mailbox1.index())
|
||||
&& tsr.tme(Mailbox::Mailbox2.index())
|
||||
@ -567,7 +597,7 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
|
||||
/// Waits until all of the transmit mailboxes become empty
|
||||
pub async fn flush_all(&self) {
|
||||
Self::flush_all_inner().await
|
||||
self.flush_all_inner().await
|
||||
}
|
||||
|
||||
/// Attempts to abort the sending of a frame that is pending in a mailbox.
|
||||
@ -578,20 +608,20 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
|
||||
/// returns `true`.
|
||||
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
|
||||
Registers(T::regs()).abort(mailbox)
|
||||
self.info.regs.abort(mailbox)
|
||||
}
|
||||
|
||||
/// Returns `true` if no frame is pending for transmission.
|
||||
pub fn is_idle(&self) -> bool {
|
||||
Registers(T::regs()).is_idle()
|
||||
self.info.regs.is_idle()
|
||||
}
|
||||
|
||||
/// Return a buffered instance of driver. User must supply Buffers
|
||||
pub fn buffered<const TX_BUF_SIZE: usize>(
|
||||
self,
|
||||
txb: &'static mut TxBuf<TX_BUF_SIZE>,
|
||||
) -> BufferedCanTx<'d, T, TX_BUF_SIZE> {
|
||||
BufferedCanTx::new(self, txb)
|
||||
) -> BufferedCanTx<'d, TX_BUF_SIZE> {
|
||||
BufferedCanTx::new(self.info, self.state, self, txb)
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,23 +629,35 @@ impl<'d, T: Instance> CanTx<'d, T> {
|
||||
pub type TxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Frame, BUF_SIZE>;
|
||||
|
||||
/// Buffered CAN driver, transmit half.
|
||||
pub struct BufferedCanTx<'d, T: Instance, const TX_BUF_SIZE: usize> {
|
||||
_tx: CanTx<'d, T>,
|
||||
pub struct BufferedCanTx<'d, const TX_BUF_SIZE: usize> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_tx: CanTx<'d>,
|
||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE> {
|
||||
fn new(_tx: CanTx<'d, T>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
|
||||
Self { _tx, tx_buf }.setup()
|
||||
impl<'d, const TX_BUF_SIZE: usize> BufferedCanTx<'d, TX_BUF_SIZE> {
|
||||
fn new(info: &'static Info, state: &'static State, _tx: CanTx<'d>, tx_buf: &'static TxBuf<TX_BUF_SIZE>) -> Self {
|
||||
Self {
|
||||
info,
|
||||
state,
|
||||
_tx,
|
||||
tx_buf,
|
||||
}
|
||||
.setup()
|
||||
}
|
||||
|
||||
fn setup(self) -> Self {
|
||||
// We don't want interrupts being processed while we change modes.
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
let tx_inner = super::common::ClassicBufferedTxInner {
|
||||
tx_receiver: self.tx_buf.receiver().into(),
|
||||
};
|
||||
T::mut_state().tx_mode = TxMode::Buffered(tx_inner);
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).tx_mode = TxMode::Buffered(tx_inner);
|
||||
}
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -623,60 +665,67 @@ impl<'d, T: Instance, const TX_BUF_SIZE: usize> BufferedCanTx<'d, T, TX_BUF_SIZE
|
||||
/// Async write frame to TX buffer.
|
||||
pub async fn write(&mut self, frame: &Frame) {
|
||||
self.tx_buf.send(*frame).await;
|
||||
T::TXInterrupt::pend(); // Wake for Tx
|
||||
let waker = self.info.tx_waker;
|
||||
waker(); // Wake for Tx
|
||||
}
|
||||
|
||||
/// Returns a sender that can be used for sending CAN frames.
|
||||
pub fn writer(&self) -> BufferedCanSender {
|
||||
BufferedCanSender {
|
||||
tx_buf: self.tx_buf.sender().into(),
|
||||
waker: T::TXInterrupt::pend,
|
||||
waker: self.info.tx_waker,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, T, TX_BUF_SIZE> {
|
||||
impl<'d, const TX_BUF_SIZE: usize> Drop for BufferedCanTx<'d, TX_BUF_SIZE> {
|
||||
fn drop(&mut self) {
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).tx_mode = TxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// CAN driver, receive half.
|
||||
#[allow(dead_code)]
|
||||
pub struct CanRx<'d, T: Instance> {
|
||||
peri: PeripheralRef<'d, T>,
|
||||
pub struct CanRx<'d> {
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> CanRx<'d, T> {
|
||||
impl<'d> CanRx<'d> {
|
||||
/// Read a CAN frame.
|
||||
///
|
||||
/// If no CAN frame is in the RX buffer, this will wait until there is one.
|
||||
///
|
||||
/// Returns a tuple of the time the message was received and the message frame
|
||||
pub async fn read(&mut self) -> Result<Envelope, BusError> {
|
||||
T::state().rx_mode.read::<T>().await
|
||||
self.state.rx_mode.read(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Attempts to read a CAN frame without blocking.
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
T::state().rx_mode.try_read::<T>()
|
||||
self.state.rx_mode.try_read(self.info)
|
||||
}
|
||||
|
||||
/// Waits while receive queue is empty.
|
||||
pub async fn wait_not_empty(&mut self) {
|
||||
T::state().rx_mode.wait_not_empty::<T>().await
|
||||
self.state.rx_mode.wait_not_empty(self.info, self.state).await
|
||||
}
|
||||
|
||||
/// Return a buffered instance of driver. User must supply Buffers
|
||||
pub fn buffered<const RX_BUF_SIZE: usize>(
|
||||
self,
|
||||
rxb: &'static mut RxBuf<RX_BUF_SIZE>,
|
||||
) -> BufferedCanRx<'d, T, RX_BUF_SIZE> {
|
||||
BufferedCanRx::new(self, rxb)
|
||||
) -> BufferedCanRx<'d, RX_BUF_SIZE> {
|
||||
BufferedCanRx::new(self.info, self.state, self, rxb)
|
||||
}
|
||||
}
|
||||
|
||||
@ -684,23 +733,35 @@ impl<'d, T: Instance> CanRx<'d, T> {
|
||||
pub type RxBuf<const BUF_SIZE: usize> = Channel<CriticalSectionRawMutex, Result<Envelope, BusError>, BUF_SIZE>;
|
||||
|
||||
/// CAN driver, receive half in Buffered mode.
|
||||
pub struct BufferedCanRx<'d, T: Instance, const RX_BUF_SIZE: usize> {
|
||||
_rx: CanRx<'d, T>,
|
||||
pub struct BufferedCanRx<'d, const RX_BUF_SIZE: usize> {
|
||||
info: &'static Info,
|
||||
state: &'static State,
|
||||
_rx: CanRx<'d>,
|
||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE> {
|
||||
fn new(_rx: CanRx<'d, T>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
|
||||
BufferedCanRx { _rx, rx_buf }.setup()
|
||||
impl<'d, const RX_BUF_SIZE: usize> BufferedCanRx<'d, RX_BUF_SIZE> {
|
||||
fn new(info: &'static Info, state: &'static State, _rx: CanRx<'d>, rx_buf: &'static RxBuf<RX_BUF_SIZE>) -> Self {
|
||||
BufferedCanRx {
|
||||
info,
|
||||
state,
|
||||
_rx,
|
||||
rx_buf,
|
||||
}
|
||||
.setup()
|
||||
}
|
||||
|
||||
fn setup(self) -> Self {
|
||||
// We don't want interrupts being processed while we change modes.
|
||||
critical_section::with(|_| unsafe {
|
||||
critical_section::with(|_| {
|
||||
let rx_inner = super::common::ClassicBufferedRxInner {
|
||||
rx_sender: self.rx_buf.sender().into(),
|
||||
};
|
||||
T::mut_state().rx_mode = RxMode::Buffered(rx_inner);
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::Buffered(rx_inner);
|
||||
}
|
||||
});
|
||||
self
|
||||
}
|
||||
@ -714,7 +775,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
|
||||
///
|
||||
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
|
||||
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
|
||||
match &T::state().rx_mode {
|
||||
match &self.state.rx_mode {
|
||||
RxMode::Buffered(_) => {
|
||||
if let Ok(result) = self.rx_buf.try_receive() {
|
||||
match result {
|
||||
@ -722,7 +783,7 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
|
||||
Err(e) => Err(TryReadError::BusError(e)),
|
||||
}
|
||||
} else {
|
||||
if let Some(err) = Registers(T::regs()).curr_error() {
|
||||
if let Some(err) = self.info.regs.curr_error() {
|
||||
return Err(TryReadError::BusError(err));
|
||||
} else {
|
||||
Err(TryReadError::Empty)
|
||||
@ -746,10 +807,14 @@ impl<'d, T: Instance, const RX_BUF_SIZE: usize> BufferedCanRx<'d, T, RX_BUF_SIZE
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, T, RX_BUF_SIZE> {
|
||||
impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
|
||||
fn drop(&mut self) {
|
||||
critical_section::with(|_| unsafe {
|
||||
T::mut_state().rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
critical_section::with(|_| {
|
||||
let state = self.state as *const State;
|
||||
unsafe {
|
||||
let mut_state = state as *mut State;
|
||||
(*mut_state).rx_mode = RxMode::NonBuffered(embassy_sync::waitqueue::AtomicWaker::new());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -839,13 +904,13 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn read<T: Instance>(&self) -> Result<Envelope, BusError> {
|
||||
pub(crate) async fn read(&self, info: &Info, state: &State) -> Result<Envelope, BusError> {
|
||||
match self {
|
||||
Self::NonBuffered(waker) => {
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
state.err_waker.register(cx.waker());
|
||||
waker.register(cx.waker());
|
||||
match self.try_read::<T>() {
|
||||
match self.try_read(info) {
|
||||
Ok(result) => Poll::Ready(Ok(result)),
|
||||
Err(TryReadError::Empty) => Poll::Pending,
|
||||
Err(TryReadError::BusError(be)) => Poll::Ready(Err(be)),
|
||||
@ -858,17 +923,17 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn try_read<T: Instance>(&self) -> Result<Envelope, TryReadError> {
|
||||
pub(crate) fn try_read(&self, info: &Info) -> Result<Envelope, TryReadError> {
|
||||
match self {
|
||||
Self::NonBuffered(_) => {
|
||||
let registers = Registers(T::regs());
|
||||
let registers = &info.regs;
|
||||
if let Some(msg) = registers.receive_fifo(RxFifo::Fifo0) {
|
||||
T::regs().ier().write(|w| {
|
||||
registers.0.ier().write(|w| {
|
||||
w.set_fmpie(0, true);
|
||||
});
|
||||
Ok(msg)
|
||||
} else if let Some(msg) = registers.receive_fifo(RxFifo::Fifo1) {
|
||||
T::regs().ier().write(|w| {
|
||||
registers.0.ier().write(|w| {
|
||||
w.set_fmpie(1, true);
|
||||
});
|
||||
Ok(msg)
|
||||
@ -883,12 +948,12 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
}
|
||||
pub async fn wait_not_empty<T: Instance>(&self) {
|
||||
match &T::state().rx_mode {
|
||||
pub(crate) async fn wait_not_empty(&self, info: &Info, state: &State) {
|
||||
match &state.rx_mode {
|
||||
Self::NonBuffered(waker) => {
|
||||
poll_fn(|cx| {
|
||||
waker.register(cx.waker());
|
||||
if Registers(T::regs()).receive_frame_available() {
|
||||
if info.regs.receive_frame_available() {
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
@ -903,7 +968,7 @@ impl RxMode {
|
||||
}
|
||||
}
|
||||
|
||||
enum TxMode {
|
||||
pub(crate) enum TxMode {
|
||||
NonBuffered(AtomicWaker),
|
||||
Buffered(super::common::ClassicBufferedTxInner),
|
||||
}
|
||||
@ -943,7 +1008,7 @@ impl TxMode {
|
||||
}
|
||||
}
|
||||
|
||||
struct State {
|
||||
pub(crate) struct State {
|
||||
pub(crate) rx_mode: RxMode,
|
||||
pub(crate) tx_mode: TxMode,
|
||||
pub err_waker: AtomicWaker,
|
||||
@ -959,7 +1024,17 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Info {
|
||||
regs: Registers,
|
||||
tx_interrupt: crate::interrupt::Interrupt,
|
||||
rx0_interrupt: crate::interrupt::Interrupt,
|
||||
rx1_interrupt: crate::interrupt::Interrupt,
|
||||
sce_interrupt: crate::interrupt::Interrupt,
|
||||
tx_waker: fn(),
|
||||
}
|
||||
|
||||
trait SealedInstance {
|
||||
fn info() -> &'static Info;
|
||||
fn regs() -> crate::pac::can::Can;
|
||||
fn state() -> &'static State;
|
||||
unsafe fn mut_state() -> &'static mut State;
|
||||
@ -1012,6 +1087,17 @@ foreach_peripheral!(
|
||||
(can, $inst:ident) => {
|
||||
impl SealedInstance for peripherals::$inst {
|
||||
|
||||
fn info() -> &'static Info {
|
||||
static INFO: Info = Info {
|
||||
regs: Registers(crate::pac::$inst),
|
||||
tx_interrupt: crate::_generated::peripheral_interrupts::$inst::TX::IRQ,
|
||||
rx0_interrupt: crate::_generated::peripheral_interrupts::$inst::RX0::IRQ,
|
||||
rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
|
||||
sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
|
||||
tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
|
||||
};
|
||||
&INFO
|
||||
}
|
||||
fn regs() -> crate::pac::can::Can {
|
||||
crate::pac::$inst
|
||||
}
|
||||
|
@ -131,7 +131,7 @@ impl Registers {
|
||||
/// Note that this will not trigger [`Interrupt::Wakeup`], only reception of an incoming CAN
|
||||
/// frame will cause that interrupt.
|
||||
#[allow(dead_code)]
|
||||
pub fn wakeup(&mut self) {
|
||||
pub fn wakeup(&self) {
|
||||
self.0.mcr().modify(|reg| {
|
||||
reg.set_sleep(false);
|
||||
reg.set_inrq(false);
|
||||
@ -216,7 +216,7 @@ impl Registers {
|
||||
/// If FIFO scheduling is enabled, frames are transmitted in the order that they are passed to this function.
|
||||
///
|
||||
/// If all transmit mailboxes are full, this function returns [`nb::Error::WouldBlock`].
|
||||
pub fn transmit(&mut self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
|
||||
pub fn transmit(&self, frame: &Frame) -> nb::Result<TransmitStatus, Infallible> {
|
||||
// Check if FIFO scheduling is enabled.
|
||||
let fifo_scheduling = self.0.mcr().read().txfp();
|
||||
|
||||
@ -292,7 +292,7 @@ impl Registers {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_mailbox(&mut self, idx: usize, frame: &Frame) {
|
||||
fn write_mailbox(&self, idx: usize, frame: &Frame) {
|
||||
debug_assert!(idx < 3);
|
||||
|
||||
let mb = self.0.tx(idx);
|
||||
@ -309,7 +309,7 @@ impl Registers {
|
||||
});
|
||||
}
|
||||
|
||||
fn read_pending_mailbox(&mut self, idx: usize) -> Option<Frame> {
|
||||
fn read_pending_mailbox(&self, idx: usize) -> Option<Frame> {
|
||||
if self.abort_by_index(idx) {
|
||||
debug_assert!(idx < 3);
|
||||
|
||||
@ -332,7 +332,7 @@ impl Registers {
|
||||
}
|
||||
|
||||
/// Tries to abort a pending frame. Returns `true` when aborted.
|
||||
fn abort_by_index(&mut self, idx: usize) -> bool {
|
||||
fn abort_by_index(&self, idx: usize) -> bool {
|
||||
self.0.tsr().write(|reg| reg.set_abrq(idx, true));
|
||||
|
||||
// Wait for the abort request to be finished.
|
||||
@ -351,7 +351,7 @@ impl Registers {
|
||||
///
|
||||
/// If there is a frame in the provided mailbox, and it is canceled successfully, this function
|
||||
/// returns `true`.
|
||||
pub fn abort(&mut self, mailbox: Mailbox) -> bool {
|
||||
pub fn abort(&self, mailbox: Mailbox) -> bool {
|
||||
// If the mailbox is empty, the value of TXOKx depends on what happened with the previous
|
||||
// frame in that mailbox. Only call abort_by_index() if the mailbox is not empty.
|
||||
let tsr = self.0.tsr().read();
|
||||
|
@ -24,7 +24,7 @@ bind_interrupts!(struct Irqs {
|
||||
});
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn send_can_message(tx: &'static mut CanTx<'static, CAN3>) {
|
||||
pub async fn send_can_message(tx: &'static mut CanTx<'static>) {
|
||||
loop {
|
||||
let frame = Frame::new_data(unwrap!(StandardId::new(0 as _)), &[0]).unwrap();
|
||||
tx.write(&frame).await;
|
||||
@ -62,7 +62,7 @@ async fn main(spawner: Spawner) {
|
||||
|
||||
let (tx, mut rx) = can.split();
|
||||
|
||||
static CAN_TX: StaticCell<CanTx<'static, CAN3>> = StaticCell::new();
|
||||
static CAN_TX: StaticCell<CanTx<'static>> = StaticCell::new();
|
||||
let tx = CAN_TX.init(tx);
|
||||
spawner.spawn(send_can_message(tx)).unwrap();
|
||||
|
||||
|
@ -19,8 +19,8 @@ mod can_common;
|
||||
use can_common::*;
|
||||
|
||||
type Can<'d> = embassy_stm32::can::Can<'d, embassy_stm32::peripherals::CAN1>;
|
||||
type CanTx<'d> = embassy_stm32::can::CanTx<'d, embassy_stm32::peripherals::CAN1>;
|
||||
type CanRx<'d> = embassy_stm32::can::CanRx<'d, embassy_stm32::peripherals::CAN1>;
|
||||
type CanTx<'d> = embassy_stm32::can::CanTx<'d>;
|
||||
type CanRx<'d> = embassy_stm32::can::CanRx<'d>;
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
CAN1_RX0 => Rx0InterruptHandler<CAN1>;
|
||||
|
Loading…
Reference in New Issue
Block a user