diff options
| -rw-r--r-- | embassy-stm32/src/can/bxcan.rs | 45 |
1 files changed, 41 insertions, 4 deletions
diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 788360249..3c663b452 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs | |||
| @@ -21,8 +21,10 @@ use crate::{interrupt, peripherals, Peripheral}; | |||
| 21 | #[derive(Debug, Clone, PartialEq, Eq)] | 21 | #[derive(Debug, Clone, PartialEq, Eq)] |
| 22 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 22 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 23 | pub struct Envelope { | 23 | pub struct Envelope { |
| 24 | /// Reception time. | ||
| 24 | #[cfg(feature = "time")] | 25 | #[cfg(feature = "time")] |
| 25 | pub ts: embassy_time::Instant, | 26 | pub ts: embassy_time::Instant, |
| 27 | /// The actual CAN frame. | ||
| 26 | pub frame: bxcan::Frame, | 28 | pub frame: bxcan::Frame, |
| 27 | } | 29 | } |
| 28 | 30 | ||
| @@ -43,6 +45,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH | |||
| 43 | } | 45 | } |
| 44 | } | 46 | } |
| 45 | 47 | ||
| 48 | /// RX0 interrupt handler. | ||
| 46 | pub struct Rx0InterruptHandler<T: Instance> { | 49 | pub struct Rx0InterruptHandler<T: Instance> { |
| 47 | _phantom: PhantomData<T>, | 50 | _phantom: PhantomData<T>, |
| 48 | } | 51 | } |
| @@ -54,6 +57,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0Interrup | |||
| 54 | } | 57 | } |
| 55 | } | 58 | } |
| 56 | 59 | ||
| 60 | /// RX1 interrupt handler. | ||
| 57 | pub struct Rx1InterruptHandler<T: Instance> { | 61 | pub struct Rx1InterruptHandler<T: Instance> { |
| 58 | _phantom: PhantomData<T>, | 62 | _phantom: PhantomData<T>, |
| 59 | } | 63 | } |
| @@ -65,6 +69,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1Interrup | |||
| 65 | } | 69 | } |
| 66 | } | 70 | } |
| 67 | 71 | ||
| 72 | /// SCE interrupt handler. | ||
| 68 | pub struct SceInterruptHandler<T: Instance> { | 73 | pub struct SceInterruptHandler<T: Instance> { |
| 69 | _phantom: PhantomData<T>, | 74 | _phantom: PhantomData<T>, |
| 70 | } | 75 | } |
| @@ -82,10 +87,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup | |||
| 82 | } | 87 | } |
| 83 | } | 88 | } |
| 84 | 89 | ||
| 90 | /// CAN driver | ||
| 85 | pub struct Can<'d, T: Instance> { | 91 | pub struct Can<'d, T: Instance> { |
| 86 | pub can: bxcan::Can<BxcanInstance<'d, T>>, | 92 | can: bxcan::Can<BxcanInstance<'d, T>>, |
| 87 | } | 93 | } |
| 88 | 94 | ||
| 95 | /// CAN bus error | ||
| 96 | #[allow(missing_docs)] | ||
| 89 | #[derive(Debug)] | 97 | #[derive(Debug)] |
| 90 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 98 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 91 | pub enum BusError { | 99 | pub enum BusError { |
| @@ -101,6 +109,7 @@ pub enum BusError { | |||
| 101 | BusWarning, | 109 | BusWarning, |
| 102 | } | 110 | } |
| 103 | 111 | ||
| 112 | /// Error returned by `try_read` | ||
| 104 | #[derive(Debug)] | 113 | #[derive(Debug)] |
| 105 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 114 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 106 | pub enum TryReadError { | 115 | pub enum TryReadError { |
| @@ -110,6 +119,7 @@ pub enum TryReadError { | |||
| 110 | Empty, | 119 | Empty, |
| 111 | } | 120 | } |
| 112 | 121 | ||
| 122 | /// Error returned by `try_write` | ||
| 113 | #[derive(Debug)] | 123 | #[derive(Debug)] |
| 114 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | 124 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] |
| 115 | pub enum TryWriteError { | 125 | pub enum TryWriteError { |
| @@ -177,6 +187,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 177 | Self { can } | 187 | Self { can } |
| 178 | } | 188 | } |
| 179 | 189 | ||
| 190 | /// Set CAN bit rate. | ||
| 180 | pub fn set_bitrate(&mut self, bitrate: u32) { | 191 | pub fn set_bitrate(&mut self, bitrate: u32) { |
| 181 | let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); | 192 | let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); |
| 182 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); | 193 | self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); |
| @@ -194,7 +205,9 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 194 | } | 205 | } |
| 195 | } | 206 | } |
| 196 | 207 | ||
| 197 | /// Queues the message to be sent but exerts backpressure | 208 | /// Queues the message to be sent. |
| 209 | /// | ||
| 210 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 198 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | 211 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 199 | self.split().0.write(frame).await | 212 | self.split().0.write(frame).await |
| 200 | } | 213 | } |
| @@ -221,12 +234,16 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 221 | CanTx::<T>::flush_all_inner().await | 234 | CanTx::<T>::flush_all_inner().await |
| 222 | } | 235 | } |
| 223 | 236 | ||
| 237 | /// Read a CAN frame. | ||
| 238 | /// | ||
| 239 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 240 | /// | ||
| 224 | /// Returns a tuple of the time the message was received and the message frame | 241 | /// Returns a tuple of the time the message was received and the message frame |
| 225 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 242 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 226 | self.split().1.read().await | 243 | self.split().1.read().await |
| 227 | } | 244 | } |
| 228 | 245 | ||
| 229 | /// Attempts to read a can frame without blocking. | 246 | /// Attempts to read a CAN frame without blocking. |
| 230 | /// | 247 | /// |
| 231 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. | 248 | /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. |
| 232 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { | 249 | pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { |
| @@ -288,7 +305,7 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 288 | } | 305 | } |
| 289 | } | 306 | } |
| 290 | 307 | ||
| 291 | pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { | 308 | const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { |
| 292 | const BS1_MAX: u8 = 16; | 309 | const BS1_MAX: u8 = 16; |
| 293 | const BS2_MAX: u8 = 8; | 310 | const BS2_MAX: u8 = 8; |
| 294 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; | 311 | const MAX_SAMPLE_POINT_PERMILL: u16 = 900; |
| @@ -379,21 +396,29 @@ impl<'d, T: Instance> Can<'d, T> { | |||
| 379 | Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) | 396 | Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) |
| 380 | } | 397 | } |
| 381 | 398 | ||
| 399 | /// Split the CAN driver into transmit and receive halves. | ||
| 400 | /// | ||
| 401 | /// Useful for doing separate transmit/receive tasks. | ||
| 382 | pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { | 402 | pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { |
| 383 | let (tx, rx0, rx1) = self.can.split_by_ref(); | 403 | let (tx, rx0, rx1) = self.can.split_by_ref(); |
| 384 | (CanTx { tx }, CanRx { rx0, rx1 }) | 404 | (CanTx { tx }, CanRx { rx0, rx1 }) |
| 385 | } | 405 | } |
| 386 | 406 | ||
| 407 | /// Get mutable access to the lower-level driver from the `bxcan` crate. | ||
| 387 | pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { | 408 | pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { |
| 388 | &mut self.can | 409 | &mut self.can |
| 389 | } | 410 | } |
| 390 | } | 411 | } |
| 391 | 412 | ||
| 413 | /// CAN driver, transmit half. | ||
| 392 | pub struct CanTx<'c, 'd, T: Instance> { | 414 | pub struct CanTx<'c, 'd, T: Instance> { |
| 393 | tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, | 415 | tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, |
| 394 | } | 416 | } |
| 395 | 417 | ||
| 396 | impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | 418 | impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { |
| 419 | /// Queues the message to be sent. | ||
| 420 | /// | ||
| 421 | /// If the TX queue is full, this will wait until there is space, therefore exerting backpressure. | ||
| 397 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { | 422 | pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus { |
| 398 | poll_fn(|cx| { | 423 | poll_fn(|cx| { |
| 399 | T::state().tx_waker.register(cx.waker()); | 424 | T::state().tx_waker.register(cx.waker()); |
| @@ -475,6 +500,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { | |||
| 475 | } | 500 | } |
| 476 | } | 501 | } |
| 477 | 502 | ||
| 503 | /// CAN driver, receive half. | ||
| 478 | #[allow(dead_code)] | 504 | #[allow(dead_code)] |
| 479 | pub struct CanRx<'c, 'd, T: Instance> { | 505 | pub struct CanRx<'c, 'd, T: Instance> { |
| 480 | rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, | 506 | rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, |
| @@ -482,6 +508,11 @@ pub struct CanRx<'c, 'd, T: Instance> { | |||
| 482 | } | 508 | } |
| 483 | 509 | ||
| 484 | impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { | 510 | impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { |
| 511 | /// Read a CAN frame. | ||
| 512 | /// | ||
| 513 | /// If no CAN frame is in the RX buffer, this will wait until there is one. | ||
| 514 | /// | ||
| 515 | /// Returns a tuple of the time the message was received and the message frame | ||
| 485 | pub async fn read(&mut self) -> Result<Envelope, BusError> { | 516 | pub async fn read(&mut self) -> Result<Envelope, BusError> { |
| 486 | poll_fn(|cx| { | 517 | poll_fn(|cx| { |
| 487 | T::state().err_waker.register(cx.waker()); | 518 | T::state().err_waker.register(cx.waker()); |
| @@ -590,13 +621,19 @@ pub(crate) mod sealed { | |||
| 590 | } | 621 | } |
| 591 | } | 622 | } |
| 592 | 623 | ||
| 624 | /// CAN instance trait. | ||
| 593 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { | 625 | pub trait Instance: sealed::Instance + RccPeripheral + 'static { |
| 626 | /// TX interrupt for this instance. | ||
| 594 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; | 627 | type TXInterrupt: crate::interrupt::typelevel::Interrupt; |
| 628 | /// RX0 interrupt for this instance. | ||
| 595 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; | 629 | type RX0Interrupt: crate::interrupt::typelevel::Interrupt; |
| 630 | /// RX1 interrupt for this instance. | ||
| 596 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; | 631 | type RX1Interrupt: crate::interrupt::typelevel::Interrupt; |
| 632 | /// SCE interrupt for this instance. | ||
| 597 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; | 633 | type SCEInterrupt: crate::interrupt::typelevel::Interrupt; |
| 598 | } | 634 | } |
| 599 | 635 | ||
| 636 | /// BXCAN instance newtype. | ||
| 600 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); | 637 | pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); |
| 601 | 638 | ||
| 602 | unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { | 639 | unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { |
