Skip to content

Commit b9f2de1

Browse files
committed
can: Add advanced filter configuration
1 parent a168666 commit b9f2de1

File tree

3 files changed

+212
-34
lines changed

3 files changed

+212
-34
lines changed

examples/can-echo.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use panic_halt as _;
66
use cortex_m_rt::entry;
77
use nb::block;
88
use stm32f1xx_hal::{
9-
can::{Can, Filter},
9+
can::{Can, Filter, NUM_FILTER_BANKS},
1010
pac,
1111
prelude::*,
1212
};
@@ -49,6 +49,7 @@ fn main() -> ! {
4949
// Split the filters at index 0: No filters for CAN1 (unused), 28 filters
5050
// for CAN2.
5151
let (_filters1, mut filters2) = can1.split_filters(0).unwrap();
52+
assert_eq!(filters2.num_available(), NUM_FILTER_BANKS);
5253
filters2.add(&Filter::accept_all()).unwrap(); // Receive all messages.
5354
let mut rx = can2.take_rx(filters2).unwrap();
5455

examples/can-loopback.rs

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use panic_halt as _;
66
use cortex_m_rt::entry;
77
use nb::block;
88
use stm32f1xx_hal::{
9-
can::{Can, Filter, Frame, NUM_FILTER_BANKS},
9+
can::{Can, Filter, Frame},
1010
pac,
1111
prelude::*,
1212
};
@@ -40,26 +40,60 @@ fn main() -> ! {
4040
// Get the transmitter part.
4141
let mut tx = can.take_tx().unwrap();
4242

43-
// Receive all messages.
43+
// Use advanced configurations for the first three filter banks.
4444
#[cfg(not(feature = "connectivity"))]
45-
let mut filters = can.split_filters().unwrap();
45+
let mut filters = can
46+
.split_filters_advanced(0x0000_0006, 0xFFFF_FFFA, 0x0000_0007)
47+
.unwrap();
4648
#[cfg(feature = "connectivity")]
47-
let (mut filters, _) = can.split_filters(NUM_FILTER_BANKS / 2).unwrap();
48-
filters.add(&Filter::accept_all()).unwrap();
49+
let (mut filters, _) = can
50+
.split_filters_advanced(0x0000_0006, 0xFFFF_FFFA, 0x0000_0007, 3)
51+
.unwrap();
52+
53+
assert_eq!(filters.num_available(), 8);
54+
55+
// Matches 0, 1, 2
56+
filters
57+
.add_standard([
58+
&Filter::new_standard(0).with_mask(!0b1),
59+
&Filter::new_standard(0).with_mask(!0b10),
60+
])
61+
.unwrap();
62+
63+
// Matches 4, 5
64+
filters
65+
.add_list([&Filter::new_standard(4), &Filter::new_standard(5)])
66+
.unwrap();
67+
68+
// Matches 8, 9, 10, 11
69+
filters
70+
.add_standard_list([
71+
&Filter::new_standard(8),
72+
&Filter::new_standard(9),
73+
&Filter::new_standard(10),
74+
&Filter::new_standard(11),
75+
])
76+
.unwrap();
77+
4978
let mut rx = can.take_rx(filters).unwrap();
5079

5180
// Sync to the bus and start normal operation.
5281
block!(can.enable()).ok();
5382

54-
// Send and receive messages with incrementing identifier.
55-
for id in (0..0x7FF_u32).cycle() {
83+
// Some messages shall pass the filters.
84+
for &id in &[0, 1, 2, 4, 5, 8, 9, 10, 11] {
5685
let frame_tx = Frame::new_standard(id, &[id as u8]);
5786
block!(tx.transmit(&frame_tx)).unwrap();
58-
5987
let frame_rx = block!(rx.receive()).unwrap();
60-
6188
assert_eq!(frame_tx, frame_rx);
6289
}
6390

91+
// Others must be filtered out.
92+
for &id in &[3, 6, 7, 12] {
93+
let frame_tx = Frame::new_standard(id, &[id as u8]);
94+
block!(tx.transmit(&frame_tx)).unwrap();
95+
assert!(rx.receive().is_err());
96+
}
97+
6498
loop {}
6599
}

src/can.rs

Lines changed: 167 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,10 @@ impl Can<CAN1> {
473473
/// Filters are required for the receiver to accept any messages at all.
474474
#[cfg(not(feature = "connectivity"))]
475475
pub fn split_filters(&mut self) -> Option<Filters<CAN1>> {
476-
self.split_filters_internal(NUM_FILTER_BANKS)?;
476+
// Set all filter banks to 32bit scale and mask mode.
477+
// Filters are alternating between between the FIFO0 and FIFO1 to share the
478+
// load equally.
479+
self.split_filters_internal(0x0000_0000, 0xFFFF_FFFF, 0xAAAA_AAAA, NUM_FILTER_BANKS)?;
477480
Some(Filters::new(0, NUM_FILTER_BANKS))
478481
}
479482

@@ -486,33 +489,80 @@ impl Can<CAN1> {
486489
/// for CAN2.
487490
#[cfg(feature = "connectivity")]
488491
pub fn split_filters(&mut self, split_idx: usize) -> Option<(Filters<CAN1>, Filters<CAN2>)> {
489-
self.split_filters_internal(split_idx)?;
492+
// Set all filter banks to 32bit scale and mask mode.
493+
// Filters are alternating between between the FIFO0 and FIFO1 to share the
494+
// load equally.
495+
self.split_filters_internal(0x0000_0000, 0xFFFF_FFFF, 0xAAAA_AAAA, split_idx)?;
490496
Some((
491497
Filters::new(0, split_idx),
492498
Filters::new(split_idx, NUM_FILTER_BANKS),
493499
))
494500
}
495501

496-
fn split_filters_internal(&mut self, split_idx: usize) -> Option<()> {
502+
/// Advanced version of `Can::split_filters()`.
503+
///
504+
/// The additional parameters are bitmasks configure the filter banks.
505+
/// Bit 0 for filter bank 0, bit 1 for filter bank 1 and so on.
506+
/// `fm1r` in combination with `fs1r` sets the filter bank layout. The correct
507+
/// `Filters::add_*()` function must be used.
508+
/// `ffa1r` selects the FIFO the filter uses to store accepted messages.
509+
/// More details can be found in the reference manual of the device.
510+
#[cfg(not(feature = "connectivity"))]
511+
pub fn split_filters_advanced(
512+
&mut self,
513+
fm1r: u32,
514+
fs1r: u32,
515+
ffa1r: u32,
516+
) -> Option<Filters<CAN1>> {
517+
self.split_filters_internal(fm1r, fs1r, ffa1r, NUM_FILTER_BANKS)?;
518+
Some(Filters::new(0, NUM_FILTER_BANKS))
519+
}
520+
521+
/// Advanced version of `Can::split_filters()`.
522+
///
523+
/// The additional parameters are bitmasks to configure the filter banks.
524+
/// Bit 0 for filter bank 0, bit 1 for filter bank 1 and so on.
525+
/// `fm1r` in combination with `fs1r` sets the filter bank layout. The correct
526+
/// `Filters::add_*()` function must be used.
527+
/// `ffa1r` selects the FIFO the filter uses to store accepted messages.
528+
/// More details can be found in the reference manual of the device.
529+
#[cfg(feature = "connectivity")]
530+
pub fn split_filters_advanced(
531+
&mut self,
532+
fm1r: u32,
533+
fs1r: u32,
534+
ffa1r: u32,
535+
split_idx: usize,
536+
) -> Option<(Filters<CAN1>, Filters<CAN2>)> {
537+
self.split_filters_internal(fm1r, fs1r, ffa1r, split_idx)?;
538+
Some((
539+
Filters::new(0, split_idx),
540+
Filters::new(split_idx, NUM_FILTER_BANKS),
541+
))
542+
}
543+
544+
fn split_filters_internal(
545+
&mut self,
546+
fm1r: u32,
547+
fs1r: u32,
548+
ffa1r: u32,
549+
_split_idx: usize,
550+
) -> Option<()> {
497551
let can = unsafe { &*CAN1::ptr() };
498552

499553
if can.fmr.read().finit().bit_is_clear() {
500554
return None;
501555
}
502556

503-
// Same configuration for all filters banks.
504-
can.fm1r.write(|w| unsafe { w.bits(0x0000_0000) }); // Mask mode
505-
can.fs1r.write(|w| unsafe { w.bits(0xFFFF_FFFF) }); // 32bit scale
506-
507-
// Filters are alternating between between the FIFO0 and FIFO1 to share the
508-
// load equally.
509-
can.ffa1r.write(|w| unsafe { w.bits(0xAAAA_AAAA) });
557+
can.fm1r.write(|w| unsafe { w.bits(fm1r) });
558+
can.fs1r.write(|w| unsafe { w.bits(fs1r) });
559+
can.ffa1r.write(|w| unsafe { w.bits(ffa1r) });
510560

511561
// Init filter banks. Each used filter must still be enabled individually.
512562
#[allow(unused_unsafe)]
513563
can.fmr.modify(|_, w| unsafe {
514564
#[cfg(feature = "connectivity")]
515-
w.can2sb().bits(split_idx as u8);
565+
w.can2sb().bits(_split_idx as u8);
516566
w.finit().clear_bit()
517567
});
518568

@@ -578,6 +628,16 @@ impl Filter {
578628
}
579629

580630
fn matches_single_id(&self) -> bool {
631+
((self.mask & (Id::IDE_MASK | Id::RTR_MASK)) == (Id::IDE_MASK | Id::RTR_MASK))
632+
&& if self.is_extended() {
633+
(self.mask & Id::EXTENDED_MASK) == Id::EXTENDED_MASK
634+
} else {
635+
(self.mask & Id::STANDARD_MASK) == Id::STANDARD_MASK
636+
}
637+
}
638+
639+
fn as_16bit_filter(reg: u32) -> u32 {
640+
(reg & Id::STANDARD_MASK) >> 16 | (reg & Id::IDE_MASK) << 1 | (reg & Id::RTR_MASK) << 3
581641
}
582642
}
583643

@@ -602,33 +662,116 @@ where
602662
}
603663
}
604664

605-
pub fn num_filters(&self) -> usize {
606-
self.stop_idx - self.start_idx
665+
/// Returns the number of available filters.
666+
pub fn num_available(&self) -> usize {
667+
let can = unsafe { &*CAN1::ptr() };
668+
669+
let mut filter_count = self.stop_idx - self.start_idx;
670+
671+
let owned_bits = ((1 << filter_count) - 1) << self.start_idx;
672+
let mode_list = can.fm1r.read().bits() & owned_bits;
673+
let scale_16bit = !can.fs1r.read().bits() & owned_bits;
674+
675+
filter_count += mode_list.count_ones() as usize;
676+
filter_count += scale_16bit.count_ones() as usize;
677+
filter_count += (mode_list & scale_16bit).count_ones() as usize;
678+
filter_count
607679
}
608680

609681
/// Adds a filter. Returns `Err` if the maximum number of filters was reached.
610682
pub fn add(&mut self, filter: &Filter) -> Result<(), ()> {
611-
let can = unsafe { &*CAN1::ptr() };
683+
let idx = self.next_idx()?;
684+
self.check_config(idx, false, true)?;
685+
self.write_filter_bank(idx, filter.id, filter.mask);
686+
Ok(())
687+
}
612688

613-
let idx = self.start_idx + self.count;
614-
if idx >= self.stop_idx {
689+
/// Adds two filters, each filtering for a single ID.
690+
///
691+
/// The filter bank must to be configured to `fm1r.fbm = 1` and `fs1r.fsc = 1` by
692+
/// `Can::split_filters_advanced()`.
693+
pub fn add_list(&mut self, filters: [&Filter; 2]) -> Result<(), ()> {
694+
if !filters[0].matches_single_id() || !filters[1].matches_single_id() {
695+
return Err(());
696+
}
697+
698+
let idx = self.next_idx()?;
699+
self.check_config(idx, true, true)?;
700+
self.write_filter_bank(idx, filters[0].id, filters[1].id);
701+
Ok(())
702+
}
703+
704+
/// Adds two standard ID filters with mask support.
705+
///
706+
/// The filter bank must to be configured to `fm1r.fbm = 0` and `fs1r.fsc = 0` by
707+
/// `Can::split_filters_advanced()`.
708+
pub fn add_standard(&mut self, filters: [&Filter; 2]) -> Result<(), ()> {
709+
if filters[0].is_extended() || filters[1].is_extended() {
615710
return Err(());
616711
}
617712

618-
let list_mode = (can.fm1r.read().bits() & (1 << idx)) != 0;
619-
let scale_32bit = (can.fs1r.read().bits() & (1 << idx)) != 0;
620-
if !list_mode && scale_32bit {
621-
let filter_bank = &can.fb[idx];
622-
filter_bank.fr1.write(|w| unsafe { w.bits(filter.id) });
623-
filter_bank.fr2.write(|w| unsafe { w.bits(filter.mask) });
624-
bb::set(&can.fa1r, idx as u8); // Enable filter
625-
self.count += 1;
713+
let idx = self.next_idx()?;
714+
self.check_config(idx, false, false)?;
715+
self.write_filter_bank(
716+
idx,
717+
Filter::as_16bit_filter(filters[0].mask) << 16 | Filter::as_16bit_filter(filters[0].id),
718+
Filter::as_16bit_filter(filters[1].mask) << 16 | Filter::as_16bit_filter(filters[1].id),
719+
);
720+
Ok(())
721+
}
722+
723+
/// Adds four filters, each filtering for a single standard ID.
724+
///
725+
/// The filter bank must to be configured to `fm1r.fbm = 1` and `fs1r.fsc = 0` by
726+
/// `Can::split_filters_advanced()`.
727+
pub fn add_standard_list(&mut self, filters: [&Filter; 4]) -> Result<(), ()> {
728+
for filter in &filters {
729+
if !filter.matches_single_id() {
730+
return Err(());
731+
}
732+
}
733+
734+
let idx = self.next_idx()?;
735+
self.check_config(idx, true, false)?;
736+
self.write_filter_bank(
737+
idx,
738+
Filter::as_16bit_filter(filters[1].id) << 16 | Filter::as_16bit_filter(filters[0].id),
739+
Filter::as_16bit_filter(filters[3].id) << 16 | Filter::as_16bit_filter(filters[2].id),
740+
);
741+
Ok(())
742+
}
743+
744+
fn next_idx(&self) -> Result<usize, ()> {
745+
let idx = self.start_idx + self.count;
746+
if idx < self.stop_idx {
747+
Ok(idx)
748+
} else {
749+
Err(())
750+
}
751+
}
752+
753+
fn check_config(&self, idx: usize, mode_list: bool, scale_32bit: bool) -> Result<(), ()> {
754+
let can = unsafe { &*CAN1::ptr() };
755+
756+
if mode_list == ((can.fm1r.read().bits() & (1 << idx)) != 0)
757+
&& scale_32bit == ((can.fs1r.read().bits() & (1 << idx)) != 0)
758+
{
626759
Ok(())
627760
} else {
628761
Err(())
629762
}
630763
}
631764

765+
fn write_filter_bank(&mut self, idx: usize, fr1: u32, fr2: u32) {
766+
let can = unsafe { &*CAN1::ptr() };
767+
768+
let filter_bank = &can.fb[idx];
769+
filter_bank.fr1.write(|w| unsafe { w.bits(fr1) });
770+
filter_bank.fr2.write(|w| unsafe { w.bits(fr2) });
771+
bb::set(&can.fa1r, idx as u8); // Enable filter
772+
self.count += 1;
773+
}
774+
632775
/// Disables all enabled filters.
633776
pub fn clear(&mut self) {
634777
let can = unsafe { &*CAN1::ptr() };

0 commit comments

Comments
 (0)