aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-06-27 22:39:00 +0000
committerGitHub <[email protected]>2023-06-27 22:39:00 +0000
commit9b5d7ec06152e4f5dd036f813605a4bafb7e8621 (patch)
tree22564eaf7bf22140a06c36717f124a1e645cf41b
parent45561f1622c9d883c8a9fa990c22a8a373d6ce5e (diff)
parented493be869fa653dc14d31060375e17e2469ce11 (diff)
Merge pull request #1589 from embassy-rs/otg-fixes
stm32/otg: implement VBUS detection, misc fixes so plug/unplug works.
-rw-r--r--embassy-rp/src/usb.rs1
-rw-r--r--embassy-stm32/Cargo.toml4
-rw-r--r--embassy-stm32/src/rcc/l0.rs4
-rw-r--r--embassy-stm32/src/usb/usb.rs85
-rw-r--r--embassy-stm32/src/usb_otg/usb.rs515
-rw-r--r--embassy-sync/src/pipe.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_ethernet.rs4
-rw-r--r--examples/stm32f4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32f7/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32g4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32h7/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32l4/src/bin/usb_serial.rs4
-rw-r--r--examples/stm32u5/src/bin/usb_serial.rs4
13 files changed, 382 insertions, 259 deletions
diff --git a/embassy-rp/src/usb.rs b/embassy-rp/src/usb.rs
index 1900ab416..b3f3bd927 100644
--- a/embassy-rp/src/usb.rs
+++ b/embassy-rp/src/usb.rs
@@ -353,6 +353,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
353 poll_fn(move |cx| { 353 poll_fn(move |cx| {
354 BUS_WAKER.register(cx.waker()); 354 BUS_WAKER.register(cx.waker());
355 355
356 // TODO: implement VBUS detection.
356 if !self.inited { 357 if !self.inited {
357 self.inited = true; 358 self.inited = true;
358 return Poll::Ready(Event::PowerDetected); 359 return Poll::Ready(Event::PowerDetected);
diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml
index 3d9ee8261..f15c6d0b7 100644
--- a/embassy-stm32/Cargo.toml
+++ b/embassy-stm32/Cargo.toml
@@ -57,7 +57,7 @@ sdio-host = "0.5.0"
57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } 57embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
58critical-section = "1.1" 58critical-section = "1.1"
59atomic-polyfill = "1.0.1" 59atomic-polyfill = "1.0.1"
60stm32-metapac = "10" 60stm32-metapac = "11"
61vcell = "0.1.3" 61vcell = "0.1.3"
62bxcan = "0.7.0" 62bxcan = "0.7.0"
63nb = "1.0.0" 63nb = "1.0.0"
@@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
74[build-dependencies] 74[build-dependencies]
75proc-macro2 = "1.0.36" 75proc-macro2 = "1.0.36"
76quote = "1.0.15" 76quote = "1.0.15"
77stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} 77stm32-metapac = { version = "11", default-features = false, features = ["metadata"]}
78 78
79[features] 79[features]
80default = ["rt"] 80default = ["rt"]
diff --git a/embassy-stm32/src/rcc/l0.rs b/embassy-stm32/src/rcc/l0.rs
index 42a481a74..d53b61069 100644
--- a/embassy-stm32/src/rcc/l0.rs
+++ b/embassy-stm32/src/rcc/l0.rs
@@ -1,7 +1,7 @@
1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; 1use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
2use crate::pac::RCC; 2use crate::pac::RCC;
3#[cfg(crs)] 3#[cfg(crs)]
4use crate::pac::{CRS, SYSCFG}; 4use crate::pac::{crs, CRS, SYSCFG};
5use crate::rcc::{set_freqs, Clocks}; 5use crate::rcc::{set_freqs, Clocks};
6use crate::time::Hertz; 6use crate::time::Hertz;
7 7
@@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) {
338 CRS.cfgr().write(|w| 338 CRS.cfgr().write(|w|
339 339
340 // Select LSE as synchronization source 340 // Select LSE as synchronization source
341 w.set_syncsrc(0b01)); 341 w.set_syncsrc(crs::vals::Syncsrc::LSE));
342 CRS.cr().modify(|w| { 342 CRS.cr().modify(|w| {
343 w.set_autotrimen(true); 343 w.set_autotrimen(true);
344 w.set_cen(true); 344 w.set_cen(true);
diff --git a/embassy-stm32/src/usb/usb.rs b/embassy-stm32/src/usb/usb.rs
index 2367127e8..01b158b17 100644
--- a/embassy-stm32/src/usb/usb.rs
+++ b/embassy-stm32/src/usb/usb.rs
@@ -480,56 +480,57 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
480 poll_fn(move |cx| { 480 poll_fn(move |cx| {
481 BUS_WAKER.register(cx.waker()); 481 BUS_WAKER.register(cx.waker());
482 482
483 if self.inited { 483 // TODO: implement VBUS detection.
484 let regs = T::regs(); 484 if !self.inited {
485 485 self.inited = true;
486 if IRQ_RESUME.load(Ordering::Acquire) { 486 return Poll::Ready(Event::PowerDetected);
487 IRQ_RESUME.store(false, Ordering::Relaxed); 487 }
488 return Poll::Ready(Event::Resume);
489 }
490 488
491 if IRQ_RESET.load(Ordering::Acquire) { 489 let regs = T::regs();
492 IRQ_RESET.store(false, Ordering::Relaxed);
493
494 trace!("RESET");
495 regs.daddr().write(|w| {
496 w.set_ef(true);
497 w.set_add(0);
498 });
499
500 regs.epr(0).write(|w| {
501 w.set_ep_type(EpType::CONTROL);
502 w.set_stat_rx(Stat::NAK);
503 w.set_stat_tx(Stat::NAK);
504 });
505
506 for i in 1..EP_COUNT {
507 regs.epr(i).write(|w| {
508 w.set_ea(i as _);
509 w.set_ep_type(self.ep_types[i - 1]);
510 })
511 }
512 490
513 for w in &EP_IN_WAKERS { 491 if IRQ_RESUME.load(Ordering::Acquire) {
514 w.wake() 492 IRQ_RESUME.store(false, Ordering::Relaxed);
515 } 493 return Poll::Ready(Event::Resume);
516 for w in &EP_OUT_WAKERS { 494 }
517 w.wake()
518 }
519 495
520 return Poll::Ready(Event::Reset); 496 if IRQ_RESET.load(Ordering::Acquire) {
497 IRQ_RESET.store(false, Ordering::Relaxed);
498
499 trace!("RESET");
500 regs.daddr().write(|w| {
501 w.set_ef(true);
502 w.set_add(0);
503 });
504
505 regs.epr(0).write(|w| {
506 w.set_ep_type(EpType::CONTROL);
507 w.set_stat_rx(Stat::NAK);
508 w.set_stat_tx(Stat::NAK);
509 });
510
511 for i in 1..EP_COUNT {
512 regs.epr(i).write(|w| {
513 w.set_ea(i as _);
514 w.set_ep_type(self.ep_types[i - 1]);
515 })
521 } 516 }
522 517
523 if IRQ_SUSPEND.load(Ordering::Acquire) { 518 for w in &EP_IN_WAKERS {
524 IRQ_SUSPEND.store(false, Ordering::Relaxed); 519 w.wake()
525 return Poll::Ready(Event::Suspend); 520 }
521 for w in &EP_OUT_WAKERS {
522 w.wake()
526 } 523 }
527 524
528 Poll::Pending 525 return Poll::Ready(Event::Reset);
529 } else { 526 }
530 self.inited = true; 527
531 return Poll::Ready(Event::PowerDetected); 528 if IRQ_SUSPEND.load(Ordering::Acquire) {
529 IRQ_SUSPEND.store(false, Ordering::Relaxed);
530 return Poll::Ready(Event::Suspend);
532 } 531 }
532
533 Poll::Pending
533 }) 534 })
534 .await 535 .await
535 } 536 }
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs
index 8af5c7bd5..6c00c93d6 100644
--- a/embassy-stm32/src/usb_otg/usb.rs
+++ b/embassy-stm32/src/usb_otg/usb.rs
@@ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
6use embassy_hal_common::{into_ref, Peripheral}; 6use embassy_hal_common::{into_ref, Peripheral};
7use embassy_sync::waitqueue::AtomicWaker; 7use embassy_sync::waitqueue::AtomicWaker;
8use embassy_usb_driver::{ 8use embassy_usb_driver::{
9 self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, 9 self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
10 EndpointType, Event, Unsupported, 10 EndpointOut, EndpointType, Event, Unsupported,
11}; 11};
12use futures::future::poll_fn; 12use futures::future::poll_fn;
13 13
@@ -31,7 +31,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
31 let state = T::state(); 31 let state = T::state();
32 32
33 let ints = r.gintsts().read(); 33 let ints = r.gintsts().read();
34 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { 34 if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
35 // Mask interrupts and notify `Bus` to process them 35 // Mask interrupts and notify `Bus` to process them
36 r.gintmsk().write(|_| {}); 36 r.gintmsk().write(|_| {});
37 T::state().bus_waker.wake(); 37 T::state().bus_waker.wake();
@@ -124,7 +124,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
124 } 124 }
125 125
126 state.ep_in_wakers[ep_num].wake(); 126 state.ep_in_wakers[ep_num].wake();
127 trace!("in ep={} irq val={:b}", ep_num, ep_ints.0); 127 trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
128 } 128 }
129 129
130 ep_mask >>= 1; 130 ep_mask >>= 1;
@@ -144,7 +144,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
144 // // clear all 144 // // clear all
145 // r.doepint(ep_num).write_value(ep_ints); 145 // r.doepint(ep_num).write_value(ep_ints);
146 // state.ep_out_wakers[ep_num].wake(); 146 // state.ep_out_wakers[ep_num].wake();
147 // trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0); 147 // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
148 // } 148 // }
149 149
150 // ep_mask >>= 1; 150 // ep_mask >>= 1;
@@ -256,7 +256,34 @@ struct EndpointData {
256 fifo_size_words: u16, 256 fifo_size_words: u16,
257} 257}
258 258
259#[non_exhaustive]
260#[derive(Clone, Copy, PartialEq, Eq, Debug)]
261pub struct Config {
262 /// Enable VBUS detection.
263 ///
264 /// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
265 /// This is done by checkihg whether there is 5V on the VBUS pin or not.
266 ///
267 /// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
268 /// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
269 /// there's power in VBUS, i.e. the USB cable is always plugged in.)
270 ///
271 /// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
272 /// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
273 ///
274 /// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
275 /// voltage divider. See ST application note AN4879 and the reference manual for more details.
276 pub vbus_detection: bool,
277}
278
279impl Default for Config {
280 fn default() -> Self {
281 Self { vbus_detection: true }
282 }
283}
284
259pub struct Driver<'d, T: Instance> { 285pub struct Driver<'d, T: Instance> {
286 config: Config,
260 phantom: PhantomData<&'d mut T>, 287 phantom: PhantomData<&'d mut T>,
261 ep_in: [Option<EndpointData>; MAX_EP_COUNT], 288 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
262 ep_out: [Option<EndpointData>; MAX_EP_COUNT], 289 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
@@ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> {
279 dp: impl Peripheral<P = impl DpPin<T>> + 'd, 306 dp: impl Peripheral<P = impl DpPin<T>> + 'd,
280 dm: impl Peripheral<P = impl DmPin<T>> + 'd, 307 dm: impl Peripheral<P = impl DmPin<T>> + 'd,
281 ep_out_buffer: &'d mut [u8], 308 ep_out_buffer: &'d mut [u8],
309 config: Config,
282 ) -> Self { 310 ) -> Self {
283 into_ref!(dp, dm); 311 into_ref!(dp, dm);
284 312
@@ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> {
286 dm.set_as_af(dm.af_num(), AFType::OutputPushPull); 314 dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
287 315
288 Self { 316 Self {
317 config,
289 phantom: PhantomData, 318 phantom: PhantomData,
290 ep_in: [None; MAX_EP_COUNT], 319 ep_in: [None; MAX_EP_COUNT],
291 ep_out: [None; MAX_EP_COUNT], 320 ep_out: [None; MAX_EP_COUNT],
@@ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> {
318 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, 347 ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
319 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, 348 ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
320 ep_out_buffer: &'d mut [u8], 349 ep_out_buffer: &'d mut [u8],
350 config: Config,
321 ) -> Self { 351 ) -> Self {
322 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); 352 assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
323 353
@@ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
327 ); 357 );
328 358
329 Self { 359 Self {
360 config,
330 phantom: PhantomData, 361 phantom: PhantomData,
331 ep_in: [None; MAX_EP_COUNT], 362 ep_in: [None; MAX_EP_COUNT],
332 ep_out: [None; MAX_EP_COUNT], 363 ep_out: [None; MAX_EP_COUNT],
@@ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
464 495
465 ( 496 (
466 Bus { 497 Bus {
498 config: self.config,
467 phantom: PhantomData, 499 phantom: PhantomData,
468 ep_in: self.ep_in, 500 ep_in: self.ep_in,
469 ep_out: self.ep_out, 501 ep_out: self.ep_out,
470 phy_type: self.phy_type, 502 phy_type: self.phy_type,
471 enabled: false, 503 inited: false,
472 }, 504 },
473 ControlPipe { 505 ControlPipe {
474 _phantom: PhantomData, 506 _phantom: PhantomData,
@@ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
481} 513}
482 514
483pub struct Bus<'d, T: Instance> { 515pub struct Bus<'d, T: Instance> {
516 config: Config,
484 phantom: PhantomData<&'d mut T>, 517 phantom: PhantomData<&'d mut T>,
485 ep_in: [Option<EndpointData>; MAX_EP_COUNT], 518 ep_in: [Option<EndpointData>; MAX_EP_COUNT],
486 ep_out: [Option<EndpointData>; MAX_EP_COUNT], 519 ep_out: [Option<EndpointData>; MAX_EP_COUNT],
487 phy_type: PhyType, 520 phy_type: PhyType,
488 enabled: bool, 521 inited: bool,
489} 522}
490 523
491impl<'d, T: Instance> Bus<'d, T> { 524impl<'d, T: Instance> Bus<'d, T> {
@@ -498,11 +531,202 @@ impl<'d, T: Instance> Bus<'d, T> {
498 w.set_iepint(true); 531 w.set_iepint(true);
499 w.set_oepint(true); 532 w.set_oepint(true);
500 w.set_rxflvlm(true); 533 w.set_rxflvlm(true);
534 w.set_srqim(true);
535 w.set_otgint(true);
501 }); 536 });
502 } 537 }
503} 538}
504 539
505impl<'d, T: Instance> Bus<'d, T> { 540impl<'d, T: Instance> Bus<'d, T> {
541 fn init(&mut self) {
542 #[cfg(stm32l4)]
543 {
544 crate::peripherals::PWR::enable();
545 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
546 }
547
548 #[cfg(stm32f7)]
549 {
550 // Enable ULPI clock if external PHY is used
551 let ulpien = !self.phy_type.internal();
552 critical_section::with(|_| {
553 crate::pac::RCC.ahb1enr().modify(|w| {
554 if T::HIGH_SPEED {
555 w.set_usb_otg_hsulpien(ulpien);
556 } else {
557 w.set_usb_otg_hsen(ulpien);
558 }
559 });
560
561 // Low power mode
562 crate::pac::RCC.ahb1lpenr().modify(|w| {
563 if T::HIGH_SPEED {
564 w.set_usb_otg_hsulpilpen(ulpien);
565 } else {
566 w.set_usb_otg_hslpen(ulpien);
567 }
568 });
569 });
570 }
571
572 #[cfg(stm32h7)]
573 {
574 // If true, VDD33USB is generated by internal regulator from VDD50USB
575 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
576 // TODO: unhardcode
577 let internal_regulator = false;
578
579 // Enable USB power
580 critical_section::with(|_| {
581 crate::pac::PWR.cr3().modify(|w| {
582 w.set_usb33den(true);
583 w.set_usbregen(internal_regulator);
584 })
585 });
586
587 // Wait for USB power to stabilize
588 while !crate::pac::PWR.cr3().read().usb33rdy() {}
589
590 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
591 critical_section::with(|_| {
592 crate::pac::RCC
593 .d2ccip2r()
594 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
595 });
596
597 // Enable ULPI clock if external PHY is used
598 let ulpien = !self.phy_type.internal();
599 critical_section::with(|_| {
600 crate::pac::RCC.ahb1enr().modify(|w| {
601 if T::HIGH_SPEED {
602 w.set_usb_otg_hs_ulpien(ulpien);
603 } else {
604 w.set_usb_otg_fs_ulpien(ulpien);
605 }
606 });
607 crate::pac::RCC.ahb1lpenr().modify(|w| {
608 if T::HIGH_SPEED {
609 w.set_usb_otg_hs_ulpilpen(ulpien);
610 } else {
611 w.set_usb_otg_fs_ulpilpen(ulpien);
612 }
613 });
614 });
615 }
616
617 #[cfg(stm32u5)]
618 {
619 // Enable USB power
620 critical_section::with(|_| {
621 crate::pac::RCC.ahb3enr().modify(|w| {
622 w.set_pwren(true);
623 });
624 cortex_m::asm::delay(2);
625
626 crate::pac::PWR.svmcr().modify(|w| {
627 w.set_usv(true);
628 w.set_uvmen(true);
629 });
630 });
631
632 // Wait for USB power to stabilize
633 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
634
635 // Select HSI48 as USB clock source.
636 critical_section::with(|_| {
637 crate::pac::RCC.ccipr1().modify(|w| {
638 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
639 })
640 });
641 }
642
643 <T as RccPeripheral>::enable();
644 <T as RccPeripheral>::reset();
645
646 T::Interrupt::unpend();
647 unsafe { T::Interrupt::enable() };
648
649 let r = T::regs();
650 let core_id = r.cid().read().0;
651 info!("Core id {:08x}", core_id);
652
653 // Wait for AHB ready.
654 while !r.grstctl().read().ahbidl() {}
655
656 // Configure as device.
657 r.gusbcfg().write(|w| {
658 // Force device mode
659 w.set_fdmod(true);
660 // Enable internal full-speed PHY
661 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
662 });
663
664 // Configuring Vbus sense and SOF output
665 match core_id {
666 0x0000_1200 | 0x0000_1100 => {
667 assert!(self.phy_type != PhyType::InternalHighSpeed);
668
669 r.gccfg_v1().modify(|w| {
670 // Enable internal full-speed PHY, logic is inverted
671 w.set_pwrdwn(self.phy_type.internal());
672 });
673
674 // F429-like chips have the GCCFG.NOVBUSSENS bit
675 r.gccfg_v1().modify(|w| {
676 w.set_novbussens(!self.config.vbus_detection);
677 w.set_vbusasen(false);
678 w.set_vbusbsen(self.config.vbus_detection);
679 w.set_sofouten(false);
680 });
681 }
682 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
683 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
684 r.gccfg_v2().modify(|w| {
685 // Enable internal full-speed PHY, logic is inverted
686 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
687 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
688 });
689
690 r.gccfg_v2().modify(|w| {
691 w.set_vbden(self.config.vbus_detection);
692 });
693
694 // Force B-peripheral session
695 r.gotgctl().modify(|w| {
696 w.set_bvaloen(!self.config.vbus_detection);
697 w.set_bvaloval(true);
698 });
699 }
700 _ => unimplemented!("Unknown USB core id {:X}", core_id),
701 }
702
703 // Soft disconnect.
704 r.dctl().write(|w| w.set_sdis(true));
705
706 // Set speed.
707 r.dcfg().write(|w| {
708 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
709 w.set_dspd(self.phy_type.to_dspd());
710 });
711
712 // Unmask transfer complete EP interrupt
713 r.diepmsk().write(|w| {
714 w.set_xfrcm(true);
715 });
716
717 // Unmask and clear core interrupts
718 Bus::<T>::restore_irqs();
719 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
720
721 // Unmask global interrupt
722 r.gahbcfg().write(|w| {
723 w.set_gint(true); // unmask global interrupt
724 });
725
726 // Connect
727 r.dctl().write(|w| w.set_sdis(false));
728 }
729
506 fn init_fifo(&mut self) { 730 fn init_fifo(&mut self) {
507 trace!("init_fifo"); 731 trace!("init_fifo");
508 732
@@ -540,6 +764,19 @@ impl<'d, T: Instance> Bus<'d, T> {
540 fifo_top <= T::FIFO_DEPTH_WORDS, 764 fifo_top <= T::FIFO_DEPTH_WORDS,
541 "FIFO allocations exceeded maximum capacity" 765 "FIFO allocations exceeded maximum capacity"
542 ); 766 );
767
768 // Flush fifos
769 r.grstctl().write(|w| {
770 w.set_rxfflsh(true);
771 w.set_txfflsh(true);
772 w.set_txfnum(0x10);
773 });
774 loop {
775 let x = r.grstctl().read();
776 if !x.rxfflsh() && !x.txfflsh() {
777 break;
778 }
779 }
543 } 780 }
544 781
545 fn configure_endpoints(&mut self) { 782 fn configure_endpoints(&mut self) {
@@ -558,6 +795,8 @@ impl<'d, T: Instance> Bus<'d, T> {
558 w.set_mpsiz(ep.max_packet_size); 795 w.set_mpsiz(ep.max_packet_size);
559 w.set_eptyp(to_eptyp(ep.ep_type)); 796 w.set_eptyp(to_eptyp(ep.ep_type));
560 w.set_sd0pid_sevnfrm(true); 797 w.set_sd0pid_sevnfrm(true);
798 w.set_txfnum(index as _);
799 w.set_snak(true);
561 } 800 }
562 }); 801 });
563 }); 802 });
@@ -598,6 +837,13 @@ impl<'d, T: Instance> Bus<'d, T> {
598 }); 837 });
599 } 838 }
600 839
840 fn disable_all_endpoints(&mut self) {
841 for i in 0..T::ENDPOINT_COUNT {
842 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
843 self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
844 }
845 }
846
601 fn disable(&mut self) { 847 fn disable(&mut self) {
602 T::Interrupt::disable(); 848 T::Interrupt::disable();
603 849
@@ -612,9 +858,14 @@ impl<'d, T: Instance> Bus<'d, T> {
612impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { 858impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
613 async fn poll(&mut self) -> Event { 859 async fn poll(&mut self) -> Event {
614 poll_fn(move |cx| { 860 poll_fn(move |cx| {
615 // TODO: implement VBUS detection 861 if !self.inited {
616 if !self.enabled { 862 self.init();
617 return Poll::Ready(Event::PowerDetected); 863 self.inited = true;
864
865 // If no vbus detection, just return a single PowerDetected event at startup.
866 if !self.config.vbus_detection {
867 return Poll::Ready(Event::PowerDetected);
868 }
618 } 869 }
619 870
620 let r = T::regs(); 871 let r = T::regs();
@@ -622,6 +873,32 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
622 T::state().bus_waker.register(cx.waker()); 873 T::state().bus_waker.register(cx.waker());
623 874
624 let ints = r.gintsts().read(); 875 let ints = r.gintsts().read();
876
877 if ints.srqint() {
878 trace!("vbus detected");
879
880 r.gintsts().write(|w| w.set_srqint(true)); // clear
881 Self::restore_irqs();
882
883 if self.config.vbus_detection {
884 return Poll::Ready(Event::PowerDetected);
885 }
886 }
887
888 if ints.otgint() {
889 let otgints = r.gotgint().read();
890 r.gotgint().write_value(otgints); // clear all
891 Self::restore_irqs();
892
893 if otgints.sedet() {
894 trace!("vbus removed");
895 if self.config.vbus_detection {
896 self.disable_all_endpoints();
897 return Poll::Ready(Event::PowerRemoved);
898 }
899 }
900 }
901
625 if ints.usbrst() { 902 if ints.usbrst() {
626 trace!("reset"); 903 trace!("reset");
627 904
@@ -744,7 +1021,19 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
744 1021
745 r.doepctl(ep_addr.index()).modify(|w| { 1022 r.doepctl(ep_addr.index()).modify(|w| {
746 w.set_usbaep(enabled); 1023 w.set_usbaep(enabled);
747 }) 1024 });
1025
1026 // Flush tx fifo
1027 r.grstctl().write(|w| {
1028 w.set_txfflsh(true);
1029 w.set_txfnum(ep_addr.index() as _);
1030 });
1031 loop {
1032 let x = r.grstctl().read();
1033 if !x.txfflsh() {
1034 break;
1035 }
1036 }
748 }); 1037 });
749 1038
750 // Wake `Endpoint::wait_enabled()` 1039 // Wake `Endpoint::wait_enabled()`
@@ -755,13 +1044,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
755 // cancel transfer if active 1044 // cancel transfer if active
756 if !enabled && r.diepctl(ep_addr.index()).read().epena() { 1045 if !enabled && r.diepctl(ep_addr.index()).read().epena() {
757 r.diepctl(ep_addr.index()).modify(|w| { 1046 r.diepctl(ep_addr.index()).modify(|w| {
758 w.set_snak(true); 1047 w.set_snak(true); // set NAK
759 w.set_epdis(true); 1048 w.set_epdis(true);
760 }) 1049 })
761 } 1050 }
762 1051
763 r.diepctl(ep_addr.index()).modify(|w| { 1052 r.diepctl(ep_addr.index()).modify(|w| {
764 w.set_usbaep(enabled); 1053 w.set_usbaep(enabled);
1054 w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
765 }) 1055 })
766 }); 1056 });
767 1057
@@ -773,203 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
773 1063
774 async fn enable(&mut self) { 1064 async fn enable(&mut self) {
775 trace!("enable"); 1065 trace!("enable");
776 1066 // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
777 #[cfg(stm32l4)]
778 {
779 crate::peripherals::PWR::enable();
780 critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true)));
781 }
782
783 #[cfg(stm32f7)]
784 {
785 // Enable ULPI clock if external PHY is used
786 let ulpien = !self.phy_type.internal();
787 critical_section::with(|_| {
788 crate::pac::RCC.ahb1enr().modify(|w| {
789 if T::HIGH_SPEED {
790 w.set_usb_otg_hsulpien(ulpien);
791 } else {
792 w.set_usb_otg_hsen(ulpien);
793 }
794 });
795
796 // Low power mode
797 crate::pac::RCC.ahb1lpenr().modify(|w| {
798 if T::HIGH_SPEED {
799 w.set_usb_otg_hsulpilpen(ulpien);
800 } else {
801 w.set_usb_otg_hslpen(ulpien);
802 }
803 });
804 });
805 }
806
807 #[cfg(stm32h7)]
808 {
809 // If true, VDD33USB is generated by internal regulator from VDD50USB
810 // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo)
811 // TODO: unhardcode
812 let internal_regulator = false;
813
814 // Enable USB power
815 critical_section::with(|_| {
816 crate::pac::PWR.cr3().modify(|w| {
817 w.set_usb33den(true);
818 w.set_usbregen(internal_regulator);
819 })
820 });
821
822 // Wait for USB power to stabilize
823 while !crate::pac::PWR.cr3().read().usb33rdy() {}
824
825 // Use internal 48MHz HSI clock. Should be enabled in RCC by default.
826 critical_section::with(|_| {
827 crate::pac::RCC
828 .d2ccip2r()
829 .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48))
830 });
831
832 // Enable ULPI clock if external PHY is used
833 let ulpien = !self.phy_type.internal();
834 critical_section::with(|_| {
835 crate::pac::RCC.ahb1enr().modify(|w| {
836 if T::HIGH_SPEED {
837 w.set_usb_otg_hs_ulpien(ulpien);
838 } else {
839 w.set_usb_otg_fs_ulpien(ulpien);
840 }
841 });
842 crate::pac::RCC.ahb1lpenr().modify(|w| {
843 if T::HIGH_SPEED {
844 w.set_usb_otg_hs_ulpilpen(ulpien);
845 } else {
846 w.set_usb_otg_fs_ulpilpen(ulpien);
847 }
848 });
849 });
850 }
851
852 #[cfg(stm32u5)]
853 {
854 // Enable USB power
855 critical_section::with(|_| {
856 crate::pac::RCC.ahb3enr().modify(|w| {
857 w.set_pwren(true);
858 });
859 cortex_m::asm::delay(2);
860
861 crate::pac::PWR.svmcr().modify(|w| {
862 w.set_usv(true);
863 w.set_uvmen(true);
864 });
865 });
866
867 // Wait for USB power to stabilize
868 while !crate::pac::PWR.svmsr().read().vddusbrdy() {}
869
870 // Select HSI48 as USB clock source.
871 critical_section::with(|_| {
872 crate::pac::RCC.ccipr1().modify(|w| {
873 w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48);
874 })
875 });
876 }
877
878 <T as RccPeripheral>::enable();
879 <T as RccPeripheral>::reset();
880
881 T::Interrupt::unpend();
882 unsafe { T::Interrupt::enable() };
883
884 let r = T::regs();
885 let core_id = r.cid().read().0;
886 info!("Core id {:08x}", core_id);
887
888 // Wait for AHB ready.
889 while !r.grstctl().read().ahbidl() {}
890
891 // Configure as device.
892 r.gusbcfg().write(|w| {
893 // Force device mode
894 w.set_fdmod(true);
895 // Enable internal full-speed PHY
896 w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed());
897 });
898
899 // Configuring Vbus sense and SOF output
900 match core_id {
901 0x0000_1200 | 0x0000_1100 => {
902 assert!(self.phy_type != PhyType::InternalHighSpeed);
903
904 r.gccfg_v1().modify(|w| {
905 // Enable internal full-speed PHY, logic is inverted
906 w.set_pwrdwn(self.phy_type.internal());
907 });
908
909 // F429-like chips have the GCCFG.NOVBUSSENS bit
910 r.gccfg_v1().modify(|w| {
911 w.set_novbussens(true);
912 w.set_vbusasen(false);
913 w.set_vbusbsen(false);
914 w.set_sofouten(false);
915 });
916 }
917 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => {
918 // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning
919 r.gccfg_v2().modify(|w| {
920 // Enable internal full-speed PHY, logic is inverted
921 w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed());
922 w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed());
923 });
924
925 r.gccfg_v2().modify(|w| {
926 w.set_vbden(false);
927 });
928
929 // Force B-peripheral session
930 r.gotgctl().modify(|w| {
931 w.set_bvaloen(true);
932 w.set_bvaloval(true);
933 });
934 }
935 _ => unimplemented!("Unknown USB core id {:X}", core_id),
936 }
937
938 // Soft disconnect.
939 r.dctl().write(|w| w.set_sdis(true));
940
941 // Set speed.
942 r.dcfg().write(|w| {
943 w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80);
944 w.set_dspd(self.phy_type.to_dspd());
945 });
946
947 // Unmask transfer complete EP interrupt
948 r.diepmsk().write(|w| {
949 w.set_xfrcm(true);
950 });
951
952 // Unmask and clear core interrupts
953 Bus::<T>::restore_irqs();
954 r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF));
955
956 // Unmask global interrupt
957 r.gahbcfg().write(|w| {
958 w.set_gint(true); // unmask global interrupt
959 });
960
961 // Connect
962 r.dctl().write(|w| w.set_sdis(false));
963
964 self.enabled = true;
965 } 1067 }
966 1068
967 async fn disable(&mut self) { 1069 async fn disable(&mut self) {
968 trace!("disable"); 1070 trace!("disable");
969 1071
970 Bus::disable(self); 1072 // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
971 1073 //Bus::disable(self);
972 self.enabled = false;
973 } 1074 }
974 1075
975 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { 1076 async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
@@ -1112,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1112 state.ep_in_wakers[index].register(cx.waker()); 1213 state.ep_in_wakers[index].register(cx.waker());
1113 1214
1114 let diepctl = r.diepctl(index).read(); 1215 let diepctl = r.diepctl(index).read();
1216 let dtxfsts = r.dtxfsts(index).read();
1217 info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
1115 if !diepctl.usbaep() { 1218 if !diepctl.usbaep() {
1219 trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
1116 Poll::Ready(Err(EndpointError::Disabled)) 1220 Poll::Ready(Err(EndpointError::Disabled))
1117 } else if !diepctl.epena() { 1221 } else if !diepctl.epena() {
1222 trace!("write ep={:?} wait for prev: ready", self.info.addr);
1118 Poll::Ready(Ok(())) 1223 Poll::Ready(Ok(()))
1119 } else { 1224 } else {
1225 trace!("write ep={:?} wait for prev: pending", self.info.addr);
1120 Poll::Pending 1226 Poll::Pending
1121 } 1227 }
1122 }) 1228 })
@@ -1141,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
1141 1247
1142 Poll::Pending 1248 Poll::Pending
1143 } else { 1249 } else {
1250 trace!("write ep={:?} wait for fifo: ready", self.info.addr);
1144 Poll::Ready(()) 1251 Poll::Ready(())
1145 } 1252 }
1146 }) 1253 })
diff --git a/embassy-sync/src/pipe.rs b/embassy-sync/src/pipe.rs
index db6ebb08b..13bf4ef01 100644
--- a/embassy-sync/src/pipe.rs
+++ b/embassy-sync/src/pipe.rs
@@ -282,7 +282,7 @@ where
282 /// returns the amount of bytes written. 282 /// returns the amount of bytes written.
283 /// 283 ///
284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full, 284 /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full,
285 /// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that 285 /// this method will wait until it isn't. See [`try_write`](Self::try_write) for a variant that
286 /// returns an error instead of waiting. 286 /// returns an error instead of waiting.
287 /// 287 ///
288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough 288 /// It is not guaranteed that all bytes in the buffer are written, even if there's enough
@@ -319,7 +319,7 @@ where
319 /// returns the amount of bytes read. 319 /// returns the amount of bytes read.
320 /// 320 ///
321 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty, 321 /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty,
322 /// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that 322 /// this method will wait until it isn't. See [`try_read`](Self::try_read) for a variant that
323 /// returns an error instead of waiting. 323 /// returns an error instead of waiting.
324 /// 324 ///
325 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough 325 /// It is not guaranteed that all bytes in the buffer are read, even if there's enough
diff --git a/examples/stm32f4/src/bin/usb_ethernet.rs b/examples/stm32f4/src/bin/usb_ethernet.rs
index 953d99a45..b1f01417c 100644
--- a/examples/stm32f4/src/bin/usb_ethernet.rs
+++ b/examples/stm32f4/src/bin/usb_ethernet.rs
@@ -52,7 +52,9 @@ async fn main(spawner: Spawner) {
52 52
53 // Create the driver, from the HAL. 53 // Create the driver, from the HAL.
54 let ep_out_buffer = &mut make_static!([0; 256])[..]; 54 let ep_out_buffer = &mut make_static!([0; 256])[..];
55 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); 55 let mut config = embassy_stm32::usb_otg::Config::default();
56 config.vbus_detection = true;
57 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
56 58
57 // Create embassy-usb Config 59 // Create embassy-usb Config
58 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 60 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f4/src/bin/usb_serial.rs b/examples/stm32f4/src/bin/usb_serial.rs
index f8f5940a7..4ff6452ef 100644
--- a/examples/stm32f4/src/bin/usb_serial.rs
+++ b/examples/stm32f4/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
29 29
30 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256]; 31 let mut ep_out_buffer = [0u8; 256];
32 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
33 35
34 // Create embassy-usb Config 36 // Create embassy-usb Config
35 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32f7/src/bin/usb_serial.rs b/examples/stm32f7/src/bin/usb_serial.rs
index 763309ce2..a2c76178b 100644
--- a/examples/stm32f7/src/bin/usb_serial.rs
+++ b/examples/stm32f7/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
30 30
31 // Create the driver, from the HAL. 31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256]; 32 let mut ep_out_buffer = [0u8; 256];
33 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
34 36
35 // Create embassy-usb Config 37 // Create embassy-usb Config
36 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32g4/src/bin/usb_serial.rs b/examples/stm32g4/src/bin/usb_serial.rs
index c111a9787..289d0ed86 100644
--- a/examples/stm32g4/src/bin/usb_serial.rs
+++ b/examples/stm32g4/src/bin/usb_serial.rs
@@ -38,7 +38,9 @@ async fn main(_spawner: Spawner) {
38 let p = embassy_stm32::init(config); 38 let p = embassy_stm32::init(config);
39 info!("Hello World!"); 39 info!("Hello World!");
40 40
41 pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); 41 pac::RCC.ccipr().write(|w| {
42 w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK);
43 });
42 44
43 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); 45 let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);
44 46
diff --git a/examples/stm32h7/src/bin/usb_serial.rs b/examples/stm32h7/src/bin/usb_serial.rs
index c622f19f7..97291f60c 100644
--- a/examples/stm32h7/src/bin/usb_serial.rs
+++ b/examples/stm32h7/src/bin/usb_serial.rs
@@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
29 29
30 // Create the driver, from the HAL. 30 // Create the driver, from the HAL.
31 let mut ep_out_buffer = [0u8; 256]; 31 let mut ep_out_buffer = [0u8; 256];
32 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 32 let mut config = embassy_stm32::usb_otg::Config::default();
33 config.vbus_detection = true;
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
33 35
34 // Create embassy-usb Config 36 // Create embassy-usb Config
35 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32l4/src/bin/usb_serial.rs b/examples/stm32l4/src/bin/usb_serial.rs
index 80811a43e..410d6891b 100644
--- a/examples/stm32l4/src/bin/usb_serial.rs
+++ b/examples/stm32l4/src/bin/usb_serial.rs
@@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
30 30
31 // Create the driver, from the HAL. 31 // Create the driver, from the HAL.
32 let mut ep_out_buffer = [0u8; 256]; 32 let mut ep_out_buffer = [0u8; 256];
33 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 33 let mut config = embassy_stm32::usb_otg::Config::default();
34 config.vbus_detection = true;
35 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
34 36
35 // Create embassy-usb Config 37 // Create embassy-usb Config
36 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 38 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
diff --git a/examples/stm32u5/src/bin/usb_serial.rs b/examples/stm32u5/src/bin/usb_serial.rs
index f36daf91b..9e47fb18a 100644
--- a/examples/stm32u5/src/bin/usb_serial.rs
+++ b/examples/stm32u5/src/bin/usb_serial.rs
@@ -31,7 +31,9 @@ async fn main(_spawner: Spawner) {
31 31
32 // Create the driver, from the HAL. 32 // Create the driver, from the HAL.
33 let mut ep_out_buffer = [0u8; 256]; 33 let mut ep_out_buffer = [0u8; 256];
34 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); 34 let mut config = embassy_stm32::usb_otg::Config::default();
35 config.vbus_detection = true;
36 let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
35 37
36 // Create embassy-usb Config 38 // Create embassy-usb Config
37 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); 39 let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);