stm32_hal2/can/
mod.rs

1//! Support for Controller Area Network (CAN) bus. Thinly wraps the [bxCAN](https://docs.rs/bxcan/0.5.0/bxcan/)
2//! or [can-fd](https://crates.io/keywords/can-fd) libraries.
3//!
4//! Requires the `can_bx` or `can_fd_g[h]` features. F3, F4, and L4 use BX CAN. G0, G4, L5, and H7 use FD CAN.
5
6use cfg_if::cfg_if;
7
8use crate::{
9    error::{Error, Result},
10    pac::RCC,
11    util::{bounded_loop, rcc_en_reset},
12};
13
14// todo: H5 support.
15cfg_if! {
16    if #[cfg(feature = "f3")] {
17        use bxcan;
18        use crate::pac::{can, CAN};
19
20    } else if #[cfg(any(feature = "f4", feature = "l4"))] {
21        use bxcan;
22        // todo: F4 has CAN2 as well.
23        use crate::pac::{CAN1 as CAN};
24    } else { // eg G0, H7
25        use fdcan;
26        // todo: CAN2 on H7.
27        use crate::pac::{FDCAN1 as CAN};
28    }
29}
30
31cfg_if! {
32    if #[cfg(feature = "g4")] {
33        pub mod g4;
34        pub use g4::*;
35    } else {
36        /// Interface to the CAN peripheral.
37        pub struct Can {
38            pub regs: CAN,
39        }
40
41        impl Can {
42            /// Initialize a CAN peripheral, including  enabling and resetting
43            /// its RCC peripheral clock. This is not handled by the `bxcan` or `canfd` crates.
44            pub fn new(regs: CAN) -> Self {
45                let rcc = unsafe { &*RCC::ptr() };
46
47                cfg_if! {
48                    if #[cfg(feature = "f3")] {
49                        rcc_en_reset!(apb1, can, rcc);
50                    } else if #[cfg(any(feature = "f4", feature = "l4"))] {
51                        rcc_en_reset!(apb1, can1, rcc);
52                    } else if #[cfg(feature = "h7")]{
53                        // We don't yet have apb1h support in `rcc_en_reset`.
54                        rcc.apb1henr().modify(|_, w| w.fdcanen().bit(true));
55                        rcc.apb1hrstr().modify(|_, w| w.fdcanrst().bit(true));
56                        rcc.apb1hrstr().modify(|_, w| w.fdcanrst().clear_bit());
57
58                        // set_message_ram_layout();
59
60                    } else {
61                        rcc_en_reset!(apb1, fdcan, rcc);
62                    }
63                }
64
65                Self { regs }
66            }
67
68            /// Print the (raw) contents of the status register.
69            pub fn read_status(&self) -> u32 {
70                cfg_if! {
71                    if #[cfg(any(feature = "h7", feature = "l5"))] {
72                        unsafe { self.regs.psr().read().bits() }
73                    } else {
74                        unsafe { self.regs.msr.read().bits() }
75                    }
76                }
77            }
78        }
79
80        #[cfg(feature = "h7")]
81        // todo: Troubleshooting. COpied from H7xx-hal
82        /// Set the message RAM layout. This is flexible on H7. This function hard-sets it to the setting
83        /// that is hard-set by hardware on G4.
84        /// todo: Allow flexibility.
85        ///
86        /// Note: Perhaps due to a reset of message ram called by the FDCAN crate's `.into_config_mode()`,
87        /// we run this in application firmware once in config mode. Although a better API would be in the constructor
88        /// This must be done after initial setup (Enabling RCC clocks most-likely).
89        pub fn set_message_ram_layout() -> Result<()> {
90            let regs = unsafe { &(*CAN::ptr()) };
91
92            // RM, section 56.4.1: Operation modes: "Access to the FDCAN configuration registers is only
93            // enabled when both INIT bit in FDCAN_CCCR register and CCE bit in FDCAN_CCCR register are set.
94            // Note: we do this as 2 separate writes. RM: "CCE bit in FDCAN_CCCR register can only be set/cleared while INIT bit in FDCAN_CCCR
95            // is set. CCE bit in FDCAN_CCCR register is automatically cleared when INIT bit in
96            // FDCAN_CCCR is cleared."
97            regs.cccr().modify(|_, w| w.init().bit(true));
98            bounded_loop!(regs.cccr.read().init().bit_is_clear(), Error::RegisterUnchanged);
99            regs.cccr().modify(|_, w| w.cce().bit(true));
100            bounded_loop!(regs.cccr.read().cce().bit_is_clear(), Error::RegisterUnchanged);
101
102            let mut word_addr = 0x000; // todo: 0x400 for FDCAN2?
103
104            use fdcan::message_ram::*;
105
106            // 11-bit filter
107            regs.sidfc()
108                .modify(|_, w| unsafe { w.flssa().bits(word_addr) });
109            word_addr += STANDARD_FILTER_MAX as u16;
110
111            // 29-bit filter
112            regs.xidfc()
113                .modify(|_, w| unsafe { w.flesa().bits(word_addr) });
114            word_addr += 2 * EXTENDED_FILTER_MAX as u16;
115
116            // Rx FIFO 0
117            regs.rxf0c().modify(|_, w| unsafe {
118                w.f0sa()
119                    .bits(word_addr)
120                    .f0s()
121                    .bits(RX_FIFO_MAX)
122                    .f0wm()
123                    .bits(RX_FIFO_MAX)
124            });
125            word_addr += 18 * RX_FIFO_MAX as u16;
126
127            // Rx FIFO 1
128            regs.rxf1c().modify(|_, w| unsafe {
129                w.f1sa()
130                    .bits(word_addr)
131                    .f1s()
132                    .bits(RX_FIFO_MAX)
133                    .f1wm()
134                    .bits(RX_FIFO_MAX)
135            });
136            word_addr += 18 * RX_FIFO_MAX as u16;
137
138            // Rx buffer - see below
139            // Tx event FIFO
140            regs.txefc().modify(|_, w| unsafe {
141                w.efsa()
142                    .bits(word_addr)
143                    .efs()
144                    .bits(TX_EVENT_MAX)
145                    .efwm()
146                    .bits(TX_EVENT_MAX)
147            });
148            word_addr += 2 * TX_EVENT_MAX as u16;
149
150            // Tx buffers
151            regs.txbc()
152                .modify(|_, w| unsafe { w.tbsa().bits(word_addr).tfqs().bits(TX_FIFO_MAX) });
153            word_addr += 18 * TX_FIFO_MAX as u16;
154
155            // Rx Buffer - not used
156            regs.rxbc().modify(|_, w| unsafe { w.rbsa().bits(word_addr) });
157
158            // TX event FIFO?
159            // Trigger memory?
160
161            // Set the element sizes to 16 bytes
162            regs.rxesc()
163                .modify(|_, w| unsafe { w.rbds().bits(0b111).f1ds().bits(0b111).f0ds().bits(0b111) });
164            regs.txesc().modify(|_, w| unsafe { w.tbds().bits(0b111) });
165        }
166
167        // Implement the traits required for the `bxcan` or `fdcan` library.
168        cfg_if! {
169            if #[cfg(feature = "can_bx")] {
170                unsafe impl bxcan::Instance for Can {
171                    const REGISTERS: *mut bxcan::RegisterBlock = CAN::ptr() as *mut _;
172                }
173
174                unsafe impl bxcan::FilterOwner for Can {
175                    #[cfg(any(feature = "f3", feature = "f4"))]
176                    const NUM_FILTER_BANKS: u8 = 28;
177                    #[cfg(any(feature = "l4"))]
178                    const NUM_FILTER_BANKS: u8 = 14;
179                }
180
181                unsafe impl bxcan::MasterInstance for Can {}
182            } else {
183                unsafe impl fdcan::Instance for Can {
184                    const REGISTERS: *mut fdcan::RegisterBlock = CAN::ptr() as *mut _;
185                }
186
187                unsafe impl fdcan::message_ram::Instance for Can {
188                    #[cfg(feature = "h7")]
189                    // H743 RM, table 8. "Register boundary addresses". 0x4000_AC00 - 0x4000_D3FF". CAN message RAM.
190                    const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = (0x4000_ac00 as *mut _);
191                    // todo: (0x4000_ac00 + 0x1000) for H7, CAN2.
192                    // todo: (0x4000_a750 as *mut _) for G4, CAN2
193                    // todo: (0x4000_aaa0 as *mut _) fir G4 CAN3.
194                }
195            }
196        }
197        // todo: H5 support.
198
199    }
200}