| 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 | |