Merge pull request #3020 from cschuhen/feature/bxcan_no_generics

Remove generics for BXCAN.
This commit is contained in:
Dario Nieuwenhuis 2024-05-30 12:16:17 +00:00 committed by GitHub
commit b378ec4558
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 200 additions and 114 deletions

View File

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

View File

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

View File

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

View File

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