diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-06-27 08:42:51 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2023-06-27 12:52:37 +0200 |
| commit | 219ef5b37a1dff5f6e770da252ec010d55c43257 (patch) | |
| tree | d90597e01633865ea810a55266c90a5d56d555ea | |
| parent | a2d1e7f02ca8d94c755ced56f1db11646ac2aa72 (diff) | |
stm32/otg: add VBUS detection.
Fixes #1442.
| -rw-r--r-- | embassy-stm32/src/usb_otg/usb.rs | 479 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_ethernet.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | examples/stm32f7/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | examples/stm32h7/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/usb_serial.rs | 4 | ||||
| -rw-r--r-- | examples/stm32u5/src/bin/usb_serial.rs | 4 |
7 files changed, 297 insertions, 206 deletions
diff --git a/embassy-stm32/src/usb_otg/usb.rs b/embassy-stm32/src/usb_otg/usb.rs index b2f7eb852..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}; | |||
| 6 | use embassy_hal_common::{into_ref, Peripheral}; | 6 | use embassy_hal_common::{into_ref, Peripheral}; |
| 7 | use embassy_sync::waitqueue::AtomicWaker; | 7 | use embassy_sync::waitqueue::AtomicWaker; |
| 8 | use embassy_usb_driver::{ | 8 | use 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 | }; |
| 12 | use futures::future::poll_fn; | 12 | use 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(); |
| @@ -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)] | ||
| 261 | pub 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 | |||
| 279 | impl Default for Config { | ||
| 280 | fn default() -> Self { | ||
| 281 | Self { vbus_detection: true } | ||
| 282 | } | ||
| 283 | } | ||
| 284 | |||
| 259 | pub struct Driver<'d, T: Instance> { | 285 | pub 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 | ||
| 483 | pub struct Bus<'d, T: Instance> { | 515 | pub 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 | ||
| 491 | impl<'d, T: Instance> Bus<'d, T> { | 524 | impl<'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 | ||
| 505 | impl<'d, T: Instance> Bus<'d, T> { | 540 | impl<'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 | ||
| @@ -613,6 +837,13 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 613 | }); | 837 | }); |
| 614 | } | 838 | } |
| 615 | 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 | |||
| 616 | fn disable(&mut self) { | 847 | fn disable(&mut self) { |
| 617 | T::Interrupt::disable(); | 848 | T::Interrupt::disable(); |
| 618 | 849 | ||
| @@ -627,9 +858,14 @@ impl<'d, T: Instance> Bus<'d, T> { | |||
| 627 | impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | 858 | impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { |
| 628 | async fn poll(&mut self) -> Event { | 859 | async fn poll(&mut self) -> Event { |
| 629 | poll_fn(move |cx| { | 860 | poll_fn(move |cx| { |
| 630 | // TODO: implement VBUS detection | 861 | if !self.inited { |
| 631 | if !self.enabled { | 862 | self.init(); |
| 632 | 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 | } | ||
| 633 | } | 869 | } |
| 634 | 870 | ||
| 635 | let r = T::regs(); | 871 | let r = T::regs(); |
| @@ -637,6 +873,32 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 637 | T::state().bus_waker.register(cx.waker()); | 873 | T::state().bus_waker.register(cx.waker()); |
| 638 | 874 | ||
| 639 | 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 | |||
| 640 | if ints.usbrst() { | 902 | if ints.usbrst() { |
| 641 | trace!("reset"); | 903 | trace!("reset"); |
| 642 | 904 | ||
| @@ -801,203 +1063,14 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> { | |||
| 801 | 1063 | ||
| 802 | async fn enable(&mut self) { | 1064 | async fn enable(&mut self) { |
| 803 | trace!("enable"); | 1065 | trace!("enable"); |
| 804 | 1066 | // TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb | |
| 805 | #[cfg(stm32l4)] | ||
| 806 | { | ||
| 807 | crate::peripherals::PWR::enable(); | ||
| 808 | critical_section::with(|_| crate::pac::PWR.cr2().modify(|w| w.set_usv(true))); | ||
| 809 | } | ||
| 810 | |||
| 811 | #[cfg(stm32f7)] | ||
| 812 | { | ||
| 813 | // Enable ULPI clock if external PHY is used | ||
| 814 | let ulpien = !self.phy_type.internal(); | ||
| 815 | critical_section::with(|_| { | ||
| 816 | crate::pac::RCC.ahb1enr().modify(|w| { | ||
| 817 | if T::HIGH_SPEED { | ||
| 818 | w.set_usb_otg_hsulpien(ulpien); | ||
| 819 | } else { | ||
| 820 | w.set_usb_otg_hsen(ulpien); | ||
| 821 | } | ||
| 822 | }); | ||
| 823 | |||
| 824 | // Low power mode | ||
| 825 | crate::pac::RCC.ahb1lpenr().modify(|w| { | ||
| 826 | if T::HIGH_SPEED { | ||
| 827 | w.set_usb_otg_hsulpilpen(ulpien); | ||
| 828 | } else { | ||
| 829 | w.set_usb_otg_hslpen(ulpien); | ||
| 830 | } | ||
| 831 | }); | ||
| 832 | }); | ||
| 833 | } | ||
| 834 | |||
| 835 | #[cfg(stm32h7)] | ||
| 836 | { | ||
| 837 | // If true, VDD33USB is generated by internal regulator from VDD50USB | ||
| 838 | // If false, VDD33USB and VDD50USB must be suplied directly with 3.3V (default on nucleo) | ||
| 839 | // TODO: unhardcode | ||
| 840 | let internal_regulator = false; | ||
| 841 | |||
| 842 | // Enable USB power | ||
| 843 | critical_section::with(|_| { | ||
| 844 | crate::pac::PWR.cr3().modify(|w| { | ||
| 845 | w.set_usb33den(true); | ||
| 846 | w.set_usbregen(internal_regulator); | ||
| 847 | }) | ||
| 848 | }); | ||
| 849 | |||
| 850 | // Wait for USB power to stabilize | ||
| 851 | while !crate::pac::PWR.cr3().read().usb33rdy() {} | ||
| 852 | |||
| 853 | // Use internal 48MHz HSI clock. Should be enabled in RCC by default. | ||
| 854 | critical_section::with(|_| { | ||
| 855 | crate::pac::RCC | ||
| 856 | .d2ccip2r() | ||
| 857 | .modify(|w| w.set_usbsel(crate::pac::rcc::vals::Usbsel::HSI48)) | ||
| 858 | }); | ||
| 859 | |||
| 860 | // Enable ULPI clock if external PHY is used | ||
| 861 | let ulpien = !self.phy_type.internal(); | ||
| 862 | critical_section::with(|_| { | ||
| 863 | crate::pac::RCC.ahb1enr().modify(|w| { | ||
| 864 | if T::HIGH_SPEED { | ||
| 865 | w.set_usb_otg_hs_ulpien(ulpien); | ||
| 866 | } else { | ||
| 867 | w.set_usb_otg_fs_ulpien(ulpien); | ||
| 868 | } | ||
| 869 | }); | ||
| 870 | crate::pac::RCC.ahb1lpenr().modify(|w| { | ||
| 871 | if T::HIGH_SPEED { | ||
| 872 | w.set_usb_otg_hs_ulpilpen(ulpien); | ||
| 873 | } else { | ||
| 874 | w.set_usb_otg_fs_ulpilpen(ulpien); | ||
| 875 | } | ||
| 876 | }); | ||
| 877 | }); | ||
| 878 | } | ||
| 879 | |||
| 880 | #[cfg(stm32u5)] | ||
| 881 | { | ||
| 882 | // Enable USB power | ||
| 883 | critical_section::with(|_| { | ||
| 884 | crate::pac::RCC.ahb3enr().modify(|w| { | ||
| 885 | w.set_pwren(true); | ||
| 886 | }); | ||
| 887 | cortex_m::asm::delay(2); | ||
| 888 | |||
| 889 | crate::pac::PWR.svmcr().modify(|w| { | ||
| 890 | w.set_usv(true); | ||
| 891 | w.set_uvmen(true); | ||
| 892 | }); | ||
| 893 | }); | ||
| 894 | |||
| 895 | // Wait for USB power to stabilize | ||
| 896 | while !crate::pac::PWR.svmsr().read().vddusbrdy() {} | ||
| 897 | |||
| 898 | // Select HSI48 as USB clock source. | ||
| 899 | critical_section::with(|_| { | ||
| 900 | crate::pac::RCC.ccipr1().modify(|w| { | ||
| 901 | w.set_iclksel(crate::pac::rcc::vals::Iclksel::HSI48); | ||
| 902 | }) | ||
| 903 | }); | ||
| 904 | } | ||
| 905 | |||
| 906 | <T as RccPeripheral>::enable(); | ||
| 907 | <T as RccPeripheral>::reset(); | ||
| 908 | |||
| 909 | T::Interrupt::unpend(); | ||
| 910 | unsafe { T::Interrupt::enable() }; | ||
| 911 | |||
| 912 | let r = T::regs(); | ||
| 913 | let core_id = r.cid().read().0; | ||
| 914 | info!("Core id {:08x}", core_id); | ||
| 915 | |||
| 916 | // Wait for AHB ready. | ||
| 917 | while !r.grstctl().read().ahbidl() {} | ||
| 918 | |||
| 919 | // Configure as device. | ||
| 920 | r.gusbcfg().write(|w| { | ||
| 921 | // Force device mode | ||
| 922 | w.set_fdmod(true); | ||
| 923 | // Enable internal full-speed PHY | ||
| 924 | w.set_physel(self.phy_type.internal() && !self.phy_type.high_speed()); | ||
| 925 | }); | ||
| 926 | |||
| 927 | // Configuring Vbus sense and SOF output | ||
| 928 | match core_id { | ||
| 929 | 0x0000_1200 | 0x0000_1100 => { | ||
| 930 | assert!(self.phy_type != PhyType::InternalHighSpeed); | ||
| 931 | |||
| 932 | r.gccfg_v1().modify(|w| { | ||
| 933 | // Enable internal full-speed PHY, logic is inverted | ||
| 934 | w.set_pwrdwn(self.phy_type.internal()); | ||
| 935 | }); | ||
| 936 | |||
| 937 | // F429-like chips have the GCCFG.NOVBUSSENS bit | ||
| 938 | r.gccfg_v1().modify(|w| { | ||
| 939 | w.set_novbussens(true); | ||
| 940 | w.set_vbusasen(false); | ||
| 941 | w.set_vbusbsen(false); | ||
| 942 | w.set_sofouten(false); | ||
| 943 | }); | ||
| 944 | } | ||
| 945 | 0x0000_2000 | 0x0000_2100 | 0x0000_2300 | 0x0000_3000 | 0x0000_3100 => { | ||
| 946 | // F446-like chips have the GCCFG.VBDEN bit with the opposite meaning | ||
| 947 | r.gccfg_v2().modify(|w| { | ||
| 948 | // Enable internal full-speed PHY, logic is inverted | ||
| 949 | w.set_pwrdwn(self.phy_type.internal() && !self.phy_type.high_speed()); | ||
| 950 | w.set_phyhsen(self.phy_type.internal() && self.phy_type.high_speed()); | ||
| 951 | }); | ||
| 952 | |||
| 953 | r.gccfg_v2().modify(|w| { | ||
| 954 | w.set_vbden(false); | ||
| 955 | }); | ||
| 956 | |||
| 957 | // Force B-peripheral session | ||
| 958 | r.gotgctl().modify(|w| { | ||
| 959 | w.set_bvaloen(true); | ||
| 960 | w.set_bvaloval(true); | ||
| 961 | }); | ||
| 962 | } | ||
| 963 | _ => unimplemented!("Unknown USB core id {:X}", core_id), | ||
| 964 | } | ||
| 965 | |||
| 966 | // Soft disconnect. | ||
| 967 | r.dctl().write(|w| w.set_sdis(true)); | ||
| 968 | |||
| 969 | // Set speed. | ||
| 970 | r.dcfg().write(|w| { | ||
| 971 | w.set_pfivl(vals::Pfivl::FRAME_INTERVAL_80); | ||
| 972 | w.set_dspd(self.phy_type.to_dspd()); | ||
| 973 | }); | ||
| 974 | |||
| 975 | // Unmask transfer complete EP interrupt | ||
| 976 | r.diepmsk().write(|w| { | ||
| 977 | w.set_xfrcm(true); | ||
| 978 | }); | ||
| 979 | |||
| 980 | // Unmask and clear core interrupts | ||
| 981 | Bus::<T>::restore_irqs(); | ||
| 982 | r.gintsts().write_value(regs::Gintsts(0xFFFF_FFFF)); | ||
| 983 | |||
| 984 | // Unmask global interrupt | ||
| 985 | r.gahbcfg().write(|w| { | ||
| 986 | w.set_gint(true); // unmask global interrupt | ||
| 987 | }); | ||
| 988 | |||
| 989 | // Connect | ||
| 990 | r.dctl().write(|w| w.set_sdis(false)); | ||
| 991 | |||
| 992 | self.enabled = true; | ||
| 993 | } | 1067 | } |
| 994 | 1068 | ||
| 995 | async fn disable(&mut self) { | 1069 | async fn disable(&mut self) { |
| 996 | trace!("disable"); | 1070 | trace!("disable"); |
| 997 | 1071 | ||
| 998 | Bus::disable(self); | 1072 | // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb |
| 999 | 1073 | //Bus::disable(self); | |
| 1000 | self.enabled = false; | ||
| 1001 | } | 1074 | } |
| 1002 | 1075 | ||
| 1003 | async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { | 1076 | 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> { | |||
| 1140 | state.ep_in_wakers[index].register(cx.waker()); | 1213 | state.ep_in_wakers[index].register(cx.waker()); |
| 1141 | 1214 | ||
| 1142 | 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); | ||
| 1143 | if !diepctl.usbaep() { | 1218 | if !diepctl.usbaep() { |
| 1219 | trace!("write ep={:?} wait for prev: error disabled", self.info.addr); | ||
| 1144 | Poll::Ready(Err(EndpointError::Disabled)) | 1220 | Poll::Ready(Err(EndpointError::Disabled)) |
| 1145 | } else if !diepctl.epena() { | 1221 | } else if !diepctl.epena() { |
| 1222 | trace!("write ep={:?} wait for prev: ready", self.info.addr); | ||
| 1146 | Poll::Ready(Ok(())) | 1223 | Poll::Ready(Ok(())) |
| 1147 | } else { | 1224 | } else { |
| 1225 | trace!("write ep={:?} wait for prev: pending", self.info.addr); | ||
| 1148 | Poll::Pending | 1226 | Poll::Pending |
| 1149 | } | 1227 | } |
| 1150 | }) | 1228 | }) |
| @@ -1169,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> { | |||
| 1169 | 1247 | ||
| 1170 | Poll::Pending | 1248 | Poll::Pending |
| 1171 | } else { | 1249 | } else { |
| 1250 | trace!("write ep={:?} wait for fifo: ready", self.info.addr); | ||
| 1172 | Poll::Ready(()) | 1251 | Poll::Ready(()) |
| 1173 | } | 1252 | } |
| 1174 | }) | 1253 | }) |
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/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); |
