embassy_stm32/usb/
mod.rs

1//! Universal Serial Bus (USB)
2
3#[cfg_attr(usb, path = "usb.rs")]
4#[cfg_attr(otg, path = "otg.rs")]
5mod _version;
6pub use _version::*;
7
8use crate::interrupt::typelevel::Interrupt;
9use crate::rcc;
10
11/// clock, power initialization stuff that's common for USB and OTG.
12fn common_init<T: Instance>() {
13    // Check the USB clock is enabled and running at exactly 48 MHz.
14    // frequency() will panic if not enabled
15    let freq = T::frequency();
16
17    // On the H7RS, the USBPHYC embeds a PLL accepting one of the input frequencies listed below and providing 48MHz to OTG_FS and 60MHz to OTG_HS internally
18    #[cfg(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs)))]
19    if ![16_000_000, 19_200_000, 20_000_000, 24_000_000, 26_000_000, 32_000_000].contains(&freq.0) {
20        panic!(
21            "USB clock should be one of 16, 19.2, 20, 24, 26, 32Mhz but is {} Hz. Please double-check your RCC settings.",
22            freq.0
23        )
24    }
25    // Check frequency is within the 0.25% tolerance allowed by the spec.
26    // Clock might not be exact 48Mhz due to rounding errors in PLL calculation, or if the user
27    // has tight clock restrictions due to something else (like audio).
28    #[cfg(not(any(stm32h7rs, all(stm32u5, peri_usb_otg_hs))))]
29    if freq.0.abs_diff(48_000_000) > 120_000 {
30        panic!(
31            "USB clock should be 48Mhz but is {} Hz. Please double-check your RCC settings.",
32            freq.0
33        )
34    }
35
36    #[cfg(any(stm32l4, stm32l5, stm32wb, stm32u0))]
37    critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
38
39    #[cfg(pwr_h5)]
40    critical_section::with(|_| crate::pac::PWR.usbscr().modify(|w| w.set_usb33sv(true)));
41
42    #[cfg(stm32h7)]
43    {
44        // If true, VDD33USB is generated by internal regulator from VDD50USB
45        // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
46        // TODO: unhardcode
47        let internal_regulator = false;
48
49        // Enable USB power
50        critical_section::with(|_| {
51            crate::pac::PWR.cr3().modify(|w| {
52                w.set_usb33den(true);
53                w.set_usbregen(internal_regulator);
54            })
55        });
56
57        // Wait for USB power to stabilize
58        while !crate::pac::PWR.cr3().read().usb33rdy() {}
59    }
60
61    #[cfg(stm32h7rs)]
62    {
63        // If true, VDD33USB is generated by internal regulator from VDD50USB
64        // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
65        // TODO: unhardcode
66        let internal_regulator = false;
67
68        // Enable USB power
69        critical_section::with(|_| {
70            crate::pac::PWR.csr2().modify(|w| {
71                w.set_usbregen(internal_regulator);
72                w.set_usb33den(true);
73                w.set_usbhsregen(true);
74            })
75        });
76
77        // Wait for USB power to stabilize
78        while !crate::pac::PWR.csr2().read().usb33rdy() {}
79    }
80
81    #[cfg(stm32u5)]
82    {
83        // Enable USB power
84        critical_section::with(|_| {
85            crate::pac::PWR.svmcr().modify(|w| {
86                w.set_usv(true);
87                w.set_uvmen(true);
88            })
89        });
90
91        // Wait for USB power to stabilize
92        while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
93
94        // Now set up transceiver power if it's a OTG-HS
95        #[cfg(peri_usb_otg_hs)]
96        {
97            crate::pac::PWR.vosr().modify(|w| {
98                w.set_usbpwren(true);
99                w.set_usbboosten(true);
100            });
101            while !crate::pac::PWR.vosr().read().usbboostrdy() {}
102        }
103    }
104
105    T::Interrupt::unpend();
106    unsafe { T::Interrupt::enable() };
107
108    rcc::enable_and_reset::<T>();
109}