1use core::marker::PhantomData;
2
3use embassy_hal_internal::{into_ref, Peripheral};
4use embassy_usb_driver::{EndpointAddress, EndpointAllocError, EndpointType, Event, Unsupported};
5use embassy_usb_synopsys_otg::otg_v1::vals::Dspd;
6use embassy_usb_synopsys_otg::otg_v1::Otg;
7pub use embassy_usb_synopsys_otg::Config;
8use embassy_usb_synopsys_otg::{
9 on_interrupt as on_interrupt_impl, Bus as OtgBus, ControlPipe, Driver as OtgDriver, Endpoint, In, OtgInstance, Out,
10 PhyType, State,
11};
12
13use crate::gpio::{AfType, OutputType, Speed};
14use crate::interrupt;
15use crate::interrupt::typelevel::Interrupt;
16use crate::rcc::{self, RccPeripheral};
17
18const MAX_EP_COUNT: usize = 9;
19
20pub struct InterruptHandler<T: Instance> {
22 _phantom: PhantomData<T>,
23}
24
25impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
26 unsafe fn on_interrupt() {
27 let r = T::regs();
28 let state = T::state();
29 on_interrupt_impl(r, state, T::ENDPOINT_COUNT);
30 }
31}
32
33macro_rules! config_ulpi_pins {
34 ($($pin:ident),*) => {
35 into_ref!($($pin),*);
36 critical_section::with(|_| {
37 $(
38 $pin.set_as_af($pin.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
39 )*
40 })
41 };
42}
43
44const RX_FIFO_EXTRA_SIZE_WORDS: u16 = 30;
49
50pub struct Driver<'d, T: Instance> {
52 phantom: PhantomData<&'d mut T>,
53 inner: OtgDriver<'d, MAX_EP_COUNT>,
54}
55
56impl<'d, T: Instance> Driver<'d, T> {
57 pub fn new_fs(
65 _peri: impl Peripheral<P = T> + 'd,
66 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
67 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
68 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
69 ep_out_buffer: &'d mut [u8],
70 config: Config,
71 ) -> Self {
72 into_ref!(dp, dm);
73
74 dp.set_as_af(dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
75 dm.set_as_af(dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
76
77 let regs = T::regs();
78
79 let instance = OtgInstance {
80 regs,
81 state: T::state(),
82 fifo_depth_words: T::FIFO_DEPTH_WORDS,
83 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
84 endpoint_count: T::ENDPOINT_COUNT,
85 phy_type: PhyType::InternalFullSpeed,
86 calculate_trdt_fn: calculate_trdt::<T>,
87 };
88
89 Self {
90 inner: OtgDriver::new(ep_out_buffer, instance, config),
91 phantom: PhantomData,
92 }
93 }
94
95 pub fn new_hs(
103 _peri: impl Peripheral<P = T> + 'd,
104 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
105 _dp: impl Peripheral<P = impl DpPin<T>> + 'd,
106 _dm: impl Peripheral<P = impl DmPin<T>> + 'd,
107 ep_out_buffer: &'d mut [u8],
108 config: Config,
109 ) -> Self {
110 #[cfg(not(all(stm32u5, peri_usb_otg_hs)))]
112 {
113 into_ref!(_dp, _dm);
114 _dp.set_as_af(_dp.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
115 _dm.set_as_af(_dm.af_num(), AfType::output(OutputType::PushPull, Speed::VeryHigh));
116 }
117
118 let instance = OtgInstance {
119 regs: T::regs(),
120 state: T::state(),
121 fifo_depth_words: T::FIFO_DEPTH_WORDS,
122 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
123 endpoint_count: T::ENDPOINT_COUNT,
124 phy_type: PhyType::InternalHighSpeed,
125 calculate_trdt_fn: calculate_trdt::<T>,
126 };
127
128 Self {
129 inner: OtgDriver::new(ep_out_buffer, instance, config),
130 phantom: PhantomData,
131 }
132 }
133
134 pub fn new_fs_ulpi(
142 _peri: impl Peripheral<P = T> + 'd,
143 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
144 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd,
145 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd,
146 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd,
147 ulpi_stp: impl Peripheral<P = impl UlpiStpPin<T>> + 'd,
148 ulpi_d0: impl Peripheral<P = impl UlpiD0Pin<T>> + 'd,
149 ulpi_d1: impl Peripheral<P = impl UlpiD1Pin<T>> + 'd,
150 ulpi_d2: impl Peripheral<P = impl UlpiD2Pin<T>> + 'd,
151 ulpi_d3: impl Peripheral<P = impl UlpiD3Pin<T>> + 'd,
152 ulpi_d4: impl Peripheral<P = impl UlpiD4Pin<T>> + 'd,
153 ulpi_d5: impl Peripheral<P = impl UlpiD5Pin<T>> + 'd,
154 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
155 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
156 ep_out_buffer: &'d mut [u8],
157 config: Config,
158 ) -> Self {
159 config_ulpi_pins!(
160 ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6,
161 ulpi_d7
162 );
163
164 let instance = OtgInstance {
165 regs: T::regs(),
166 state: T::state(),
167 fifo_depth_words: T::FIFO_DEPTH_WORDS,
168 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
169 endpoint_count: T::ENDPOINT_COUNT,
170 phy_type: PhyType::ExternalFullSpeed,
171 calculate_trdt_fn: calculate_trdt::<T>,
172 };
173
174 Self {
175 inner: OtgDriver::new(ep_out_buffer, instance, config),
176 phantom: PhantomData,
177 }
178 }
179
180 pub fn new_hs_ulpi(
188 _peri: impl Peripheral<P = T> + 'd,
189 _irq: impl interrupt::typelevel::Binding<T::Interrupt, InterruptHandler<T>> + 'd,
190 ulpi_clk: impl Peripheral<P = impl UlpiClkPin<T>> + 'd,
191 ulpi_dir: impl Peripheral<P = impl UlpiDirPin<T>> + 'd,
192 ulpi_nxt: impl Peripheral<P = impl UlpiNxtPin<T>> + 'd,
193 ulpi_stp: impl Peripheral<P = impl UlpiStpPin<T>> + 'd,
194 ulpi_d0: impl Peripheral<P = impl UlpiD0Pin<T>> + 'd,
195 ulpi_d1: impl Peripheral<P = impl UlpiD1Pin<T>> + 'd,
196 ulpi_d2: impl Peripheral<P = impl UlpiD2Pin<T>> + 'd,
197 ulpi_d3: impl Peripheral<P = impl UlpiD3Pin<T>> + 'd,
198 ulpi_d4: impl Peripheral<P = impl UlpiD4Pin<T>> + 'd,
199 ulpi_d5: impl Peripheral<P = impl UlpiD5Pin<T>> + 'd,
200 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
201 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
202 ep_out_buffer: &'d mut [u8],
203 config: Config,
204 ) -> Self {
205 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
206
207 config_ulpi_pins!(
208 ulpi_clk, ulpi_dir, ulpi_nxt, ulpi_stp, ulpi_d0, ulpi_d1, ulpi_d2, ulpi_d3, ulpi_d4, ulpi_d5, ulpi_d6,
209 ulpi_d7
210 );
211
212 let instance = OtgInstance {
213 regs: T::regs(),
214 state: T::state(),
215 fifo_depth_words: T::FIFO_DEPTH_WORDS,
216 extra_rx_fifo_words: RX_FIFO_EXTRA_SIZE_WORDS,
217 endpoint_count: T::ENDPOINT_COUNT,
218 phy_type: PhyType::ExternalHighSpeed,
219 calculate_trdt_fn: calculate_trdt::<T>,
220 };
221
222 Self {
223 inner: OtgDriver::new(ep_out_buffer, instance, config),
224 phantom: PhantomData,
225 }
226 }
227}
228
229impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
230 type EndpointOut = Endpoint<'d, Out>;
231 type EndpointIn = Endpoint<'d, In>;
232 type ControlPipe = ControlPipe<'d>;
233 type Bus = Bus<'d, T>;
234
235 fn alloc_endpoint_in(
236 &mut self,
237 ep_type: EndpointType,
238 max_packet_size: u16,
239 interval_ms: u8,
240 ) -> Result<Self::EndpointIn, EndpointAllocError> {
241 self.inner.alloc_endpoint_in(ep_type, max_packet_size, interval_ms)
242 }
243
244 fn alloc_endpoint_out(
245 &mut self,
246 ep_type: EndpointType,
247 max_packet_size: u16,
248 interval_ms: u8,
249 ) -> Result<Self::EndpointOut, EndpointAllocError> {
250 self.inner.alloc_endpoint_out(ep_type, max_packet_size, interval_ms)
251 }
252
253 fn start(self, control_max_packet_size: u16) -> (Self::Bus, Self::ControlPipe) {
254 let (bus, cp) = self.inner.start(control_max_packet_size);
255
256 (
257 Bus {
258 phantom: PhantomData,
259 inner: bus,
260 inited: false,
261 },
262 cp,
263 )
264 }
265}
266
267pub struct Bus<'d, T: Instance> {
269 phantom: PhantomData<&'d mut T>,
270 inner: OtgBus<'d, MAX_EP_COUNT>,
271 inited: bool,
272}
273
274impl<'d, T: Instance> Bus<'d, T> {
275 fn init(&mut self) {
276 super::common_init::<T>();
277
278 let phy_type = self.inner.phy_type();
280 let _ulpien = !phy_type.internal();
281
282 #[cfg(any(stm32f2, stm32f4, stm32f7))]
283 if T::HIGH_SPEED {
284 critical_section::with(|_| {
285 let rcc = crate::pac::RCC;
286 rcc.ahb1enr().modify(|w| w.set_usb_otg_hsulpien(_ulpien));
287 rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hsulpilpen(_ulpien));
288 });
289 }
290
291 #[cfg(stm32h7)]
292 critical_section::with(|_| {
293 let rcc = crate::pac::RCC;
294 if T::HIGH_SPEED {
295 rcc.ahb1enr().modify(|w| w.set_usb_otg_hs_ulpien(_ulpien));
296 rcc.ahb1lpenr().modify(|w| w.set_usb_otg_hs_ulpilpen(_ulpien));
297 } else {
298 rcc.ahb1enr().modify(|w| w.set_usb_otg_fs_ulpien(_ulpien));
299 rcc.ahb1lpenr().modify(|w| w.set_usb_otg_fs_ulpilpen(_ulpien));
300 }
301 });
302
303 #[cfg(stm32h7rs)]
304 critical_section::with(|_| {
305 let rcc = crate::pac::RCC;
306 rcc.ahb1enr().modify(|w| {
307 w.set_usbphycen(true);
308 w.set_usb_otg_hsen(true);
309 });
310 rcc.ahb1lpenr().modify(|w| {
311 w.set_usbphyclpen(true);
312 w.set_usb_otg_hslpen(true);
313 });
314 });
315
316 #[cfg(all(stm32u5, peri_usb_otg_hs))]
317 {
318 crate::pac::SYSCFG.otghsphycr().modify(|w| {
319 w.set_en(true);
320 });
321
322 critical_section::with(|_| {
323 crate::pac::RCC.ahb2enr1().modify(|w| {
324 w.set_usb_otg_hsen(true);
325 w.set_usb_otg_hs_phyen(true);
326 });
327 });
328 }
329
330 let r = T::regs();
331 let core_id = r.cid().read().0;
332 trace!("Core id {:08x}", core_id);
333
334 while !r.grstctl().read().ahbidl() {}
336
337 self.inner.configure_as_device();
339
340 match core_id {
342 0x0000_1200 | 0x0000_1100 => self.inner.config_v1(),
343 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => self.inner.config_v2v3(),
344 0x0000_5000 => self.inner.config_v5(),
345 _ => unimplemented!("Unknown USB core id {:X}", core_id),
346 }
347 }
348
349 fn disable(&mut self) {
350 T::Interrupt::disable();
351
352 rcc::disable::<T>();
353 self.inited = false;
354
355 #[cfg(stm32l4)]
356 crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
357 }
359}
360
361impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
362 async fn poll(&mut self) -> Event {
363 if !self.inited {
364 self.init();
365 self.inited = true;
366 }
367
368 self.inner.poll().await
369 }
370
371 fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
372 self.inner.endpoint_set_stalled(ep_addr, stalled)
373 }
374
375 fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
376 self.inner.endpoint_is_stalled(ep_addr)
377 }
378
379 fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
380 self.inner.endpoint_set_enabled(ep_addr, enabled)
381 }
382
383 async fn enable(&mut self) {
384 self.inner.enable().await
385 }
386
387 async fn disable(&mut self) {
388 self.inner.disable().await
390 }
391
392 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
393 self.inner.remote_wakeup().await
394 }
395}
396
397impl<'d, T: Instance> Drop for Bus<'d, T> {
398 fn drop(&mut self) {
399 Bus::disable(self);
400 }
401}
402
403trait SealedInstance {
404 const HIGH_SPEED: bool;
405 const FIFO_DEPTH_WORDS: u16;
406 const ENDPOINT_COUNT: usize;
407
408 fn regs() -> Otg;
409 fn state() -> &'static State<{ MAX_EP_COUNT }>;
410}
411
412#[allow(private_bounds)]
414pub trait Instance: SealedInstance + RccPeripheral + 'static {
415 type Interrupt: interrupt::typelevel::Interrupt;
417}
418
419pin_trait!(DpPin, Instance);
421pin_trait!(DmPin, Instance);
422
423pin_trait!(UlpiClkPin, Instance);
425pin_trait!(UlpiDirPin, Instance);
426pin_trait!(UlpiNxtPin, Instance);
427pin_trait!(UlpiStpPin, Instance);
428pin_trait!(UlpiD0Pin, Instance);
429pin_trait!(UlpiD1Pin, Instance);
430pin_trait!(UlpiD2Pin, Instance);
431pin_trait!(UlpiD3Pin, Instance);
432pin_trait!(UlpiD4Pin, Instance);
433pin_trait!(UlpiD5Pin, Instance);
434pin_trait!(UlpiD6Pin, Instance);
435pin_trait!(UlpiD7Pin, Instance);
436
437foreach_interrupt!(
438 (USB_OTG_FS, otg, $block:ident, GLOBAL, $irq:ident) => {
439 impl SealedInstance for crate::peripherals::USB_OTG_FS {
440 const HIGH_SPEED: bool = false;
441
442 cfg_if::cfg_if! {
443 if #[cfg(stm32f1)] {
444 const FIFO_DEPTH_WORDS: u16 = 128;
445 const ENDPOINT_COUNT: usize = 8;
446 } else if #[cfg(any(
447 stm32f2,
448 stm32f401,
449 stm32f405,
450 stm32f407,
451 stm32f411,
452 stm32f415,
453 stm32f417,
454 stm32f427,
455 stm32f429,
456 stm32f437,
457 stm32f439,
458 ))] {
459 const FIFO_DEPTH_WORDS: u16 = 320;
460 const ENDPOINT_COUNT: usize = 4;
461 } else if #[cfg(any(
462 stm32f412,
463 stm32f413,
464 stm32f423,
465 stm32f446,
466 stm32f469,
467 stm32f479,
468 stm32f7,
469 stm32l4,
470 stm32u5,
471 ))] {
472 const FIFO_DEPTH_WORDS: u16 = 320;
473 const ENDPOINT_COUNT: usize = 6;
474 } else if #[cfg(stm32g0x1)] {
475 const FIFO_DEPTH_WORDS: u16 = 512;
476 const ENDPOINT_COUNT: usize = 8;
477 } else if #[cfg(any(stm32h7, stm32h7rs))] {
478 const FIFO_DEPTH_WORDS: u16 = 1024;
479 const ENDPOINT_COUNT: usize = 9;
480 } else if #[cfg(stm32u5)] {
481 const FIFO_DEPTH_WORDS: u16 = 320;
482 const ENDPOINT_COUNT: usize = 6;
483 } else {
484 compile_error!("USB_OTG_FS peripheral is not supported by this chip.");
485 }
486 }
487
488 fn regs() -> Otg {
489 unsafe { Otg::from_ptr(crate::pac::USB_OTG_FS.as_ptr()) }
490 }
491
492 fn state() -> &'static State<MAX_EP_COUNT> {
493 static STATE: State<MAX_EP_COUNT> = State::new();
494 &STATE
495 }
496 }
497
498 impl Instance for crate::peripherals::USB_OTG_FS {
499 type Interrupt = crate::interrupt::typelevel::$irq;
500 }
501 };
502
503 (USB_OTG_HS, otg, $block:ident, GLOBAL, $irq:ident) => {
504 impl SealedInstance for crate::peripherals::USB_OTG_HS {
505 const HIGH_SPEED: bool = true;
506
507 cfg_if::cfg_if! {
508 if #[cfg(any(
509 stm32f2,
510 stm32f405,
511 stm32f407,
512 stm32f415,
513 stm32f417,
514 stm32f427,
515 stm32f429,
516 stm32f437,
517 stm32f439,
518 ))] {
519 const FIFO_DEPTH_WORDS: u16 = 1024;
520 const ENDPOINT_COUNT: usize = 6;
521 } else if #[cfg(any(
522 stm32f446,
523 stm32f469,
524 stm32f479,
525 stm32f7,
526 stm32h7, stm32h7rs,
527 ))] {
528 const FIFO_DEPTH_WORDS: u16 = 1024;
529 const ENDPOINT_COUNT: usize = 9;
530 } else if #[cfg(stm32u5)] {
531 const FIFO_DEPTH_WORDS: u16 = 1024;
532 const ENDPOINT_COUNT: usize = 9;
533 } else {
534 compile_error!("USB_OTG_HS peripheral is not supported by this chip.");
535 }
536 }
537
538 fn regs() -> Otg {
539 unsafe { Otg::from_ptr(crate::pac::USB_OTG_HS.as_ptr()) }
541 }
542
543 fn state() -> &'static State<MAX_EP_COUNT> {
544 static STATE: State<MAX_EP_COUNT> = State::new();
545 &STATE
546 }
547 }
548
549 impl Instance for crate::peripherals::USB_OTG_HS {
550 type Interrupt = crate::interrupt::typelevel::$irq;
551 }
552 };
553);
554
555fn calculate_trdt<T: Instance>(speed: Dspd) -> u8 {
556 let ahb_freq = T::frequency().0;
557 match speed {
558 Dspd::HIGH_SPEED => {
559 if ahb_freq >= 30_000_000 || cfg!(stm32h7rs) {
561 0x9
562 } else {
563 panic!("AHB frequency is too low")
564 }
565 }
566 Dspd::FULL_SPEED_EXTERNAL | Dspd::FULL_SPEED_INTERNAL => {
567 match ahb_freq {
569 0..=14_199_999 => panic!("AHB frequency is too low"),
570 14_200_000..=14_999_999 => 0xF,
571 15_000_000..=15_999_999 => 0xE,
572 16_000_000..=17_199_999 => 0xD,
573 17_200_000..=18_499_999 => 0xC,
574 18_500_000..=19_999_999 => 0xB,
575 20_000_000..=21_799_999 => 0xA,
576 21_800_000..=23_999_999 => 0x9,
577 24_000_000..=27_499_999 => 0x8,
578 27_500_000..=31_999_999 => 0x7, 32_000_000..=u32::MAX => 0x6,
580 }
581 }
582 _ => unimplemented!(),
583 }
584}