1use core::marker::PhantomData;
8
9#[cfg(feature = "embassy-usb-driver-impl")]
10use embassy_usb_driver as driver;
11#[cfg(feature = "embassy-usb-driver-impl")]
12use embassy_usb_driver::{EndpointType, EndpointAddress};
13#[cfg(feature = "usb-device-impl")]
14pub use musb::UsbdBus;
15#[cfg(feature = "embassy-usb-driver-impl")]
16use musb::{Bus, ControlPipe, Endpoint, In, MusbDriver, Out};
17
18use musb::UsbInstance;
19
20use crate::interrupt::typelevel::Interrupt;
21use crate::rcc::{self, RccPeripheral};
22use crate::{interrupt, Peripheral};
23
24pub struct InterruptHandler<T: Instance> {
26 _phantom: PhantomData<T>,
27}
28
29impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
30 unsafe fn on_interrupt() {
31 musb::on_interrupt::<UsbInstance>();
32 }
33}
34
35fn init<T: Instance>() {
36 let freq = T::frequency();
37 if freq.0 != 48_000_000 {
38 panic!("USB clock (PLL) must be 48MHz");
39 }
40
41 T::Interrupt::unpend();
42 unsafe { T::Interrupt::enable() };
43 rcc::enable_and_reset::<T>();
44
45 #[cfg(feature = "time")]
46 embassy_time::block_for(embassy_time::Duration::from_millis(100));
47 #[cfg(not(feature = "time"))]
48 cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.to_hertz().unwrap().0 / 10);
49}
50
51#[cfg(feature = "embassy-usb-driver-impl")]
52pub struct Driver<'d, T: Instance> {
54 phantom: PhantomData<&'d mut T>,
55 inner: MusbDriver<'d, UsbInstance>,
56}
57
58#[cfg(feature = "embassy-usb-driver-impl")]
59impl<'d, T: Instance> Driver<'d, T> {
60 pub fn new(
62 _usb: impl Peripheral<P = T> + 'd,
63 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
64 _dp: impl Peripheral<P = impl DpPin<T>> + 'd,
65 _dm: impl Peripheral<P = impl DmPin<T>> + 'd,
66 ) -> Self {
67 init::<T>();
68
69 Self {
70 inner: MusbDriver::new(),
71 phantom: PhantomData,
72 }
73 }
74}
75
76#[cfg(feature = "embassy-usb-driver-impl")]
77impl<'d, T: Instance> driver::Driver<'d> for Driver<'d, T> {
78 type EndpointOut = Endpoint<'d, UsbInstance, Out>;
79 type EndpointIn = Endpoint<'d, UsbInstance, In>;
80 type ControlPipe = ControlPipe<'d, UsbInstance>;
81 type Bus = Bus<'d, UsbInstance>;
82
83 fn alloc_endpoint_in(
84 &mut self,
85 ep_type: EndpointType,
86 ep_addr: Option<EndpointAddress>,
87 max_packet_size: u16,
88 interval_ms: u8,
89 ) -> Result<Self::EndpointIn, driver::EndpointAllocError> {
90 self.inner
91 .alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
92 }
93
94 fn alloc_endpoint_out(
95 &mut self,
96 ep_type: EndpointType,
97 ep_addr: Option<EndpointAddress>,
98 max_packet_size: u16,
99 interval_ms: u8,
100 ) -> Result<Self::EndpointOut, driver::EndpointAllocError> {
101 self.inner
102 .alloc_endpoint(ep_type, ep_addr, max_packet_size, interval_ms)
103 }
104
105 fn start(
106 self,
107 control_max_packet_size: u16,
108 ) -> (Bus<'d, UsbInstance>, ControlPipe<'d, UsbInstance>) {
109 self.inner.start(control_max_packet_size)
110 }
111}
112
113#[cfg(feature = "usb-device-impl")]
114pub fn new_bus<'d, T: Instance>(
115 _usb: impl Peripheral<P = T> + 'd,
116 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
117 _dp: impl Peripheral<P = impl DpPin<T>> + 'd,
118 _dm: impl Peripheral<P = impl DmPin<T>> + 'd,
119) -> UsbdBus<UsbInstance> {
120 init::<T>();
121
122 UsbdBus::new()
123}
124
125trait SealedInstance {}
126
127#[allow(private_bounds)]
129pub trait Instance: SealedInstance + RccPeripheral + 'static {
130 type Interrupt: interrupt::typelevel::Interrupt;
132}
133
134pin_trait!(DpPin, Instance);
136pin_trait!(DmPin, Instance);
137
138foreach_interrupt!(
139 ($inst:ident, usb, $block:ident, LP, $irq:ident) => {
140 impl SealedInstance for crate::peripherals::$inst {}
141
142 impl Instance for crate::peripherals::$inst {
143 type Interrupt = crate::interrupt::typelevel::$irq;
144 }
145 };
146);