1 | //! Universal Serial Bus (USB) |
2 | |
3 | #[cfg_attr (usb, path = "usb.rs" )] |
4 | #[cfg_attr (otg, path = "otg.rs" )] |
5 | mod _version; |
6 | pub use _version::*; |
7 | |
8 | use crate::interrupt::typelevel::Interrupt; |
9 | use crate::rcc; |
10 | |
11 | /// clock, power initialization stuff that's common for USB and OTG. |
12 | fn 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 | } |
110 | |