diff --git a/boards/atsame54_xpro/src/devices.rs b/boards/atsame54_xpro/src/devices.rs index a5a3c760df0f..2afe08ce1117 100644 --- a/boards/atsame54_xpro/src/devices.rs +++ b/boards/atsame54_xpro/src/devices.rs @@ -372,5 +372,6 @@ pub fn usb_allocator( let usb_gclk = clocks.get_gclk(Genselect::Gclk2).unwrap(); let usb_clock = &clocks.usb(&usb_gclk).unwrap(); let (dm, dp) = (dm.into(), dp.into()); - UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb)) + /// Safety - V1 clocking API forces a 48Mhz USB clock + UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb).unwrap()) } diff --git a/boards/feather_m4/src/lib.rs b/boards/feather_m4/src/lib.rs index 0aec0a57b4a4..526387389de9 100644 --- a/boards/feather_m4/src/lib.rs +++ b/boards/feather_m4/src/lib.rs @@ -272,5 +272,6 @@ pub fn usb_allocator( let usb_gclk = clocks.get_gclk(Genselect::Gclk2).unwrap(); let usb_clock = &clocks.usb(&usb_gclk).unwrap(); let (dm, dp) = (dm.into(), dp.into()); - UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb)) + /// Safety - V1 clocking API forces a 48Mhz USB clock + UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb).unwrap()) } diff --git a/boards/metro_m4/src/lib.rs b/boards/metro_m4/src/lib.rs index 7e972ef621ab..522d0fc21f70 100644 --- a/boards/metro_m4/src/lib.rs +++ b/boards/metro_m4/src/lib.rs @@ -365,5 +365,6 @@ pub fn usb_allocator( let usb_gclk = clocks.get_gclk(Genselect::Gclk2).unwrap(); let usb_clock = &clocks.usb(&usb_gclk).unwrap(); let (dm, dp) = (dm.into(), dp.into()); - UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb)) + /// Safety - V1 clocking API forces a 48Mhz USB clock + UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb).unwrap()) } diff --git a/boards/pygamer/src/pins.rs b/boards/pygamer/src/pins.rs index 01134236e691..16b356b1d424 100644 --- a/boards/pygamer/src/pins.rs +++ b/boards/pygamer/src/pins.rs @@ -813,7 +813,8 @@ impl USB { let usb_gclk = clocks.get_gclk(Genselect::Gclk2).unwrap(); let usb_clock = &clocks.usb(&usb_gclk).unwrap(); let (dm, dp): (UsbDm, UsbDp) = (self.dm.into(), self.dp.into()); - UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb)) + /// Safety - V1 clocking API forces a 48Mhz USB clock + UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb).unwrap()) } } diff --git a/hal/src/peripherals/usb/d11/bus.rs b/hal/src/peripherals/usb/d11/bus.rs index 45315e94bbd3..80392a87a792 100644 --- a/hal/src/peripherals/usb/d11/bus.rs +++ b/hal/src/peripherals/usb/d11/bus.rs @@ -490,6 +490,9 @@ impl UsbBus { dp_pad: impl AnyPin, _usb: Usb, ) -> Self { + // Note for Clock V2 implementation - Check that USB + // Freq is 48Mhz and error out if it is not - Check + // the D5X implementation pm.apbbmask().modify(|_, w| w.usb_().set_bit()); let desc = RefCell::new(Descriptors::new()); diff --git a/hal/src/peripherals/usb/d5x/bus.rs b/hal/src/peripherals/usb/d5x/bus.rs index 1441ff780dc2..1856853a2080 100644 --- a/hal/src/peripherals/usb/d5x/bus.rs +++ b/hal/src/peripherals/usb/d5x/bus.rs @@ -524,13 +524,44 @@ impl Inner { } } +#[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum UsbBusErr { + /// USB clock freq is not valid for a stable connection + InvalidClockFreq, +} + impl UsbBus { + /// Create a new USB Bus, checking the clock frequency of the USB clock for + /// a stable USB link to most hosts. The `clock` freq must be 48Mhz, otherwise + /// [`UsbBusErr::InvalidClockFreq`] will be returned pub fn new( - _clock: &clock::UsbClock, + clock: &clock::UsbClock, mclk: &mut Mclk, dm_pad: impl AnyPin, dp_pad: impl AnyPin, _usb: Usb, + ) -> Result { + if clock.freq().to_Hz() != 48_000_000 { + Err(UsbBusErr::InvalidClockFreq) + } else { + let res = unsafe { Self::new_unchecked(clock, mclk, dm_pad, dp_pad) }; + Ok(res) + } + } + + /// Creates a new USB Bus, but does NOT perform the USB clock frequency check. + /// + /// SAFETY: For a SAMx to PC connection, the USB clock must be 48Mhz for stability. + /// This function allows you to bypass this check however if you intend to connect multiple SAM chips + /// together with faster running USB clocks for a boost in transfer rate. + /// + /// Consult the datasheet for GCLK_USB absolute maximums + pub unsafe fn new_unchecked( + _clock: &clock::UsbClock, + mclk: &mut Mclk, + dm_pad: impl AnyPin, + dp_pad: impl AnyPin, ) -> Self { mclk.ahbmask().modify(|_, w| w.usb_().set_bit()); mclk.apbbmask().modify(|_, w| w.usb_().set_bit());