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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
//! Support for Controller Area Network (CAN) bus. Thinly wraps the [bxCAN](https://docs.rs/bxcan/0.5.0/bxcan/)
//! or [can-fd](https://crates.io/keywords/can-fd) libraries.
//!
//! 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.
use cfg_if::cfg_if;
use crate::{pac::RCC, util::rcc_en_reset};
// todo: H5 support.
cfg_if! {
if #[cfg(feature = "f3")] {
use bxcan;
use crate::pac::{can, CAN};
} else if #[cfg(any(feature = "f4", feature = "l4"))] {
use bxcan;
// todo: F4 has CAN2 as well.
use crate::pac::{CAN1 as CAN};
} else if #[cfg(feature = "g4")]{
use fdcan;
use crate::pac::{FDCAN1 as CAN};
} else { // eg G0, H7
use fdcan;
// todo: CAN2 on H7.
use crate::pac::{FDCAN1 as CAN};
}
}
/// Interface to the CAN peripheral.
pub struct Can {
pub regs: CAN,
}
impl Can {
/// Initialize a CAN peripheral, including enabling and resetting
/// its RCC peripheral clock. This is not handled by the `bxcan` or `canfd` crates.
pub fn new(regs: CAN) -> Self {
let rcc = unsafe { &*RCC::ptr() };
cfg_if! {
if #[cfg(feature = "f3")] {
rcc_en_reset!(apb1, can, rcc);
} else if #[cfg(any(feature = "f4", feature = "l4"))] {
rcc_en_reset!(apb1, can1, rcc);
} else if #[cfg(feature = "h7")]{
// We don't yet have apb1h support in `rcc_en_reset`.
rcc.apb1henr.modify(|_, w| w.fdcanen().set_bit());
rcc.apb1hrstr.modify(|_, w| w.fdcanrst().set_bit());
rcc.apb1hrstr.modify(|_, w| w.fdcanrst().clear_bit());
// set_message_ram_layout();
} else {
rcc_en_reset!(apb1, fdcan, rcc);
}
}
Self { regs }
}
/// Print the (raw) contents of the status register.
pub fn read_status(&self) -> u32 {
unsafe { self.regs.psr.read().bits() }
}
}
#[cfg(feature = "h7")]
// todo: Troubleshooting. COpied from H7xx-hal
/// Set the message RAM layout. This is flexible on H7. This function hard-sets it to the setting
/// that is hard-set by hardware on G4.
/// todo: Allow flexibility.
///
/// Note: Perhaps due to a reset of message ram called by the FDCAN crate's `.into_config_mode()`,
/// we run this in application firmware once in config mode. Although a better API would be in the constructor
/// This must be done after initial setup (Enabling RCC clocks most-likely).
pub fn set_message_ram_layout() {
let regs = unsafe { &(*CAN::ptr()) };
// RM, section 56.4.1: Operation modes: "Access to the FDCAN configuration registers is only
// enabled when both INIT bit in FDCAN_CCCR register and CCE bit in FDCAN_CCCR register are set.
// 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
// is set. CCE bit in FDCAN_CCCR register is automatically cleared when INIT bit in
// FDCAN_CCCR is cleared."
regs.cccr.modify(|_, w| w.init().set_bit());
while regs.cccr.read().init().bit_is_clear() {}
regs.cccr.modify(|_, w| w.cce().set_bit());
while regs.cccr.read().cce().bit_is_clear() {}
let mut word_addr = 0x000; // todo: 0x400 for FDCAN2?
use fdcan::message_ram::*;
// 11-bit filter
regs.sidfc
.modify(|_, w| unsafe { w.flssa().bits(word_addr) });
word_addr += STANDARD_FILTER_MAX as u16;
// 29-bit filter
regs.xidfc
.modify(|_, w| unsafe { w.flesa().bits(word_addr) });
word_addr += 2 * EXTENDED_FILTER_MAX as u16;
// Rx FIFO 0
regs.rxf0c.modify(|_, w| unsafe {
w.f0sa()
.bits(word_addr)
.f0s()
.bits(RX_FIFO_MAX)
.f0wm()
.bits(RX_FIFO_MAX)
});
word_addr += 18 * RX_FIFO_MAX as u16;
// Rx FIFO 1
regs.rxf1c.modify(|_, w| unsafe {
w.f1sa()
.bits(word_addr)
.f1s()
.bits(RX_FIFO_MAX)
.f1wm()
.bits(RX_FIFO_MAX)
});
word_addr += 18 * RX_FIFO_MAX as u16;
// Rx buffer - see below
// Tx event FIFO
regs.txefc.modify(|_, w| unsafe {
w.efsa()
.bits(word_addr)
.efs()
.bits(TX_EVENT_MAX)
.efwm()
.bits(TX_EVENT_MAX)
});
word_addr += 2 * TX_EVENT_MAX as u16;
// Tx buffers
regs.txbc
.modify(|_, w| unsafe { w.tbsa().bits(word_addr).tfqs().bits(TX_FIFO_MAX) });
word_addr += 18 * TX_FIFO_MAX as u16;
// Rx Buffer - not used
regs.rxbc.modify(|_, w| unsafe { w.rbsa().bits(word_addr) });
// TX event FIFO?
// Trigger memory?
// Set the element sizes to 16 bytes
regs.rxesc
.modify(|_, w| unsafe { w.rbds().bits(0b111).f1ds().bits(0b111).f0ds().bits(0b111) });
regs.txesc.modify(|_, w| unsafe { w.tbds().bits(0b111) });
}
// Implement the traits required for the `bxcan` or `fdcan` library.
cfg_if! {
if #[cfg(feature = "can_bx")] {
unsafe impl bxcan::Instance for Can {
const REGISTERS: *mut bxcan::RegisterBlock = CAN::ptr() as *mut _;
}
unsafe impl bxcan::FilterOwner for Can {
#[cfg(any(feature = "f3", feature = "f4"))]
const NUM_FILTER_BANKS: u8 = 28;
#[cfg(any(feature = "l4"))]
const NUM_FILTER_BANKS: u8 = 14;
}
unsafe impl bxcan::MasterInstance for Can {}
} else {
unsafe impl fdcan::Instance for Can {
const REGISTERS: *mut fdcan::RegisterBlock = CAN::ptr() as *mut _;
}
unsafe impl fdcan::message_ram::Instance for Can {
#[cfg(feature = "g4")]
// G4 RM, table 3. "Series memory map and peripheral register boundary
// addresses". CAN message RAM: 3 listings, 1kb each:
const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = (0x4000_a400 as *mut _);
// const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = (0x4000_a800 as *mut _); // todo ts
// const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = (0x4000_ac00 as *mut _); // todo ts
#[cfg(feature = "h7")]
// H743 RM, table 8. "Register boundary addresses". 0x4000_AC00 - 0x4000_D3FF". CAN message RAM.
const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = (0x4000_ac00 as *mut _);
// todo: (0x4000_ac00 + 0x1000) for H7, CAN2.
// todo: (0x4000_a750 as *mut _) for G4, CAN2
// todo: (0x4000_aaa0 as *mut _) fir G4 CAN3.
}
}
}