Remove more BXCAN generics.

This commit is contained in:
Corey Schuhen 2024-06-02 19:40:25 +10:00 committed by Corey Schuhen
parent e61136fa4a
commit 367a22cc0e
6 changed files with 99 additions and 82 deletions

View File

@ -2,7 +2,7 @@
use core::marker::PhantomData;
use super::{ExtendedId, Fifo, FilterOwner, Id, Instance, MasterInstance, StandardId};
use super::{ExtendedId, Fifo, Id, StandardId};
const F32_RTR: u32 = 0b010; // set the RTR bit to match remote frames
const F32_IDE: u32 = 0b100; // set the IDE bit to match extended identifiers
@ -210,24 +210,24 @@ impl From<Mask32> for BankConfig {
}
/// Interface to the filter banks of a CAN peripheral.
pub struct MasterFilters<'a, I: FilterOwner> {
pub struct MasterFilters<'a> {
/// Number of assigned filter banks.
///
/// On chips with splittable filter banks, this value can be dynamic.
bank_count: u8,
_can: PhantomData<&'a mut I>,
canregs: crate::pac::can::Can,
_phantom: PhantomData<&'a ()>,
info: &'static crate::can::Info,
}
// NOTE: This type mutably borrows the CAN instance and has unique access to the registers while it
// exists.
impl<I: FilterOwner> MasterFilters<'_, I> {
pub(crate) unsafe fn new(canregs: crate::pac::can::Can) -> Self {
impl MasterFilters<'_> {
pub(crate) unsafe fn new(info: &'static crate::can::Info) -> Self {
// Enable initialization mode.
canregs.fmr().modify(|reg| reg.set_finit(true));
info.regs.0.fmr().modify(|reg| reg.set_finit(true));
// Read the filter split value.
let bank_count = canregs.fmr().read().can2sb();
let bank_count = info.regs.0.fmr().read().can2sb();
// (Reset value of CAN2SB is 0x0E, 14, which, in devices with 14 filter banks, assigns all
// of them to the master peripheral, and in devices with 28, assigns them 50/50 to
@ -235,8 +235,8 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
Self {
bank_count,
_can: PhantomData,
canregs,
_phantom: PhantomData,
info,
}
}
@ -244,7 +244,7 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
FilterBanks {
start_idx: 0,
bank_count: self.bank_count,
canregs: self.canregs,
info: self.info,
}
}
@ -291,49 +291,49 @@ impl<I: FilterOwner> MasterFilters<'_, I> {
}
}
impl<I: MasterInstance> MasterFilters<'_, I> {
impl MasterFilters<'_> {
/// Sets the index at which the filter banks owned by the slave peripheral start.
pub fn set_split(&mut self, split_index: u8) -> &mut Self {
assert!(split_index <= I::NUM_FILTER_BANKS);
self.canregs.fmr().modify(|reg| reg.set_can2sb(split_index));
assert!(split_index <= self.info.num_filter_banks);
self.info.regs.0.fmr().modify(|reg| reg.set_can2sb(split_index));
self.bank_count = split_index;
self
}
/// Accesses the filters assigned to the slave peripheral.
pub fn slave_filters(&mut self) -> SlaveFilters<'_, I> {
pub fn slave_filters(&mut self) -> SlaveFilters<'_> {
// NB: This mutably borrows `self`, so it has full access to the filter bank registers.
SlaveFilters {
start_idx: self.bank_count,
bank_count: I::NUM_FILTER_BANKS - self.bank_count,
_can: PhantomData,
canregs: self.canregs,
bank_count: self.info.num_filter_banks - self.bank_count,
_phantom: PhantomData,
info: self.info,
}
}
}
impl<I: FilterOwner> Drop for MasterFilters<'_, I> {
impl Drop for MasterFilters<'_> {
#[inline]
fn drop(&mut self) {
// Leave initialization mode.
self.canregs.fmr().modify(|regs| regs.set_finit(false));
self.info.regs.0.fmr().modify(|regs| regs.set_finit(false));
}
}
/// Interface to the filter banks assigned to a slave peripheral.
pub struct SlaveFilters<'a, I: Instance> {
pub struct SlaveFilters<'a> {
start_idx: u8,
bank_count: u8,
_can: PhantomData<&'a mut I>,
canregs: crate::pac::can::Can,
_phantom: PhantomData<&'a ()>,
info: &'static crate::can::Info,
}
impl<I: Instance> SlaveFilters<'_, I> {
impl SlaveFilters<'_> {
fn banks_imm(&self) -> FilterBanks {
FilterBanks {
start_idx: self.start_idx,
bank_count: self.bank_count,
canregs: self.canregs,
info: self.info,
}
}
@ -377,14 +377,14 @@ impl<I: Instance> SlaveFilters<'_, I> {
struct FilterBanks {
start_idx: u8,
bank_count: u8,
canregs: crate::pac::can::Can,
info: &'static crate::can::Info,
}
impl FilterBanks {
fn clear(&mut self) {
let mask = filter_bitmask(self.start_idx, self.bank_count);
self.canregs.fa1r().modify(|reg| {
self.info.regs.0.fa1r().modify(|reg| {
for i in 0..28usize {
if (0x01u32 << i) & mask != 0 {
reg.set_fact(i, false);
@ -399,7 +399,11 @@ impl FilterBanks {
fn disable(&mut self, index: u8) {
self.assert_bank_index(index);
self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, false))
self.info
.regs
.0
.fa1r()
.modify(|reg| reg.set_fact(index as usize, false))
}
fn enable(&mut self, index: u8, fifo: Fifo, config: BankConfig) {
@ -407,11 +411,11 @@ impl FilterBanks {
// Configure mode.
let mode = matches!(config, BankConfig::List16(_) | BankConfig::List32(_));
self.canregs.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
self.info.regs.0.fm1r().modify(|reg| reg.set_fbm(index as usize, mode));
// Configure scale.
let scale = matches!(config, BankConfig::List32(_) | BankConfig::Mask32(_));
self.canregs.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
self.info.regs.0.fs1r().modify(|reg| reg.set_fsc(index as usize, scale));
// Configure filter register.
let (fxr1, fxr2);
@ -433,12 +437,12 @@ impl FilterBanks {
fxr2 = a.mask;
}
};
let bank = self.canregs.fb(index as usize);
let bank = self.info.regs.0.fb(index as usize);
bank.fr1().write(|w| w.0 = fxr1);
bank.fr2().write(|w| w.0 = fxr2);
// Assign to the right FIFO
self.canregs.ffa1r().modify(|reg| {
self.info.regs.0.ffa1r().modify(|reg| {
reg.set_ffa(
index as usize,
match fifo {
@ -449,7 +453,7 @@ impl FilterBanks {
});
// Set active.
self.canregs.fa1r().modify(|reg| reg.set_fact(index as usize, true))
self.info.regs.0.fa1r().modify(|reg| reg.set_fact(index as usize, true))
}
}

View File

@ -6,7 +6,7 @@ use core::marker::PhantomData;
use core::task::Poll;
use embassy_hal_internal::interrupt::InterruptExt;
use embassy_hal_internal::{into_ref, PeripheralRef};
use embassy_hal_internal::into_ref;
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
use embassy_sync::channel::Channel;
use embassy_sync::waitqueue::AtomicWaker;
@ -91,11 +91,13 @@ impl<T: Instance> interrupt::typelevel::Handler<T::SCEInterrupt> for SceInterrup
}
/// Configuration proxy returned by [`Can::modify_config`].
pub struct CanConfig<'a, T: Instance> {
can: PhantomData<&'a mut T>,
pub struct CanConfig<'a> {
phantom: PhantomData<&'a ()>,
info: &'static Info,
periph_clock: crate::time::Hertz,
}
impl<T: Instance> CanConfig<'_, T> {
impl CanConfig<'_> {
/// Configures the bit timings.
///
/// You can use <http://www.bittiming.can-wiki.info/> to calculate the `btr` parameter. Enter
@ -109,7 +111,7 @@ impl<T: Instance> CanConfig<'_, T> {
/// 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(self, bt: crate::can::util::NominalBitTiming) -> Self {
Registers(T::regs()).set_bit_timing(bt);
self.info.regs.set_bit_timing(bt);
self
}
@ -117,20 +119,20 @@ impl<T: Instance> CanConfig<'_, T> {
///
/// This is a helper that internally calls `set_bit_timing()`[Self::set_bit_timing].
pub fn set_bitrate(self, bitrate: u32) -> Self {
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
self.set_bit_timing(bit_timing)
}
/// Enables or disables loopback mode: Internally connects the TX and RX
/// signals together.
pub fn set_loopback(self, enabled: bool) -> Self {
Registers(T::regs()).set_loopback(enabled);
self.info.regs.set_loopback(enabled);
self
}
/// Enables or disables silent mode: Disconnects the TX signal from the pin.
pub fn set_silent(self, enabled: bool) -> Self {
Registers(T::regs()).set_silent(enabled);
self.info.regs.set_silent(enabled);
self
}
@ -141,23 +143,24 @@ impl<T: Instance> CanConfig<'_, T> {
///
/// Automatic retransmission is enabled by default.
pub fn set_automatic_retransmit(self, enabled: bool) -> Self {
Registers(T::regs()).set_automatic_retransmit(enabled);
self.info.regs.set_automatic_retransmit(enabled);
self
}
}
impl<T: Instance> Drop for CanConfig<'_, T> {
impl Drop for CanConfig<'_> {
#[inline]
fn drop(&mut self) {
Registers(T::regs()).leave_init_mode();
self.info.regs.leave_init_mode();
}
}
/// CAN driver
pub struct Can<'d, T: Instance> {
_peri: PeripheralRef<'d, T>,
pub struct Can<'d> {
phantom: PhantomData<&'d ()>,
info: &'static Info,
state: &'static State,
periph_clock: crate::time::Hertz,
}
/// Error returned by `try_write`
@ -168,11 +171,11 @@ pub enum TryWriteError {
Full,
}
impl<'d, T: Instance> Can<'d, T> {
impl<'d> Can<'d> {
/// Creates a new Bxcan instance, keeping the peripheral in sleep mode.
/// You must call [Can::enable_non_blocking] to use the peripheral.
pub fn new(
peri: impl Peripheral<P = T> + 'd,
pub fn new<T: Instance>(
_peri: impl Peripheral<P = T> + 'd,
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
_irqs: impl interrupt::typelevel::Binding<T::TXInterrupt, TxInterruptHandler<T>>
@ -181,7 +184,7 @@ impl<'d, T: Instance> Can<'d, T> {
+ interrupt::typelevel::Binding<T::SCEInterrupt, SceInterruptHandler<T>>
+ 'd,
) -> Self {
into_ref!(peri, rx, tx);
into_ref!(_peri, rx, tx);
let info = T::info();
let regs = &T::info().regs;
@ -226,15 +229,16 @@ impl<'d, T: Instance> Can<'d, T> {
Registers(T::regs()).leave_init_mode();
Self {
_peri: peri,
phantom: PhantomData,
info: T::info(),
state: T::state(),
periph_clock: T::frequency(),
}
}
/// Set CAN bit rate.
pub fn set_bitrate(&mut self, bitrate: u32) {
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
let bit_timing = util::calc_can_timings(self.periph_clock, bitrate).unwrap();
self.modify_config().set_bit_timing(bit_timing);
}
@ -242,10 +246,14 @@ impl<'d, T: Instance> Can<'d, T> {
///
/// Calling this method will enter initialization mode. You must enable the peripheral
/// again afterwards with [`enable`](Self::enable).
pub fn modify_config(&mut self) -> CanConfig<'_, T> {
Registers(T::regs()).enter_init_mode();
pub fn modify_config(&mut self) -> CanConfig<'_> {
self.info.regs.enter_init_mode();
CanConfig { can: PhantomData }
CanConfig {
phantom: self.phantom,
info: self.info,
periph_clock: self.periph_clock,
}
}
/// Enables the peripheral and synchronizes with the bus.
@ -253,7 +261,7 @@ impl<'d, T: Instance> Can<'d, T> {
/// This will wait for 11 consecutive recessive bits (bus idle state).
/// Contrary to enable method from bxcan library, this will not freeze the executor while waiting.
pub async fn enable(&mut self) {
while Registers(T::regs()).enable_non_blocking().is_err() {
while self.info.regs.enable_non_blocking().is_err() {
// SCE interrupt is only generated for entering sleep mode, but not leaving.
// Yield to allow other tasks to execute while can bus is initializing.
embassy_futures::yield_now().await;
@ -263,7 +271,7 @@ impl<'d, T: Instance> Can<'d, T> {
/// Enables or disables the peripheral from automatically wakeup when a SOF is detected on the bus
/// while the peripheral is in sleep mode
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
Registers(T::regs()).set_automatic_wakeup(enabled);
self.info.regs.set_automatic_wakeup(enabled);
}
/// Manually wake the peripheral from sleep mode.
@ -313,12 +321,12 @@ impl<'d, T: Instance> Can<'d, T> {
///
/// FIFO scheduling is disabled by default.
pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) {
Registers(T::regs()).set_tx_fifo_scheduling(enabled)
self.info.regs.set_tx_fifo_scheduling(enabled)
}
/// Checks if FIFO scheduling of outgoing frames is enabled.
pub fn tx_fifo_scheduling_enabled(&self) -> bool {
Registers(T::regs()).tx_fifo_scheduling_enabled()
self.info.regs.tx_fifo_scheduling_enabled()
}
/// Queues the message to be sent.
@ -448,13 +456,13 @@ impl<'d, T: Instance> Can<'d, T> {
}
}
impl<'d, T: FilterOwner> Can<'d, T> {
impl<'d> Can<'d> {
/// Accesses the filter banks owned by this CAN peripheral.
///
/// To modify filters of a slave peripheral, `modify_filters` has to be called on the master
/// peripheral instead.
pub fn modify_filters(&mut self) -> MasterFilters<'_, T> {
unsafe { MasterFilters::new(self.info.regs.0) }
pub fn modify_filters(&mut self) -> MasterFilters<'_> {
unsafe { MasterFilters::new(self.info) }
}
}
@ -819,12 +827,14 @@ impl<'d, const RX_BUF_SIZE: usize> Drop for BufferedCanRx<'d, RX_BUF_SIZE> {
}
}
impl<'d, T: Instance> Drop for Can<'d, T> {
impl Drop for Can<'_> {
fn drop(&mut self) {
// Cannot call `free()` because it moves the instance.
// Manually reset the peripheral.
T::regs().mcr().write(|w| w.set_reset(true));
rcc::disable::<T>();
self.info.regs.0.mcr().write(|w| w.set_reset(true));
self.info.regs.enter_init_mode();
self.info.regs.leave_init_mode();
//rcc::disable::<T>();
}
}
@ -1031,6 +1041,11 @@ pub(crate) struct Info {
rx1_interrupt: crate::interrupt::Interrupt,
sce_interrupt: crate::interrupt::Interrupt,
tx_waker: fn(),
/// The total number of filter banks available to the instance.
///
/// This is usually either 14 or 28, and should be specified in the chip's reference manual or datasheet.
num_filter_banks: u8,
}
trait SealedInstance {
@ -1095,6 +1110,7 @@ foreach_peripheral!(
rx1_interrupt: crate::_generated::peripheral_interrupts::$inst::RX1::IRQ,
sce_interrupt: crate::_generated::peripheral_interrupts::$inst::SCE::IRQ,
tx_waker: crate::_generated::peripheral_interrupts::$inst::TX::pend,
num_filter_banks: peripherals::$inst::NUM_FILTER_BANKS,
};
&INFO
}
@ -1148,6 +1164,11 @@ foreach_peripheral!(
}
}
};
(can, CAN2) => {
unsafe impl FilterOwner for peripherals::CAN2 {
const NUM_FILTER_BANKS: u8 = 0;
}
};
(can, CAN3) => {
unsafe impl FilterOwner for peripherals::CAN3 {
const NUM_FILTER_BANKS: u8 = 14;

View File

@ -11,7 +11,7 @@ use crate::can::frame::{Envelope, Frame, Header};
pub(crate) struct Registers(pub crate::pac::can::Can);
impl Registers {
pub fn enter_init_mode(&mut self) {
pub fn enter_init_mode(&self) {
self.0.mcr().modify(|reg| {
reg.set_sleep(false);
reg.set_inrq(true);
@ -25,7 +25,7 @@ impl Registers {
}
// Leaves initialization mode, enters sleep mode.
pub fn leave_init_mode(&mut self) {
pub fn leave_init_mode(&self) {
self.0.mcr().modify(|reg| {
reg.set_sleep(true);
reg.set_inrq(false);
@ -38,7 +38,7 @@ impl Registers {
}
}
pub fn set_bit_timing(&mut self, bt: crate::can::util::NominalBitTiming) {
pub fn set_bit_timing(&self, bt: crate::can::util::NominalBitTiming) {
let prescaler = u16::from(bt.prescaler) & 0x1FF;
let seg1 = u8::from(bt.seg1);
let seg2 = u8::from(bt.seg2) & 0x7F;
@ -84,7 +84,7 @@ impl Registers {
/// receive the frame. If enabled, [`Interrupt::Wakeup`] will also be triggered by the incoming
/// frame.
#[allow(dead_code)]
pub fn set_automatic_wakeup(&mut self, enabled: bool) {
pub fn set_automatic_wakeup(&self, enabled: bool) {
self.0.mcr().modify(|reg| reg.set_awum(enabled));
}
@ -96,7 +96,7 @@ impl Registers {
/// If this returns [`WouldBlock`][nb::Error::WouldBlock], the peripheral will enable itself
/// in the background. The peripheral is enabled and ready to use when this method returns
/// successfully.
pub fn enable_non_blocking(&mut self) -> nb::Result<(), Infallible> {
pub fn enable_non_blocking(&self) -> nb::Result<(), Infallible> {
let msr = self.0.msr().read();
if msr.slak() {
self.0.mcr().modify(|reg| {
@ -186,7 +186,7 @@ impl Registers {
/// If this is enabled, mailboxes are scheduled based on the time when the transmit request bit of the mailbox was set.
///
/// If this is disabled, mailboxes are scheduled based on the priority of the frame in the mailbox.
pub fn set_tx_fifo_scheduling(&mut self, enabled: bool) {
pub fn set_tx_fifo_scheduling(&self, enabled: bool) {
self.0.mcr().modify(|w| w.set_txfp(enabled))
}

View File

@ -18,10 +18,6 @@ use {defmt_rtt as _, panic_probe as _};
mod can_common;
use can_common::*;
type Can<'d> = embassy_stm32::can::Can<'d, embassy_stm32::peripherals::CAN1>;
type CanTx<'d> = embassy_stm32::can::CanTx<'d>;
type CanRx<'d> = embassy_stm32::can::CanRx<'d>;
bind_interrupts!(struct Irqs {
CAN1_RX0 => Rx0InterruptHandler<CAN1>;
CAN1_RX1 => Rx1InterruptHandler<CAN1>;
@ -50,7 +46,7 @@ async fn main(_spawner: Spawner) {
let rx_pin = Input::new(&mut rx, Pull::Up);
core::mem::forget(rx_pin);
let mut can = Can::new(can, rx, tx, Irqs);
let mut can = embassy_stm32::can::Can::new(can, rx, tx, Irqs);
info!("Configuring can...");

View File

@ -8,7 +8,7 @@ pub struct TestOptions {
pub max_buffered: u8,
}
pub async fn run_can_tests<'d>(can: &mut crate::Can<'d>, options: &TestOptions) {
pub async fn run_can_tests<'d>(can: &mut can::Can<'d>, options: &TestOptions) {
//pub async fn run_can_tests<'d, T: can::Instance>(can: &mut can::Can<'d, T>, options: &TestOptions) {
let mut i: u8 = 0;
loop {
@ -80,7 +80,7 @@ pub async fn run_can_tests<'d>(can: &mut crate::Can<'d>, options: &TestOptions)
}
}
pub async fn run_split_can_tests<'d>(tx: &mut crate::CanTx<'d>, rx: &mut crate::CanRx<'d>, options: &TestOptions) {
pub async fn run_split_can_tests<'d>(tx: &mut can::CanTx<'d>, rx: &mut can::CanRx<'d>, options: &TestOptions) {
for i in 0..options.max_buffered {
// Try filling up the RX FIFO0 buffers
//let tx_frame = if 0 != (i & 0x01) {

View File

@ -15,10 +15,6 @@ use {defmt_rtt as _, panic_probe as _};
mod can_common;
use can_common::*;
type Can<'d> = can::Can<'d>;
type CanTx<'d> = can::CanTx<'d>;
type CanRx<'d> = can::CanRx<'d>;
bind_interrupts!(struct Irqs2 {
FDCAN2_IT0 => can::IT0InterruptHandler<FDCAN2>;
FDCAN2_IT1 => can::IT1InterruptHandler<FDCAN2>;