mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-10-30 05:40:55 +00:00
Merge pull request #2840 from MaxiluxSystems/feature/fdcan-runtime-cfg
stm32: can: fd: Properties for common runtime get/set operations
This commit is contained in:
commit
1de44e7086
@ -29,6 +29,24 @@ pub enum BusError {
|
|||||||
BusWarning,
|
BusWarning,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Bus error modes.
|
||||||
|
///
|
||||||
|
/// Contrary to the `BusError` enum which also includes last-seen acute protocol
|
||||||
|
/// errors, this enum includes only the mutually exclusive bus error modes.
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
pub enum BusErrorMode {
|
||||||
|
/// Error active mode (default). Controller will transmit an active error
|
||||||
|
/// frame upon protocol error.
|
||||||
|
ErrorActive,
|
||||||
|
/// Error passive mode. An error counter exceeded 127. Controller will
|
||||||
|
/// transmit a passive error frame upon protocol error.
|
||||||
|
ErrorPassive,
|
||||||
|
/// Bus off mode. The transmit error counter exceeded 255. Controller is not
|
||||||
|
/// participating in bus traffic.
|
||||||
|
BusOff,
|
||||||
|
}
|
||||||
|
|
||||||
/// Frame Create Errors
|
/// Frame Create Errors
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||||
|
@ -146,6 +146,7 @@ pub struct CanConfigurator<'d, T: Instance> {
|
|||||||
config: crate::can::fd::config::FdCanConfig,
|
config: crate::can::fd::config::FdCanConfig,
|
||||||
/// Reference to internals.
|
/// Reference to internals.
|
||||||
instance: FdcanInstance<'d, T>,
|
instance: FdcanInstance<'d, T>,
|
||||||
|
properties: Properties<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
|
fn calc_ns_per_timer_tick<T: Instance>(mode: crate::can::fd::config::FrameTransmissionConfig) -> u64 {
|
||||||
@ -199,9 +200,15 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
Self {
|
Self {
|
||||||
config,
|
config,
|
||||||
instance: FdcanInstance(peri),
|
instance: FdcanInstance(peri),
|
||||||
|
properties: Properties::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get driver properties
|
||||||
|
pub fn properties(&self) -> &Properties<T> {
|
||||||
|
&self.properties
|
||||||
|
}
|
||||||
|
|
||||||
/// Get configuration
|
/// Get configuration
|
||||||
pub fn config(&self) -> crate::can::fd::config::FdCanConfig {
|
pub fn config(&self) -> crate::can::fd::config::FdCanConfig {
|
||||||
return self.config;
|
return self.config;
|
||||||
@ -240,32 +247,6 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
self.config = self.config.set_data_bit_timing(nbtr);
|
self.config = self.config.set_data_bit_timing(nbtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set an Standard Address CAN filter into slot 'id'
|
|
||||||
#[inline]
|
|
||||||
pub fn set_standard_filter(&mut self, slot: StandardFilterSlot, filter: StandardFilter) {
|
|
||||||
T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set an array of Standard Address CAN filters and overwrite the current set
|
|
||||||
pub fn set_standard_filters(&mut self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
|
|
||||||
for (i, f) in filters.iter().enumerate() {
|
|
||||||
T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set an Extended Address CAN filter into slot 'id'
|
|
||||||
#[inline]
|
|
||||||
pub fn set_extended_filter(&mut self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
|
|
||||||
T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set an array of Extended Address CAN filters and overwrite the current set
|
|
||||||
pub fn set_extended_filters(&mut self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
|
|
||||||
for (i, f) in filters.iter().enumerate() {
|
|
||||||
T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Start in mode.
|
/// Start in mode.
|
||||||
pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
|
pub fn start(self, mode: OperatingMode) -> Can<'d, T> {
|
||||||
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
|
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.config.frame_transmit);
|
||||||
@ -277,6 +258,7 @@ impl<'d, T: Instance> CanConfigurator<'d, T> {
|
|||||||
config: self.config,
|
config: self.config,
|
||||||
instance: self.instance,
|
instance: self.instance,
|
||||||
_mode: mode,
|
_mode: mode,
|
||||||
|
properties: self.properties,
|
||||||
};
|
};
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
@ -303,9 +285,15 @@ pub struct Can<'d, T: Instance> {
|
|||||||
/// Reference to internals.
|
/// Reference to internals.
|
||||||
instance: FdcanInstance<'d, T>,
|
instance: FdcanInstance<'d, T>,
|
||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
|
properties: Properties<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d, T: Instance> Can<'d, T> {
|
impl<'d, T: Instance> Can<'d, T> {
|
||||||
|
/// Get driver properties
|
||||||
|
pub fn properties(&self) -> &Properties<T> {
|
||||||
|
&self.properties
|
||||||
|
}
|
||||||
|
|
||||||
/// Flush one of the TX mailboxes.
|
/// Flush one of the TX mailboxes.
|
||||||
pub async fn flush(&self, idx: usize) {
|
pub async fn flush(&self, idx: usize) {
|
||||||
poll_fn(|cx| {
|
poll_fn(|cx| {
|
||||||
@ -350,8 +338,8 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
T::state().rx_mode.read_fd::<T>().await
|
T::state().rx_mode.read_fd::<T>().await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split instance into separate Tx(write) and Rx(read) portions
|
/// Split instance into separate portions: Tx(write), Rx(read), common properties
|
||||||
pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>) {
|
pub fn split(self) -> (CanTx<'d, T>, CanRx<'d, T>, Properties<T>) {
|
||||||
(
|
(
|
||||||
CanTx {
|
CanTx {
|
||||||
config: self.config,
|
config: self.config,
|
||||||
@ -363,6 +351,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
_instance2: T::regs(),
|
_instance2: T::regs(),
|
||||||
_mode: self._mode,
|
_mode: self._mode,
|
||||||
},
|
},
|
||||||
|
self.properties,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,6 +362,7 @@ impl<'d, T: Instance> Can<'d, T> {
|
|||||||
//_instance2: T::regs(),
|
//_instance2: T::regs(),
|
||||||
instance: tx._instance,
|
instance: tx._instance,
|
||||||
_mode: rx._mode,
|
_mode: rx._mode,
|
||||||
|
properties: Properties::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,6 +398,7 @@ pub struct BufferedCan<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_S
|
|||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
tx_buf: &'static TxBuf<TX_BUF_SIZE>,
|
||||||
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
rx_buf: &'static RxBuf<RX_BUF_SIZE>,
|
||||||
|
properties: Properties<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
||||||
@ -426,10 +417,16 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
_mode,
|
_mode,
|
||||||
tx_buf,
|
tx_buf,
|
||||||
rx_buf,
|
rx_buf,
|
||||||
|
properties: Properties::new(),
|
||||||
}
|
}
|
||||||
.setup()
|
.setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get driver properties
|
||||||
|
pub fn properties(&self) -> &Properties<T> {
|
||||||
|
&self.properties
|
||||||
|
}
|
||||||
|
|
||||||
fn setup(self) -> Self {
|
fn setup(self) -> Self {
|
||||||
// We don't want interrupts being processed while we change modes.
|
// We don't want interrupts being processed while we change modes.
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| unsafe {
|
||||||
@ -494,6 +491,7 @@ pub struct BufferedCanFd<'d, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF
|
|||||||
_mode: OperatingMode,
|
_mode: OperatingMode,
|
||||||
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
tx_buf: &'static TxFdBuf<TX_BUF_SIZE>,
|
||||||
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
rx_buf: &'static RxFdBuf<RX_BUF_SIZE>,
|
||||||
|
properties: Properties<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sender that can be used for sending CAN frames.
|
/// Sender that can be used for sending CAN frames.
|
||||||
@ -542,10 +540,16 @@ impl<'c, 'd, T: Instance, const TX_BUF_SIZE: usize, const RX_BUF_SIZE: usize>
|
|||||||
_mode,
|
_mode,
|
||||||
tx_buf,
|
tx_buf,
|
||||||
rx_buf,
|
rx_buf,
|
||||||
|
properties: Properties::new(),
|
||||||
}
|
}
|
||||||
.setup()
|
.setup()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get driver properties
|
||||||
|
pub fn properties(&self) -> &Properties<T> {
|
||||||
|
&self.properties
|
||||||
|
}
|
||||||
|
|
||||||
fn setup(self) -> Self {
|
fn setup(self) -> Self {
|
||||||
// We don't want interrupts being processed while we change modes.
|
// We don't want interrupts being processed while we change modes.
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| unsafe {
|
||||||
@ -804,6 +808,71 @@ impl TxMode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Common driver properties, including filters and error counters
|
||||||
|
pub struct Properties<T> {
|
||||||
|
// phantom pointer to ensure !Sync
|
||||||
|
instance: PhantomData<*const T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Instance> Properties<T> {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
instance: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a standard address CAN filter in the specified slot in FDCAN memory.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_standard_filter(&self, slot: StandardFilterSlot, filter: StandardFilter) {
|
||||||
|
T::registers().msg_ram_mut().filters.flssa[slot as usize].activate(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the full array of standard address CAN filters in FDCAN memory.
|
||||||
|
/// Overwrites all standard address filters in memory.
|
||||||
|
pub fn set_standard_filters(&self, filters: &[StandardFilter; STANDARD_FILTER_MAX as usize]) {
|
||||||
|
for (i, f) in filters.iter().enumerate() {
|
||||||
|
T::registers().msg_ram_mut().filters.flssa[i].activate(*f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set an extended address CAN filter in the specified slot in FDCAN memory.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_extended_filter(&self, slot: ExtendedFilterSlot, filter: ExtendedFilter) {
|
||||||
|
T::registers().msg_ram_mut().filters.flesa[slot as usize].activate(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the full array of extended address CAN filters in FDCAN memory.
|
||||||
|
/// Overwrites all extended address filters in memory.
|
||||||
|
pub fn set_extended_filters(&self, filters: &[ExtendedFilter; EXTENDED_FILTER_MAX as usize]) {
|
||||||
|
for (i, f) in filters.iter().enumerate() {
|
||||||
|
T::registers().msg_ram_mut().filters.flesa[i].activate(*f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the CAN RX error counter
|
||||||
|
pub fn rx_error_count(&self) -> u8 {
|
||||||
|
T::regs().ecr().read().rec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the CAN TX error counter
|
||||||
|
pub fn tx_error_count(&self) -> u8 {
|
||||||
|
T::regs().ecr().read().tec()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current bus error mode
|
||||||
|
pub fn bus_error_mode(&self) -> BusErrorMode {
|
||||||
|
// This read will clear LEC and DLEC. This is not ideal, but protocol
|
||||||
|
// error reporting in this driver should have a big ol' FIXME on it
|
||||||
|
// anyway!
|
||||||
|
let psr = T::regs().psr().read();
|
||||||
|
match (psr.bo(), psr.ep()) {
|
||||||
|
(false, false) => BusErrorMode::ErrorActive,
|
||||||
|
(false, true) => BusErrorMode::ErrorPassive,
|
||||||
|
(true, _) => BusErrorMode::BusOff,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
pub rx_mode: RxMode,
|
pub rx_mode: RxMode,
|
||||||
pub tx_mode: TxMode,
|
pub tx_mode: TxMode,
|
||||||
|
@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
|
|
||||||
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
|
let mut can = can::CanConfigurator::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
|
||||||
|
|
||||||
can.set_extended_filter(
|
can.properties().set_extended_filter(
|
||||||
can::filter::ExtendedFilterSlot::_0,
|
can::filter::ExtendedFilterSlot::_0,
|
||||||
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
||||||
);
|
);
|
||||||
@ -128,7 +128,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
let (mut tx, mut rx) = can.split();
|
let (mut tx, mut rx, _props) = can.split();
|
||||||
// With split
|
// With split
|
||||||
loop {
|
loop {
|
||||||
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
|
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
|
||||||
|
@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut tx, mut rx) = can.split();
|
let (mut tx, mut rx, _props) = can.split();
|
||||||
// With split
|
// With split
|
||||||
loop {
|
loop {
|
||||||
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
|
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
|
||||||
|
@ -67,7 +67,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut tx, mut rx) = can.split();
|
let (mut tx, mut rx, _props) = can.split();
|
||||||
// With split
|
// With split
|
||||||
loop {
|
loop {
|
||||||
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
|
let frame = can::frame::Frame::new_extended(0x123456F, &[i; 8]).unwrap();
|
||||||
|
@ -15,7 +15,7 @@ stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma"
|
|||||||
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
|
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
|
||||||
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
|
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac", "ucpd"]
|
||||||
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"]
|
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan", "cordic"]
|
||||||
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "hash", "cordic"]
|
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng", "fdcan", "hash", "cordic"]
|
||||||
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
|
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan", "hash", "cryp"]
|
||||||
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
|
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan", "hash", "cryp"]
|
||||||
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
|
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
|
||||||
|
@ -24,7 +24,19 @@ bind_interrupts!(struct Irqs1 {
|
|||||||
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
|
#[cfg(feature = "stm32h563zi")]
|
||||||
|
fn options() -> (Config, TestOptions) {
|
||||||
|
info!("H563 config");
|
||||||
|
(
|
||||||
|
config(),
|
||||||
|
TestOptions {
|
||||||
|
max_latency: Duration::from_micros(1200),
|
||||||
|
max_buffered: 3,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi"))]
|
||||||
fn options() -> (Config, TestOptions) {
|
fn options() -> (Config, TestOptions) {
|
||||||
use embassy_stm32::rcc;
|
use embassy_stm32::rcc;
|
||||||
info!("H75 config");
|
info!("H75 config");
|
||||||
@ -88,11 +100,11 @@ async fn main(_spawner: Spawner) {
|
|||||||
can.set_bitrate(250_000);
|
can.set_bitrate(250_000);
|
||||||
can2.set_bitrate(250_000);
|
can2.set_bitrate(250_000);
|
||||||
|
|
||||||
can.set_extended_filter(
|
can.properties().set_extended_filter(
|
||||||
can::filter::ExtendedFilterSlot::_0,
|
can::filter::ExtendedFilterSlot::_0,
|
||||||
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
||||||
);
|
);
|
||||||
can2.set_extended_filter(
|
can2.properties().set_extended_filter(
|
||||||
can::filter::ExtendedFilterSlot::_0,
|
can::filter::ExtendedFilterSlot::_0,
|
||||||
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
||||||
);
|
);
|
||||||
@ -106,8 +118,8 @@ async fn main(_spawner: Spawner) {
|
|||||||
info!("CAN Configured");
|
info!("CAN Configured");
|
||||||
|
|
||||||
// Test again with a split
|
// Test again with a split
|
||||||
let (mut tx, mut rx) = can.split();
|
let (mut tx, mut rx, _props) = can.split();
|
||||||
let (mut tx2, mut rx2) = can2.split();
|
let (mut tx2, mut rx2, _props) = can2.split();
|
||||||
run_split_can_tests(&mut tx, &mut rx, &options).await;
|
run_split_can_tests(&mut tx, &mut rx, &options).await;
|
||||||
run_split_can_tests(&mut tx2, &mut rx2, &options).await;
|
run_split_can_tests(&mut tx2, &mut rx2, &options).await;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user