From 807e573994d046d0cd00e631db111fafd2627559 Mon Sep 17 00:00:00 2001 From: Maarten de Vries Date: Wed, 22 May 2024 17:13:38 +0200 Subject: [PATCH] embassy_stm32: allow scheduling lower priority frames in bxcan driver --- embassy-stm32/src/can/bxcan/mod.rs | 16 ++++++++++++++-- embassy-stm32/src/can/bxcan/registers.rs | 10 ++++------ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/src/can/bxcan/mod.rs b/embassy-stm32/src/can/bxcan/mod.rs index 05b1b83d8..0ac4cdab6 100644 --- a/embassy-stm32/src/can/bxcan/mod.rs +++ b/embassy-stm32/src/can/bxcan/mod.rs @@ -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 { 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 { Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) } diff --git a/embassy-stm32/src/can/bxcan/registers.rs b/embassy-stm32/src/can/bxcan/registers.rs index a0519cd1f..ad27e0744 100644 --- a/embassy-stm32/src/can/bxcan/registers.rs +++ b/embassy-stm32/src/can/bxcan/registers.rs @@ -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); }