use core::marker::PhantomData; use core::ops::{Deref, DerefMut}; use embassy::util::Unborrow; use embassy_hal_common::unborrow; use crate::gpio::Pin; use crate::{peripherals, rcc::RccPeripheral}; pub use bxcan::*; pub struct Can<'d, T: Instance + bxcan::Instance> { phantom: PhantomData<&'d mut T>, can: bxcan::Can, } impl<'d, T: Instance + bxcan::Instance> Can<'d, T> { pub fn new( peri: impl Unborrow + 'd, // irq: impl Unborrow + 'd, rx: impl Unborrow> + 'd, tx: impl Unborrow> + 'd, ) -> Self { unborrow!(peri, rx, tx); unsafe { rx.set_as_af(rx.af_num()); tx.set_as_af(tx.af_num()); } T::enable(); T::reset(); // TODO: CAN2 also required CAN1 clock Self { phantom: PhantomData, can: bxcan::Can::new(peri), } } } impl<'d, T: Instance + bxcan::Instance> Drop for Can<'d, T> { fn drop(&mut self) { // Cannot call `free()` because it moves the instance. // Manually reset the peripheral. unsafe { T::regs().mcr().write(|w| w.set_reset(true)); } T::disable(); } } impl<'d, T: Instance + bxcan::Instance> Deref for Can<'d, T> { type Target = bxcan::Can; fn deref(&self) -> &Self::Target { &self.can } } impl<'d, T: Instance + bxcan::Instance> DerefMut for Can<'d, T> { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.can } } pub(crate) mod sealed { use super::*; pub trait Instance { fn regs() -> &'static crate::pac::bxcan::Can; } pub trait RxPin: Pin { fn af_num(&self) -> u8; } pub trait TxPin: Pin { fn af_num(&self) -> u8; } } pub trait Instance: sealed::Instance + RccPeripheral {} pub trait RxPin: sealed::RxPin {} pub trait TxPin: sealed::TxPin {} crate::pac::peripherals!( (bxcan, $inst:ident) => { impl sealed::Instance for peripherals::$inst { fn regs() -> &'static crate::pac::bxcan::Can { &crate::pac::$inst } } impl Instance for peripherals::$inst {} unsafe impl bxcan::Instance for peripherals::$inst { const REGISTERS: *mut bxcan::RegisterBlock = crate::pac::$inst.0 as *mut _; } }; // (bxcan, CAN) => { // unsafe impl bxcan::FilterOwner for Can { // const NUM_FILTER_BANKS: u8 = 14; // } // }; ); crate::pac::peripherals!( // TODO: rename CAN to CAN1 on yaml level?? (bxcan, CAN) => { unsafe impl bxcan::FilterOwner for peripherals::CAN { const NUM_FILTER_BANKS: u8 = 14; } }; (bxcan, CAN1) => { unsafe impl bxcan::FilterOwner for peripherals::CAN1 { const NUM_FILTER_BANKS: u8 = 14; } }; (bxcan, CAN2) => { // TODO: when CAN2 existis, we have 28 filter banks unsafe impl bxcan::MasterInstance for peripherals::CAN1 {} }; ); macro_rules! impl_pin { ($inst:ident, $pin:ident, $signal:ident, $af:expr) => { impl $signal for peripherals::$pin {} impl sealed::$signal for peripherals::$pin { fn af_num(&self) -> u8 { $af } } }; } crate::pac::peripheral_pins!( ($inst:ident, bxcan, CAN, $pin:ident, TX, $af:expr) => { impl_pin!($inst, $pin, TxPin, $af); }; ($inst:ident, bxcan, CAN, $pin:ident, RX, $af:expr) => { impl_pin!($inst, $pin, RxPin, $af); }; );