Merge pull request #2307 from embassy-rs/stm32-docs

stm32/can: docs, cleanup interrupt handling.y
This commit is contained in:
Dario Nieuwenhuis 2023-12-18 17:52:37 +00:00 committed by GitHub
commit 59d2977c0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -21,8 +21,10 @@ use crate::{interrupt, peripherals, Peripheral};
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Envelope { pub struct Envelope {
/// Reception time.
#[cfg(feature = "time")] #[cfg(feature = "time")]
pub ts: embassy_time::Instant, pub ts: embassy_time::Instant,
/// The actual CAN frame.
pub frame: bxcan::Frame, pub frame: bxcan::Frame,
} }
@ -43,6 +45,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::TXInterrupt> for TxInterruptH
} }
} }
/// RX0 interrupt handler.
pub struct Rx0InterruptHandler<T: Instance> { pub struct Rx0InterruptHandler<T: Instance> {
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
@ -54,6 +57,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX0Interrupt> for Rx0Interrup
} }
} }
/// RX1 interrupt handler.
pub struct Rx1InterruptHandler<T: Instance> { pub struct Rx1InterruptHandler<T: Instance> {
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
@ -65,6 +69,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::RX1Interrupt> for Rx1Interrup
} }
} }
/// SCE interrupt handler.
pub struct SceInterruptHandler<T: Instance> { pub struct SceInterruptHandler<T: Instance> {
_phantom: PhantomData<T>, _phantom: PhantomData<T>,
} }
@ -82,10 +87,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
} }
} }
/// CAN driver
pub struct Can<'d, T: Instance> { pub struct Can<'d, T: Instance> {
pub can: bxcan::Can<BxcanInstance<'d, T>>, can: bxcan::Can<BxcanInstance<'d, T>>,
} }
/// CAN bus error
#[allow(missing_docs)]
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum BusError { pub enum BusError {
@ -101,6 +109,7 @@ pub enum BusError {
BusWarning, BusWarning,
} }
/// Error returned by `try_read`
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TryReadError { pub enum TryReadError {
@ -110,6 +119,7 @@ pub enum TryReadError {
Empty, Empty,
} }
/// Error returned by `try_write`
#[derive(Debug)] #[derive(Debug)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))] #[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum TryWriteError { pub enum TryWriteError {
@ -177,6 +187,7 @@ impl<'d, T: Instance> Can<'d, T> {
Self { can } Self { can }
} }
/// Set CAN bit rate.
pub fn set_bitrate(&mut self, bitrate: u32) { pub fn set_bitrate(&mut self, bitrate: u32) {
let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap(); let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
self.can.modify_config().set_bit_timing(bit_timing).leave_disabled(); self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
@ -194,7 +205,9 @@ impl<'d, T: Instance> Can<'d, T> {
} }
} }
/// Queues the message to be sent but exerts backpressure /// 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) -> bxcan::TransmitStatus { pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
self.split().0.write(frame).await self.split().0.write(frame).await
} }
@ -221,12 +234,16 @@ impl<'d, T: Instance> Can<'d, T> {
CanTx::<T>::flush_all_inner().await CanTx::<T>::flush_all_inner().await
} }
/// 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 /// Returns a tuple of the time the message was received and the message frame
pub async fn read(&mut self) -> Result<Envelope, BusError> { pub async fn read(&mut self) -> Result<Envelope, BusError> {
self.split().1.read().await self.split().1.read().await
} }
/// Attempts to read a can frame without blocking. /// Attempts to read a CAN frame without blocking.
/// ///
/// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue. /// Returns [Err(TryReadError::Empty)] if there are no frames in the rx queue.
pub fn try_read(&mut self) -> Result<Envelope, TryReadError> { pub fn try_read(&mut self) -> Result<Envelope, TryReadError> {
@ -288,7 +305,7 @@ impl<'d, T: Instance> Can<'d, T> {
} }
} }
pub const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> { const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
const BS1_MAX: u8 = 16; const BS1_MAX: u8 = 16;
const BS2_MAX: u8 = 8; const BS2_MAX: u8 = 8;
const MAX_SAMPLE_POINT_PERMILL: u16 = 900; const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
@ -379,21 +396,29 @@ impl<'d, T: Instance> Can<'d, T> {
Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1)) Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
} }
/// Split the CAN driver into transmit and receive halves.
///
/// Useful for doing separate transmit/receive tasks.
pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) { pub fn split<'c>(&'c mut self) -> (CanTx<'c, 'd, T>, CanRx<'c, 'd, T>) {
let (tx, rx0, rx1) = self.can.split_by_ref(); let (tx, rx0, rx1) = self.can.split_by_ref();
(CanTx { tx }, CanRx { rx0, rx1 }) (CanTx { tx }, CanRx { rx0, rx1 })
} }
/// Get mutable access to the lower-level driver from the `bxcan` crate.
pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> { pub fn as_mut(&mut self) -> &mut bxcan::Can<BxcanInstance<'d, T>> {
&mut self.can &mut self.can
} }
} }
/// CAN driver, transmit half.
pub struct CanTx<'c, 'd, T: Instance> { pub struct CanTx<'c, 'd, T: Instance> {
tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>, tx: &'c mut bxcan::Tx<BxcanInstance<'d, T>>,
} }
impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> { impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
/// 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) -> bxcan::TransmitStatus { pub async fn write(&mut self, frame: &Frame) -> bxcan::TransmitStatus {
poll_fn(|cx| { poll_fn(|cx| {
T::state().tx_waker.register(cx.waker()); T::state().tx_waker.register(cx.waker());
@ -475,6 +500,7 @@ impl<'c, 'd, T: Instance> CanTx<'c, 'd, T> {
} }
} }
/// CAN driver, receive half.
#[allow(dead_code)] #[allow(dead_code)]
pub struct CanRx<'c, 'd, T: Instance> { pub struct CanRx<'c, 'd, T: Instance> {
rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>, rx0: &'c mut bxcan::Rx0<BxcanInstance<'d, T>>,
@ -482,6 +508,11 @@ pub struct CanRx<'c, 'd, T: Instance> {
} }
impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> { impl<'c, 'd, T: Instance> CanRx<'c, 'd, T> {
/// 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> { pub async fn read(&mut self) -> Result<Envelope, BusError> {
poll_fn(|cx| { poll_fn(|cx| {
T::state().err_waker.register(cx.waker()); T::state().err_waker.register(cx.waker());
@ -585,30 +616,24 @@ pub(crate) mod sealed {
pub trait Instance { pub trait Instance {
const REGISTERS: *mut bxcan::RegisterBlock; const REGISTERS: *mut bxcan::RegisterBlock;
fn regs() -> &'static crate::pac::can::Can; fn regs() -> crate::pac::can::Can;
fn state() -> &'static State; fn state() -> &'static State;
} }
} }
pub trait TXInstance { /// CAN instance trait.
pub trait Instance: sealed::Instance + RccPeripheral + 'static {
/// TX interrupt for this instance.
type TXInterrupt: crate::interrupt::typelevel::Interrupt; type TXInterrupt: crate::interrupt::typelevel::Interrupt;
} /// RX0 interrupt for this instance.
pub trait RX0Instance {
type RX0Interrupt: crate::interrupt::typelevel::Interrupt; type RX0Interrupt: crate::interrupt::typelevel::Interrupt;
} /// RX1 interrupt for this instance.
pub trait RX1Instance {
type RX1Interrupt: crate::interrupt::typelevel::Interrupt; type RX1Interrupt: crate::interrupt::typelevel::Interrupt;
} /// SCE interrupt for this instance.
pub trait SCEInstance {
type SCEInterrupt: crate::interrupt::typelevel::Interrupt; type SCEInterrupt: crate::interrupt::typelevel::Interrupt;
} }
pub trait InterruptableInstance: TXInstance + RX0Instance + RX1Instance + SCEInstance {} /// BXCAN instance newtype.
pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>); pub struct BxcanInstance<'a, T>(PeripheralRef<'a, T>);
unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> { unsafe impl<'d, T: Instance> bxcan::Instance for BxcanInstance<'d, T> {
@ -620,8 +645,8 @@ foreach_peripheral!(
impl sealed::Instance for peripherals::$inst { impl sealed::Instance for peripherals::$inst {
const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _; const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
fn regs() -> &'static crate::pac::can::Can { fn regs() -> crate::pac::can::Can {
&crate::pac::$inst crate::pac::$inst
} }
fn state() -> &'static sealed::State { fn state() -> &'static sealed::State {
@ -630,32 +655,12 @@ foreach_peripheral!(
} }
} }
impl Instance for peripherals::$inst {} impl Instance for peripherals::$inst {
type TXInterrupt = crate::_generated::peripheral_interrupts::$inst::TX;
foreach_interrupt!( type RX0Interrupt = crate::_generated::peripheral_interrupts::$inst::RX0;
($inst,can,CAN,TX,$irq:ident) => { type RX1Interrupt = crate::_generated::peripheral_interrupts::$inst::RX1;
impl TXInstance for peripherals::$inst { type SCEInterrupt = crate::_generated::peripheral_interrupts::$inst::SCE;
type TXInterrupt = crate::interrupt::typelevel::$irq; }
}
};
($inst,can,CAN,RX0,$irq:ident) => {
impl RX0Instance for peripherals::$inst {
type RX0Interrupt = crate::interrupt::typelevel::$irq;
}
};
($inst,can,CAN,RX1,$irq:ident) => {
impl RX1Instance for peripherals::$inst {
type RX1Interrupt = crate::interrupt::typelevel::$irq;
}
};
($inst,can,CAN,SCE,$irq:ident) => {
impl SCEInstance for peripherals::$inst {
type SCEInterrupt = crate::interrupt::typelevel::$irq;
}
};
);
impl InterruptableInstance for peripherals::$inst {}
}; };
); );