1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//! Controller Area Network.
//!
//! CAN is currently not enabled by default, and
//! can be enabled by the `can` feature.
//!
//! It is a implementation of the [`bxcan`][can] traits.
//!
//! [can]: bxcan
//!
//! A usage example of the can peripheral can be found at [examples/can.rs]
//!
//! [examples/can.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.8.0/examples/can.rs

use crate::gpio::{gpioa, gpiob};
use crate::gpio::{PushPull, AF7, AF9};
use crate::pac;

use crate::rcc::APB1;

pub use bxcan;
use bxcan::RegisterBlock;

use cfg_if::cfg_if;

mod sealed {
    pub trait Sealed {}
}

/// Marker trait for pins (with specific AF mode) that can be used as a CAN RX pin.
pub trait RxPin: sealed::Sealed {}

/// Marker trait for pins (with specific AF mode) that can be used as a CAN TX pin.
pub trait TxPin: sealed::Sealed {}

cfg_if! {
    if #[cfg(any(feature = "gpio-f302", feature = "gpio-f303"))] {
        use crate::gpio::gpiod;

        impl sealed::Sealed for gpioa::PA11<AF9<PushPull>> {}
        impl RxPin for gpioa::PA11<AF9<PushPull>> {}
        impl sealed::Sealed for gpioa::PA12<AF9<PushPull>> {}
        impl TxPin for gpioa::PA12<AF9<PushPull>> {}

        impl sealed::Sealed for gpiob::PB8<AF9<PushPull>> {}
        impl RxPin for gpiob::PB8<AF9<PushPull>> {}
        impl sealed::Sealed for gpiob::PB9<AF9<PushPull>> {}
        impl TxPin for gpiob::PB9<AF9<PushPull>> {}

        impl sealed::Sealed for gpiod::PD0<AF7<PushPull>> {}
        impl RxPin for gpiod::PD0<AF7<PushPull>> {}
        impl sealed::Sealed for gpiod::PD1<AF7<PushPull>> {}
        impl TxPin for gpiod::PD1<AF7<PushPull>> {}
    }
}

/// Struct representing a CAN peripheral and its configured TX and RX pins.
///
/// See [`bxcan::Instance`] for more information on how to use the CAN interface.
pub struct Can<Tx, Rx> {
    can: pac::CAN,
    tx: Tx,
    rx: Rx,
}

impl<Tx, Rx> Can<Tx, Rx>
where
    Tx: TxPin,
    Rx: RxPin,
{
    /// Create a new CAN instance, using the specified TX and RX pins.
    ///
    /// Note: this does not actually initialize the CAN bus.
    /// You will need to first call [`bxcan::Can::new`] and  set the bus configuration and filters
    /// before the peripheral can be enabled.
    /// See the CAN example, for a more thorough example of the full setup process.
    pub fn new(can: pac::CAN, tx: Tx, rx: Rx, apb1: &mut APB1) -> bxcan::Can<Self> {
        apb1.enr().modify(|_, w| w.canen().enabled());
        apb1.rstr().modify(|_, w| w.canrst().set_bit());
        apb1.rstr().modify(|_, w| w.canrst().clear_bit());

        bxcan::Can::new(Can { can, tx, rx })
    }

    /// Releases the CAN peripheral and associated pins
    pub fn free(self) -> (pac::CAN, Tx, Rx) {
        (self.can, self.tx, self.rx)
    }
}

unsafe impl<Tx, Rx> bxcan::Instance for Can<Tx, Rx> {
    const REGISTERS: *mut RegisterBlock = pac::CAN::ptr() as *mut _;
}

unsafe impl<Tx, Rx> bxcan::FilterOwner for Can<Tx, Rx> {
    const NUM_FILTER_BANKS: u8 = 28;
}