embassy_stm32: allow scheduling lower priority frames in bxcan driver

This commit is contained in:
Maarten de Vries 2024-05-22 17:13:38 +02:00
parent 854ae5da8f
commit 807e573994
2 changed files with 18 additions and 8 deletions

View File

@ -324,7 +324,13 @@ impl<'d, T: Instance> Can<'d, T> {
/// Attempts to transmit a frame without blocking.
///
/// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
/// Returns [Err(TryWriteError::Full)] if the frame can not be queued for transmission now.
///
/// If FIFO scheduling is enabled, any empty mailbox will be used.
///
/// Otherwise, the frame will only be accepted if there is no frame with the same priority already queued.
/// 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> {
self.split().0.try_write(frame)
}
@ -487,7 +493,13 @@ impl<'d, T: Instance> CanTx<'d, T> {
/// Attempts to transmit a frame without blocking.
///
/// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full.
/// Returns [Err(TryWriteError::Full)] if the frame can not be queued for transmission now.
///
/// If FIFO scheduling is enabled, any empty mailbox will be used.
///
/// Otherwise, the frame will only be accepted if there is no frame with the same priority already queued.
/// 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)
}

View File

@ -239,7 +239,7 @@ impl Registers {
// Frames with identical priority should be transmitted in FIFO order,
// but the controller schedules pending frames of same priority based on the
// mailbox index. As a workaround check all pending mailboxes and only accept
// higher priority frames.
// frames with a different priority.
self.check_priority(0, frame.id().into())?;
self.check_priority(1, frame.id().into())?;
self.check_priority(2, frame.id().into())?;
@ -276,18 +276,16 @@ impl Registers {
}
/// Returns `Ok` when the mailbox is free or if it contains pending frame with a
/// lower priority (higher ID) than the identifier `id`.
/// different priority from the identifier `id`.
fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> {
// Read the pending frame's id to check its priority.
assert!(idx < 3);
let tir = &self.0.tx(idx).tir().read();
//let tir = &can.tx[idx].tir.read();
// Check the priority by comparing the identifiers. But first make sure the
// frame has not finished the transmission (`TXRQ` == 0) in the meantime.
if tir.txrq() && id <= IdReg::from_register(tir.0) {
// There's a mailbox whose priority is higher or equal
// the priority of the new frame.
if tir.txrq() && id == IdReg::from_register(tir.0) {
// There's a mailbox whose priority is equal to the priority of the new frame.
return Err(nb::Error::WouldBlock);
}