diff --git a/src/filter.rs b/src/filter.rs index 40f7fa8..02b3539 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -270,12 +270,13 @@ impl MasterFilters<'_, I> { impl MasterFilters<'_, I> { /// Sets the index at which the filter banks owned by the slave peripheral start. - pub fn set_split(&mut self, split_index: u8) { + pub fn set_split(&mut self, split_index: u8) -> &mut Self { assert!(split_index <= I::NUM_FILTER_BANKS); self.registers() .fmr .modify(|_, w| unsafe { w.can2sb().bits(split_index) }); self.bank_count = split_index; + self } /// Accesses the filters assigned to the slave peripheral. diff --git a/src/lib.rs b/src/lib.rs index 65593d2..1cde263 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -211,14 +211,11 @@ impl PartialOrd for IdReg { } /// Configuration proxy to be used with `Can::configure()`. -pub struct CanConfig { - _can: PhantomData, +pub struct CanConfig<'a, I: Instance> { + _can: PhantomData<&'a mut I>, } -impl CanConfig -where - I: Instance, -{ +impl CanConfig<'_, I> { fn registers(&self) -> &RegisterBlock { unsafe { &*I::REGISTERS } } @@ -235,25 +232,44 @@ where /// /// Then copy the `CAN_BUS_TIME` register value from the table and pass it as the `btr` /// parameter to this method. - pub fn set_bit_timing(&mut self, btr: u32) { + pub fn set_bit_timing(&mut self, btr: u32) -> &mut Self { let can = self.registers(); can.btr.modify(|r, w| unsafe { let mode_bits = r.bits() & 0xC000_0000; w.bits(mode_bits | btr) }); + self } /// Enables or disables loopback mode: Internally connects the TX and RX /// signals together. - pub fn set_loopback(&mut self, enabled: bool) { + pub fn set_loopback(&mut self, enabled: bool) -> &mut Self { let can = self.registers(); can.btr.modify(|_, w| w.lbkm().bit(enabled)); + self } /// Enables or disables silent mode: Disconnects the TX signal from the pin. - pub fn set_silent(&mut self, enabled: bool) { + pub fn set_silent(&mut self, enabled: bool) -> &mut Self { let can = self.registers(); can.btr.modify(|_, w| w.silm().bit(enabled)); + self + } +} + +impl Drop for CanConfig<'_, I> { + #[inline] + fn drop(&mut self) { + // Leave initialization mode + let can = self.registers(); + can.mcr + .modify(|_, w| w.sleep().set_bit().inrq().clear_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_set() && msr.inak().bit_is_clear() { + break; + } + } } } @@ -307,9 +323,23 @@ where let mut config = CanConfig { _can: PhantomData }; f(&mut config); + } + + /// Configure bit timings and silent/loop-back mode. + pub fn modify_config(&mut self) -> CanConfig<'_, I> { + let can = self.registers(); + + // Enter init mode. + can.mcr + .modify(|_, w| w.sleep().clear_bit().inrq().set_bit()); + loop { + let msr = can.msr.read(); + if msr.slak().bit_is_clear() && msr.inak().bit_is_set() { + break; + } + } - // Leave init mode: go back to sleep. - self.sleep(); + CanConfig { _can: PhantomData } } /// Configures the automatic wake-up feature. diff --git a/testsuite/tests/integration.rs b/testsuite/tests/integration.rs index ecc1bf0..d57aae7 100644 --- a/testsuite/tests/integration.rs +++ b/testsuite/tests/integration.rs @@ -15,17 +15,15 @@ impl State { let periph = defmt::unwrap!(pac::Peripherals::take()); let (can1, can2) = testsuite::init(periph); let mut can1 = Can::new(can1); - can1.configure(|c| { - c.set_loopback(true); - c.set_silent(true); - c.set_bit_timing(0x00050000); - }); + can1.modify_config() + .set_loopback(true) + .set_silent(true) + .set_bit_timing(0x00050000); let mut can2 = Can::new(can2); - can2.configure(|c| { - c.set_loopback(true); - c.set_silent(true); - c.set_bit_timing(0x00050000); - }); + can2.modify_config() + .set_loopback(true) + .set_silent(true) + .set_bit_timing(0x00050000); Self { can1, can2 } } @@ -34,21 +32,21 @@ impl State { /// /// This is useful for testing recovery when the mailboxes are full. fn go_slow(&mut self) { - self.can1.configure(|c| { - c.set_loopback(true); - c.set_silent(true); - c.set_bit_timing(0x007f_03ff); - }); + self.can1 + .modify_config() + .set_loopback(true) + .set_silent(true) + .set_bit_timing(0x007f_03ff); nb::block!(self.can1.enable()).unwrap(); } /// Configures the default (fast) speed. fn go_fast(&mut self) { - self.can1.configure(|c| { - c.set_loopback(true); - c.set_silent(true); - c.set_bit_timing(0x00050000); - }); + self.can1 + .modify_config() + .set_loopback(true) + .set_silent(true) + .set_bit_timing(0x00050000); nb::block!(self.can1.enable()).unwrap(); } } @@ -384,26 +382,32 @@ mod tests { /// Requires that both are hooked up to the same CAN bus. #[test] fn ext_roundtrip(state: &mut State) { - state.can1.configure(|c| { - c.set_loopback(false); - c.set_silent(false); - c.set_bit_timing(0x00050000); - }); - state.can2.configure(|c| { - c.set_loopback(false); - c.set_silent(false); - c.set_bit_timing(0x00050000); - }); - - let mut filt1 = state.can1.modify_filters(); - filt1.set_split(1); - filt1.clear(); - filt1.enable_bank(0, Mask32::accept_all()); - - let mut filt2 = filt1.slave_filters(); - filt2.clear(); - filt2.enable_bank(1, Mask32::accept_all()); - drop(filt1); + state + .can1 + .modify_config() + .set_loopback(false) + .set_silent(false) + .set_bit_timing(0x00050000); + state + .can2 + .modify_config() + .set_loopback(false) + .set_silent(false) + .set_bit_timing(0x00050000); + + state + .can1 + .modify_filters() + .set_split(1) + .clear() + .enable_bank(0, Mask32::accept_all()); + + state + .can1 + .modify_filters() + .slave_filters() + .clear() + .enable_bank(1, Mask32::accept_all()); block!(state.can1.enable()).unwrap(); block!(state.can2.enable()).unwrap();