parent
							
								
									a2d1e7f02c
								
							
						
					
					
						commit
						219ef5b37a
					
				| @ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering}; | |||||||
| use embassy_hal_common::{into_ref, Peripheral}; | use embassy_hal_common::{into_ref, Peripheral}; | ||||||
| use embassy_sync::waitqueue::AtomicWaker; | use embassy_sync::waitqueue::AtomicWaker; | ||||||
| use embassy_usb_driver::{ | use embassy_usb_driver::{ | ||||||
|     self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, |     self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, | ||||||
|     EndpointType, Event, Unsupported, |     EndpointOut, EndpointType, Event, Unsupported, | ||||||
| }; | }; | ||||||
| use futures::future::poll_fn; | use futures::future::poll_fn; | ||||||
| 
 | 
 | ||||||
| @ -31,7 +31,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl | |||||||
|         let state = T::state(); |         let state = T::state(); | ||||||
| 
 | 
 | ||||||
|         let ints = r.gintsts().read(); |         let ints = r.gintsts().read(); | ||||||
|         if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { |         if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() { | ||||||
|             // Mask interrupts and notify `Bus` to process them
 |             // Mask interrupts and notify `Bus` to process them
 | ||||||
|             r.gintmsk().write(|_| {}); |             r.gintmsk().write(|_| {}); | ||||||
|             T::state().bus_waker.wake(); |             T::state().bus_waker.wake(); | ||||||
| @ -256,7 +256,34 @@ struct EndpointData { | |||||||
|     fifo_size_words: u16, |     fifo_size_words: u16, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[non_exhaustive] | ||||||
|  | #[derive(Clone, Copy, PartialEq, Eq, Debug)] | ||||||
|  | pub struct Config { | ||||||
|  |     /// Enable VBUS detection.
 | ||||||
|  |     ///
 | ||||||
|  |     /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
 | ||||||
|  |     /// This is done by checkihg whether there is 5V on the VBUS pin or not.
 | ||||||
|  |     ///
 | ||||||
|  |     /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
 | ||||||
|  |     /// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
 | ||||||
|  |     /// there's power in VBUS, i.e. the USB cable is always plugged in.)
 | ||||||
|  |     ///
 | ||||||
|  |     /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
 | ||||||
|  |     /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
 | ||||||
|  |     ///
 | ||||||
|  |     /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
 | ||||||
|  |     /// voltage divider. See ST application note AN4879 and the reference manual for more details.
 | ||||||
|  |     pub vbus_detection: bool, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Default for Config { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { vbus_detection: true } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub struct Driver<'d, T: Instance> { | pub struct Driver<'d, T: Instance> { | ||||||
|  |     config: Config, | ||||||
|     phantom: PhantomData<&'d mut T>, |     phantom: PhantomData<&'d mut T>, | ||||||
|     ep_in: [Option<EndpointData>; MAX_EP_COUNT], |     ep_in: [Option<EndpointData>; MAX_EP_COUNT], | ||||||
|     ep_out: [Option<EndpointData>; MAX_EP_COUNT], |     ep_out: [Option<EndpointData>; MAX_EP_COUNT], | ||||||
| @ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||||||
|         dp: impl Peripheral<P = impl DpPin<T>> + 'd, |         dp: impl Peripheral<P = impl DpPin<T>> + 'd, | ||||||
|         dm: impl Peripheral<P = impl DmPin<T>> + 'd, |         dm: impl Peripheral<P = impl DmPin<T>> + 'd, | ||||||
|         ep_out_buffer: &'d mut [u8], |         ep_out_buffer: &'d mut [u8], | ||||||
|  |         config: Config, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         into_ref!(dp, dm); |         into_ref!(dp, dm); | ||||||
| 
 | 
 | ||||||
| @ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||||||
|         dm.set_as_af(dm.af_num(), AFType::OutputPushPull); |         dm.set_as_af(dm.af_num(), AFType::OutputPushPull); | ||||||
| 
 | 
 | ||||||
|         Self { |         Self { | ||||||
|  |             config, | ||||||
|             phantom: PhantomData, |             phantom: PhantomData, | ||||||
|             ep_in: [None; MAX_EP_COUNT], |             ep_in: [None; MAX_EP_COUNT], | ||||||
|             ep_out: [None; MAX_EP_COUNT], |             ep_out: [None; MAX_EP_COUNT], | ||||||
| @ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||||||
|         ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, |         ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, | ||||||
|         ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, |         ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, | ||||||
|         ep_out_buffer: &'d mut [u8], |         ep_out_buffer: &'d mut [u8], | ||||||
|  |         config: Config, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); |         assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); | ||||||
| 
 | 
 | ||||||
| @ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> { | |||||||
|         ); |         ); | ||||||
| 
 | 
 | ||||||
|         Self { |         Self { | ||||||
|  |             config, | ||||||
|             phantom: PhantomData, |             phantom: PhantomData, | ||||||
|             ep_in: [None; MAX_EP_COUNT], |             ep_in: [None; MAX_EP_COUNT], | ||||||
|             ep_out: [None; MAX_EP_COUNT], |             ep_out: [None; MAX_EP_COUNT], | ||||||
| @ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { | |||||||
| 
 | 
 | ||||||
|         ( |         ( | ||||||
|             Bus { |             Bus { | ||||||
|  |                 config: self.config, | ||||||
|                 phantom: PhantomData, |                 phantom: PhantomData, | ||||||
|                 ep_in: self.ep_in, |                 ep_in: self.ep_in, | ||||||
|                 ep_out: self.ep_out, |                 ep_out: self.ep_out, | ||||||
|                 phy_type: self.phy_type, |                 phy_type: self.phy_type, | ||||||
|                 enabled: false, |                 inited: false, | ||||||
|             }, |             }, | ||||||
|             ControlPipe { |             ControlPipe { | ||||||
|                 _phantom: PhantomData, |                 _phantom: PhantomData, | ||||||
| @ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub struct Bus<'d, T: Instance> { | pub struct Bus<'d, T: Instance> { | ||||||
|  |     config: Config, | ||||||
|     phantom: PhantomData<&'d mut T>, |     phantom: PhantomData<&'d mut T>, | ||||||
|     ep_in: [Option<EndpointData>; MAX_EP_COUNT], |     ep_in: [Option<EndpointData>; MAX_EP_COUNT], | ||||||
|     ep_out: [Option<EndpointData>; MAX_EP_COUNT], |     ep_out: [Option<EndpointData>; MAX_EP_COUNT], | ||||||
|     phy_type: PhyType, |     phy_type: PhyType, | ||||||
|     enabled: bool, |     inited: bool, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> Bus<'d, T> { | impl<'d, T: Instance> Bus<'d, T> { | ||||||
| @ -498,11 +531,202 @@ impl<'d, T: Instance> Bus<'d, T> { | |||||||
|             w.set_iepint(true); |             w.set_iepint(true); | ||||||
|             w.set_oepint(true); |             w.set_oepint(true); | ||||||
|             w.set_rxflvlm(true); |             w.set_rxflvlm(true); | ||||||
|  |             w.set_srqim(true); | ||||||
|  |             w.set_otgint(true); | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'d, T: Instance> Bus<'d, T> { | impl<'d, T: Instance> Bus<'d, T> { | ||||||
|  |     fn init(&mut self) { | ||||||
|  |         #[cfg(stm32l4)] | ||||||
|  |         { | ||||||
|  |             crate::peripherals::PWR::enable(); | ||||||
|  |             critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         #[cfg(stm32f7)] | ||||||
|  |         { | ||||||
|  |             // Enable ULPI clock if external PHY is used
 | ||||||
|  |             let ulpien = !self.phy_type.internal(); | ||||||
|  |             critical_section::with(|_| { | ||||||
|  |                 crate::pac::RCC.ahb1enr().modify(|w| { | ||||||
|  |                     if T::HIGH_SPEED { | ||||||
|  |                         w.set_usb_otg_hsulpien(ulpien); | ||||||
|  |                     } else { | ||||||
|  |                         w.set_usb_otg_hsen(ulpien); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 // Low power mode
 | ||||||
|  |                 crate::pac::RCC.ahb1lpenr().modify(|w| { | ||||||
|  |                     if T::HIGH_SPEED { | ||||||
|  |                         w.set_usb_otg_hsulpilpen(ulpien); | ||||||
|  |                     } else { | ||||||
|  |                         w.set_usb_otg_hslpen(ulpien); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         #[cfg(stm32h7)] | ||||||
|  |         { | ||||||
|  |             // If true, VDD33USB is generated by internal regulator from VDD50USB
 | ||||||
|  |             // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
 | ||||||
|  |             // TODO: unhardcode
 | ||||||
|  |             let internal_regulator = false; | ||||||
|  | 
 | ||||||
|  |             // Enable USB power
 | ||||||
|  |             critical_section::with(|_| { | ||||||
|  |                 crate::pac::PWR.cr3().modify(|w| { | ||||||
|  |                     w.set_usb33den(true); | ||||||
|  |                     w.set_usbregen(internal_regulator); | ||||||
|  |                 }) | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             // Wait for USB power to stabilize
 | ||||||
|  |             while !crate::pac::PWR.cr3().read().usb33rdy() {} | ||||||
|  | 
 | ||||||
|  |             // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
 | ||||||
|  |             critical_section::with(|_| { | ||||||
|  |                 crate::pac::RCC | ||||||
|  |                     .d2ccip2r() | ||||||
|  |                     .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             // Enable ULPI clock if external PHY is used
 | ||||||
|  |             let ulpien = !self.phy_type.internal(); | ||||||
|  |             critical_section::with(|_| { | ||||||
|  |                 crate::pac::RCC.ahb1enr().modify(|w| { | ||||||
|  |                     if T::HIGH_SPEED { | ||||||
|  |                         w.set_usb_otg_hs_ulpien(ulpien); | ||||||
|  |                     } else { | ||||||
|  |                         w.set_usb_otg_fs_ulpien(ulpien); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |                 crate::pac::RCC.ahb1lpenr().modify(|w| { | ||||||
|  |                     if T::HIGH_SPEED { | ||||||
|  |                         w.set_usb_otg_hs_ulpilpen(ulpien); | ||||||
|  |                     } else { | ||||||
|  |                         w.set_usb_otg_fs_ulpilpen(ulpien); | ||||||
|  |                     } | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         #[cfg(stm32u5)] | ||||||
|  |         { | ||||||
|  |             // Enable USB power
 | ||||||
|  |             critical_section::with(|_| { | ||||||
|  |                 crate::pac::RCC.ahb3enr().modify(|w| { | ||||||
|  |                     w.set_pwren(true); | ||||||
|  |                 }); | ||||||
|  |                 cortex_m::asm::delay(2); | ||||||
|  | 
 | ||||||
|  |                 crate::pac::PWR.svmcr().modify(|w| { | ||||||
|  |                     w.set_usv(true); | ||||||
|  |                     w.set_uvmen(true); | ||||||
|  |                 }); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             // Wait for USB power to stabilize
 | ||||||
|  |             while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | ||||||
|  | 
 | ||||||
|  |             // Select HSI48 as USB clock source.
 | ||||||
|  |             critical_section::with(|_| { | ||||||
|  |                 crate::pac::RCC.ccipr1().modify(|w| { | ||||||
|  |                     w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); | ||||||
|  |                 }) | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         <T as RccPeripheral>::enable(); | ||||||
|  |         <T as RccPeripheral>::reset(); | ||||||
|  | 
 | ||||||
|  |         T::Interrupt::unpend(); | ||||||
|  |         unsafe { T::Interrupt::enable() }; | ||||||
|  | 
 | ||||||
|  |         let r = T::regs(); | ||||||
|  |         let core_id = r.cid().read().0; | ||||||
|  |         info!("Core id {:08x}", core_id); | ||||||
|  | 
 | ||||||
|  |         // Wait for AHB ready.
 | ||||||
|  |         while !r.grstctl().read().ahbidl() {} | ||||||
|  | 
 | ||||||
|  |         // Configure as device.
 | ||||||
|  |         r.gusbcfg().write(|w| { | ||||||
|  |             // Force device mode
 | ||||||
|  |             w.set_fdmod(true); | ||||||
|  |             // Enable internal full-speed PHY
 | ||||||
|  |             w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // Configuring Vbus sense and SOF output
 | ||||||
|  |         match core_id { | ||||||
|  |             0x0000_1200 | 0x0000_1100 => { | ||||||
|  |                 assert!(self.phy_type != PhyType::InternalHighSpeed); | ||||||
|  | 
 | ||||||
|  |                 r.gccfg_v1().modify(|w| { | ||||||
|  |                     // Enable internal full-speed PHY, logic is inverted
 | ||||||
|  |                     w.set_pwrdwn(self.phy_type.internal()); | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 // F429-like chips have the GCCFG.NOVBUSSENS bit
 | ||||||
|  |                 r.gccfg_v1().modify(|w| { | ||||||
|  |                     w.set_novbussens(!self.config.vbus_detection); | ||||||
|  |                     w.set_vbusasen(false); | ||||||
|  |                     w.set_vbusbsen(self.config.vbus_detection); | ||||||
|  |                     w.set_sofouten(false); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { | ||||||
|  |                 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
 | ||||||
|  |                 r.gccfg_v2().modify(|w| { | ||||||
|  |                     // Enable internal full-speed PHY, logic is inverted
 | ||||||
|  |                     w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); | ||||||
|  |                     w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 r.gccfg_v2().modify(|w| { | ||||||
|  |                     w.set_vbden(self.config.vbus_detection); | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |                 // Force B-peripheral session
 | ||||||
|  |                 r.gotgctl().modify(|w| { | ||||||
|  |                     w.set_bvaloen(!self.config.vbus_detection); | ||||||
|  |                     w.set_bvaloval(true); | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |             _ => unimplemented!("Unknown USB core id {:X}", core_id), | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Soft disconnect.
 | ||||||
|  |         r.dctl().write(|w| w.set_sdis(true)); | ||||||
|  | 
 | ||||||
|  |         // Set speed.
 | ||||||
|  |         r.dcfg().write(|w| { | ||||||
|  |             w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); | ||||||
|  |             w.set_dspd(self.phy_type.to_dspd()); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // Unmask transfer complete EP interrupt
 | ||||||
|  |         r.diepmsk().write(|w| { | ||||||
|  |             w.set_xfrcm(true); | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // Unmask and clear core interrupts
 | ||||||
|  |         Bus::<T>::restore_irqs(); | ||||||
|  |         r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); | ||||||
|  | 
 | ||||||
|  |         // Unmask global interrupt
 | ||||||
|  |         r.gahbcfg().write(|w| { | ||||||
|  |             w.set_gint(true); // unmask global interrupt
 | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |         // Connect
 | ||||||
|  |         r.dctl().write(|w| w.set_sdis(false)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn init_fifo(&mut self) { |     fn init_fifo(&mut self) { | ||||||
|         trace!("init_fifo"); |         trace!("init_fifo"); | ||||||
| 
 | 
 | ||||||
| @ -613,6 +837,13 @@ impl<'d, T: Instance> Bus<'d, T> { | |||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     fn disable_all_endpoints(&mut self) { | ||||||
|  |         for i in 0..T::ENDPOINT_COUNT { | ||||||
|  |             self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false); | ||||||
|  |             self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     fn disable(&mut self) { |     fn disable(&mut self) { | ||||||
|         T::Interrupt::disable(); |         T::Interrupt::disable(); | ||||||
| 
 | 
 | ||||||
| @ -627,16 +858,47 @@ impl<'d, T: Instance> Bus<'d, T> { | |||||||
| impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | ||||||
|     async fn poll(&mut self) -> Event { |     async fn poll(&mut self) -> Event { | ||||||
|         poll_fn(move |cx| { |         poll_fn(move |cx| { | ||||||
|             // TODO: implement VBUS detection
 |             if !self.inited { | ||||||
|             if !self.enabled { |                 self.init(); | ||||||
|  |                 self.inited = true; | ||||||
|  | 
 | ||||||
|  |                 // If no vbus detection, just return a single PowerDetected event at startup.
 | ||||||
|  |                 if !self.config.vbus_detection { | ||||||
|                     return Poll::Ready(Event::PowerDetected); |                     return Poll::Ready(Event::PowerDetected); | ||||||
|                 } |                 } | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             let r = T::regs(); |             let r = T::regs(); | ||||||
| 
 | 
 | ||||||
|             T::state().bus_waker.register(cx.waker()); |             T::state().bus_waker.register(cx.waker()); | ||||||
| 
 | 
 | ||||||
|             let ints = r.gintsts().read(); |             let ints = r.gintsts().read(); | ||||||
|  | 
 | ||||||
|  |             if ints.srqint() { | ||||||
|  |                 trace!("vbus detected"); | ||||||
|  | 
 | ||||||
|  |                 r.gintsts().write(|w| w.set_srqint(true)); // clear
 | ||||||
|  |                 Self::restore_irqs(); | ||||||
|  | 
 | ||||||
|  |                 if self.config.vbus_detection { | ||||||
|  |                     return Poll::Ready(Event::PowerDetected); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if ints.otgint() { | ||||||
|  |                 let otgints = r.gotgint().read(); | ||||||
|  |                 r.gotgint().write_value(otgints); // clear all
 | ||||||
|  |                 Self::restore_irqs(); | ||||||
|  | 
 | ||||||
|  |                 if otgints.sedet() { | ||||||
|  |                     trace!("vbus removed"); | ||||||
|  |                     if self.config.vbus_detection { | ||||||
|  |                         self.disable_all_endpoints(); | ||||||
|  |                         return Poll::Ready(Event::PowerRemoved); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|             if ints.usbrst() { |             if ints.usbrst() { | ||||||
|                 trace!("reset"); |                 trace!("reset"); | ||||||
| 
 | 
 | ||||||
| @ -801,203 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||||||
| 
 | 
 | ||||||
|     async fn enable(&mut self) { |     async fn enable(&mut self) { | ||||||
|         trace!("enable"); |         trace!("enable"); | ||||||
| 
 |         // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
 | ||||||
|         #[cfg(stm32l4)] |  | ||||||
|         { |  | ||||||
|             crate::peripherals::PWR::enable(); |  | ||||||
|             critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         #[cfg(stm32f7)] |  | ||||||
|         { |  | ||||||
|             // Enable ULPI clock if external PHY is used
 |  | ||||||
|             let ulpien = !self.phy_type.internal(); |  | ||||||
|             critical_section::with(|_| { |  | ||||||
|                 crate::pac::RCC.ahb1enr().modify(|w| { |  | ||||||
|                     if T::HIGH_SPEED { |  | ||||||
|                         w.set_usb_otg_hsulpien(ulpien); |  | ||||||
|                     } else { |  | ||||||
|                         w.set_usb_otg_hsen(ulpien); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|                 // Low power mode
 |  | ||||||
|                 crate::pac::RCC.ahb1lpenr().modify(|w| { |  | ||||||
|                     if T::HIGH_SPEED { |  | ||||||
|                         w.set_usb_otg_hsulpilpen(ulpien); |  | ||||||
|                     } else { |  | ||||||
|                         w.set_usb_otg_hslpen(ulpien); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         #[cfg(stm32h7)] |  | ||||||
|         { |  | ||||||
|             // If true, VDD33USB is generated by internal regulator from VDD50USB
 |  | ||||||
|             // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
 |  | ||||||
|             // TODO: unhardcode
 |  | ||||||
|             let internal_regulator = false; |  | ||||||
| 
 |  | ||||||
|             // Enable USB power
 |  | ||||||
|             critical_section::with(|_| { |  | ||||||
|                 crate::pac::PWR.cr3().modify(|w| { |  | ||||||
|                     w.set_usb33den(true); |  | ||||||
|                     w.set_usbregen(internal_regulator); |  | ||||||
|                 }) |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             // Wait for USB power to stabilize
 |  | ||||||
|             while !crate::pac::PWR.cr3().read().usb33rdy() {} |  | ||||||
| 
 |  | ||||||
|             // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
 |  | ||||||
|             critical_section::with(|_| { |  | ||||||
|                 crate::pac::RCC |  | ||||||
|                     .d2ccip2r() |  | ||||||
|                     .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             // Enable ULPI clock if external PHY is used
 |  | ||||||
|             let ulpien = !self.phy_type.internal(); |  | ||||||
|             critical_section::with(|_| { |  | ||||||
|                 crate::pac::RCC.ahb1enr().modify(|w| { |  | ||||||
|                     if T::HIGH_SPEED { |  | ||||||
|                         w.set_usb_otg_hs_ulpien(ulpien); |  | ||||||
|                     } else { |  | ||||||
|                         w.set_usb_otg_fs_ulpien(ulpien); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
|                 crate::pac::RCC.ahb1lpenr().modify(|w| { |  | ||||||
|                     if T::HIGH_SPEED { |  | ||||||
|                         w.set_usb_otg_hs_ulpilpen(ulpien); |  | ||||||
|                     } else { |  | ||||||
|                         w.set_usb_otg_fs_ulpilpen(ulpien); |  | ||||||
|                     } |  | ||||||
|                 }); |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         #[cfg(stm32u5)] |  | ||||||
|         { |  | ||||||
|             // Enable USB power
 |  | ||||||
|             critical_section::with(|_| { |  | ||||||
|                 crate::pac::RCC.ahb3enr().modify(|w| { |  | ||||||
|                     w.set_pwren(true); |  | ||||||
|                 }); |  | ||||||
|                 cortex_m::asm::delay(2); |  | ||||||
| 
 |  | ||||||
|                 crate::pac::PWR.svmcr().modify(|w| { |  | ||||||
|                     w.set_usv(true); |  | ||||||
|                     w.set_uvmen(true); |  | ||||||
|                 }); |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|             // Wait for USB power to stabilize
 |  | ||||||
|             while !crate::pac::PWR.svmsr().read().vddusbrdy() {} |  | ||||||
| 
 |  | ||||||
|             // Select HSI48 as USB clock source.
 |  | ||||||
|             critical_section::with(|_| { |  | ||||||
|                 crate::pac::RCC.ccipr1().modify(|w| { |  | ||||||
|                     w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); |  | ||||||
|                 }) |  | ||||||
|             }); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         <T as RccPeripheral>::enable(); |  | ||||||
|         <T as RccPeripheral>::reset(); |  | ||||||
| 
 |  | ||||||
|         T::Interrupt::unpend(); |  | ||||||
|         unsafe { T::Interrupt::enable() }; |  | ||||||
| 
 |  | ||||||
|         let r = T::regs(); |  | ||||||
|         let core_id = r.cid().read().0; |  | ||||||
|         info!("Core id {:08x}", core_id); |  | ||||||
| 
 |  | ||||||
|         // Wait for AHB ready.
 |  | ||||||
|         while !r.grstctl().read().ahbidl() {} |  | ||||||
| 
 |  | ||||||
|         // Configure as device.
 |  | ||||||
|         r.gusbcfg().write(|w| { |  | ||||||
|             // Force device mode
 |  | ||||||
|             w.set_fdmod(true); |  | ||||||
|             // Enable internal full-speed PHY
 |  | ||||||
|             w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         // Configuring Vbus sense and SOF output
 |  | ||||||
|         match core_id { |  | ||||||
|             0x0000_1200 | 0x0000_1100 => { |  | ||||||
|                 assert!(self.phy_type != PhyType::InternalHighSpeed); |  | ||||||
| 
 |  | ||||||
|                 r.gccfg_v1().modify(|w| { |  | ||||||
|                     // Enable internal full-speed PHY, logic is inverted
 |  | ||||||
|                     w.set_pwrdwn(self.phy_type.internal()); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|                 // F429-like chips have the GCCFG.NOVBUSSENS bit
 |  | ||||||
|                 r.gccfg_v1().modify(|w| { |  | ||||||
|                     w.set_novbussens(true); |  | ||||||
|                     w.set_vbusasen(false); |  | ||||||
|                     w.set_vbusbsen(false); |  | ||||||
|                     w.set_sofouten(false); |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|             0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { |  | ||||||
|                 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
 |  | ||||||
|                 r.gccfg_v2().modify(|w| { |  | ||||||
|                     // Enable internal full-speed PHY, logic is inverted
 |  | ||||||
|                     w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); |  | ||||||
|                     w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|                 r.gccfg_v2().modify(|w| { |  | ||||||
|                     w.set_vbden(false); |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|                 // Force B-peripheral session
 |  | ||||||
|                 r.gotgctl().modify(|w| { |  | ||||||
|                     w.set_bvaloen(true); |  | ||||||
|                     w.set_bvaloval(true); |  | ||||||
|                 }); |  | ||||||
|             } |  | ||||||
|             _ => unimplemented!("Unknown USB core id {:X}", core_id), |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // Soft disconnect.
 |  | ||||||
|         r.dctl().write(|w| w.set_sdis(true)); |  | ||||||
| 
 |  | ||||||
|         // Set speed.
 |  | ||||||
|         r.dcfg().write(|w| { |  | ||||||
|             w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); |  | ||||||
|             w.set_dspd(self.phy_type.to_dspd()); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         // Unmask transfer complete EP interrupt
 |  | ||||||
|         r.diepmsk().write(|w| { |  | ||||||
|             w.set_xfrcm(true); |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         // Unmask and clear core interrupts
 |  | ||||||
|         Bus::<T>::restore_irqs(); |  | ||||||
|         r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); |  | ||||||
| 
 |  | ||||||
|         // Unmask global interrupt
 |  | ||||||
|         r.gahbcfg().write(|w| { |  | ||||||
|             w.set_gint(true); // unmask global interrupt
 |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|         // Connect
 |  | ||||||
|         r.dctl().write(|w| w.set_sdis(false)); |  | ||||||
| 
 |  | ||||||
|         self.enabled = true; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn disable(&mut self) { |     async fn disable(&mut self) { | ||||||
|         trace!("disable"); |         trace!("disable"); | ||||||
| 
 | 
 | ||||||
|         Bus::disable(self); |         // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
 | ||||||
| 
 |         //Bus::disable(self);
 | ||||||
|         self.enabled = false; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { |     async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { | ||||||
| @ -1140,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||||||
|             state.ep_in_wakers[index].register(cx.waker()); |             state.ep_in_wakers[index].register(cx.waker()); | ||||||
| 
 | 
 | ||||||
|             let diepctl = r.diepctl(index).read(); |             let diepctl = r.diepctl(index).read(); | ||||||
|  |             let dtxfsts = r.dtxfsts(index).read(); | ||||||
|  |             info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0); | ||||||
|             if !diepctl.usbaep() { |             if !diepctl.usbaep() { | ||||||
|  |                 trace!("write ep={:?} wait for prev: error disabled", self.info.addr); | ||||||
|                 Poll::Ready(Err(EndpointError::Disabled)) |                 Poll::Ready(Err(EndpointError::Disabled)) | ||||||
|             } else if !diepctl.epena() { |             } else if !diepctl.epena() { | ||||||
|  |                 trace!("write ep={:?} wait for prev: ready", self.info.addr); | ||||||
|                 Poll::Ready(Ok(())) |                 Poll::Ready(Ok(())) | ||||||
|             } else { |             } else { | ||||||
|  |                 trace!("write ep={:?} wait for prev: pending", self.info.addr); | ||||||
|                 Poll::Pending |                 Poll::Pending | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
| @ -1169,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||||||
| 
 | 
 | ||||||
|                     Poll::Pending |                     Poll::Pending | ||||||
|                 } else { |                 } else { | ||||||
|  |                     trace!("write ep={:?} wait for fifo: ready", self.info.addr); | ||||||
|                     Poll::Ready(()) |                     Poll::Ready(()) | ||||||
|                 } |                 } | ||||||
|             }) |             }) | ||||||
|  | |||||||
| @ -52,7 +52,9 @@ async fn main(spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     // Create the driver, from the HAL.
 |     // Create the driver, from the HAL.
 | ||||||
|     let ep_out_buffer = &mut make_static!([0; 256])[..]; |     let ep_out_buffer = &mut make_static!([0; 256])[..]; | ||||||
|     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); |     let mut config = embassy_stm32::usb_otg::Config::default(); | ||||||
|  |     config.vbus_detection = true; | ||||||
|  |     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config); | ||||||
| 
 | 
 | ||||||
|     // Create embassy-usb Config
 |     // Create embassy-usb Config
 | ||||||
|     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  | |||||||
| @ -29,7 +29,9 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     // Create the driver, from the HAL.
 |     // Create the driver, from the HAL.
 | ||||||
|     let mut ep_out_buffer = [0u8; 256]; |     let mut ep_out_buffer = [0u8; 256]; | ||||||
|     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); |     let mut config = embassy_stm32::usb_otg::Config::default(); | ||||||
|  |     config.vbus_detection = true; | ||||||
|  |     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||||||
| 
 | 
 | ||||||
|     // Create embassy-usb Config
 |     // Create embassy-usb Config
 | ||||||
|     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  | |||||||
| @ -30,7 +30,9 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     // Create the driver, from the HAL.
 |     // Create the driver, from the HAL.
 | ||||||
|     let mut ep_out_buffer = [0u8; 256]; |     let mut ep_out_buffer = [0u8; 256]; | ||||||
|     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); |     let mut config = embassy_stm32::usb_otg::Config::default(); | ||||||
|  |     config.vbus_detection = true; | ||||||
|  |     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||||||
| 
 | 
 | ||||||
|     // Create embassy-usb Config
 |     // Create embassy-usb Config
 | ||||||
|     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  | |||||||
| @ -29,7 +29,9 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     // Create the driver, from the HAL.
 |     // Create the driver, from the HAL.
 | ||||||
|     let mut ep_out_buffer = [0u8; 256]; |     let mut ep_out_buffer = [0u8; 256]; | ||||||
|     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); |     let mut config = embassy_stm32::usb_otg::Config::default(); | ||||||
|  |     config.vbus_detection = true; | ||||||
|  |     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||||||
| 
 | 
 | ||||||
|     // Create embassy-usb Config
 |     // Create embassy-usb Config
 | ||||||
|     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  | |||||||
| @ -30,7 +30,9 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     // Create the driver, from the HAL.
 |     // Create the driver, from the HAL.
 | ||||||
|     let mut ep_out_buffer = [0u8; 256]; |     let mut ep_out_buffer = [0u8; 256]; | ||||||
|     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); |     let mut config = embassy_stm32::usb_otg::Config::default(); | ||||||
|  |     config.vbus_detection = true; | ||||||
|  |     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||||||
| 
 | 
 | ||||||
|     // Create embassy-usb Config
 |     // Create embassy-usb Config
 | ||||||
|     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  | |||||||
| @ -31,7 +31,9 @@ async fn main(_spawner: Spawner) { | |||||||
| 
 | 
 | ||||||
|     // Create the driver, from the HAL.
 |     // Create the driver, from the HAL.
 | ||||||
|     let mut ep_out_buffer = [0u8; 256]; |     let mut ep_out_buffer = [0u8; 256]; | ||||||
|     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); |     let mut config = embassy_stm32::usb_otg::Config::default(); | ||||||
|  |     config.vbus_detection = true; | ||||||
|  |     let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config); | ||||||
| 
 | 
 | ||||||
|     // Create embassy-usb Config
 |     // Create embassy-usb Config
 | ||||||
|     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); |     let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user