diff options
| author | Maarten de Vries <[email protected]> | 2024-05-22 17:13:38 +0200 |
|---|---|---|
| committer | Maarten de Vries <[email protected]> | 2024-05-27 16:10:08 +0200 |
| commit | 807e573994d046d0cd00e631db111fafd2627559 (patch) | |
| tree | 35d30b84fb36fff9a85b0f9b305df751da897bc7 | |
| parent | 854ae5da8fde2b2b33b6ad3c5de1a1d441b4d6b3 (diff) | |
embassy_stm32: allow scheduling lower priority frames in bxcan driver
| -rw-r--r-- | embassy-stm32/src/can/bxcan/mod.rs | 16 | ||||
| -rw-r--r-- | 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> { | |||
| 324 | 324 | ||
| 325 | /// Attempts to transmit a frame without blocking. | 325 | /// Attempts to transmit a frame without blocking. |
| 326 | /// | 326 | /// |
| 327 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | 327 | /// Returns [Err(TryWriteError::Full)] if the frame can not be queued for transmission now. |
| 328 | /// | ||
| 329 | /// If FIFO scheduling is enabled, any empty mailbox will be used. | ||
| 330 | /// | ||
| 331 | /// Otherwise, the frame will only be accepted if there is no frame with the same priority already queued. | ||
| 332 | /// This is done to work around a hardware limitation that could lead to out-of-order delivery | ||
| 333 | /// of frames with the same priority. | ||
| 328 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { | 334 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { |
| 329 | self.split().0.try_write(frame) | 335 | self.split().0.try_write(frame) |
| 330 | } | 336 | } |
| @@ -487,7 +493,13 @@ impl<'d, T: Instance> CanTx<'d, T> { | |||
| 487 | 493 | ||
| 488 | /// Attempts to transmit a frame without blocking. | 494 | /// Attempts to transmit a frame without blocking. |
| 489 | /// | 495 | /// |
| 490 | /// Returns [Err(TryWriteError::Full)] if all transmit mailboxes are full. | 496 | /// Returns [Err(TryWriteError::Full)] if the frame can not be queued for transmission now. |
| 497 | /// | ||
| 498 | /// If FIFO scheduling is enabled, any empty mailbox will be used. | ||
| 499 | /// | ||
| 500 | /// Otherwise, the frame will only be accepted if there is no frame with the same priority already queued. | ||
| 501 | /// This is done to work around a hardware limitation that could lead to out-of-order delivery | ||
| 502 | /// of frames with the same priority. | ||
| 491 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { | 503 | pub fn try_write(&mut self, frame: &Frame) -> Result<TransmitStatus, TryWriteError> { |
| 492 | Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) | 504 | Registers(T::regs()).transmit(frame).map_err(|_| TryWriteError::Full) |
| 493 | } | 505 | } |
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 { | |||
| 239 | // Frames with identical priority should be transmitted in FIFO order, | 239 | // Frames with identical priority should be transmitted in FIFO order, |
| 240 | // but the controller schedules pending frames of same priority based on the | 240 | // but the controller schedules pending frames of same priority based on the |
| 241 | // mailbox index. As a workaround check all pending mailboxes and only accept | 241 | // mailbox index. As a workaround check all pending mailboxes and only accept |
| 242 | // higher priority frames. | 242 | // frames with a different priority. |
| 243 | self.check_priority(0, frame.id().into())?; | 243 | self.check_priority(0, frame.id().into())?; |
| 244 | self.check_priority(1, frame.id().into())?; | 244 | self.check_priority(1, frame.id().into())?; |
| 245 | self.check_priority(2, frame.id().into())?; | 245 | self.check_priority(2, frame.id().into())?; |
| @@ -276,18 +276,16 @@ impl Registers { | |||
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a | 278 | /// Returns `Ok` when the mailbox is free or if it contains pending frame with a |
| 279 | /// lower priority (higher ID) than the identifier `id`. | 279 | /// different priority from the identifier `id`. |
| 280 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { | 280 | fn check_priority(&self, idx: usize, id: IdReg) -> nb::Result<(), Infallible> { |
| 281 | // Read the pending frame's id to check its priority. | 281 | // Read the pending frame's id to check its priority. |
| 282 | assert!(idx < 3); | 282 | assert!(idx < 3); |
| 283 | let tir = &self.0.tx(idx).tir().read(); | 283 | let tir = &self.0.tx(idx).tir().read(); |
| 284 | //let tir = &can.tx[idx].tir.read(); | ||
| 285 | 284 | ||
| 286 | // Check the priority by comparing the identifiers. But first make sure the | 285 | // Check the priority by comparing the identifiers. But first make sure the |
| 287 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. | 286 | // frame has not finished the transmission (`TXRQ` == 0) in the meantime. |
| 288 | if tir.txrq() && id <= IdReg::from_register(tir.0) { | 287 | if tir.txrq() && id == IdReg::from_register(tir.0) { |
| 289 | // There's a mailbox whose priority is higher or equal | 288 | // There's a mailbox whose priority is equal to the priority of the new frame. |
| 290 | // the priority of the new frame. | ||
| 291 | return Err(nb::Error::WouldBlock); | 289 | return Err(nb::Error::WouldBlock); |
| 292 | } | 290 | } |
| 293 | 291 | ||
