diff options
| author | Dario Nieuwenhuis <[email protected]> | 2023-06-27 22:39:00 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-06-27 22:39:00 +0000 |
| commit | 9b5d7ec06152e4f5dd036f813605a4bafb7e8621 (patch) | |
| tree | 22564eaf7bf22140a06c36717f124a1e645cf41b | |
| parent | 45561f1622c9d883c8a9fa990c22a8a373d6ce5e (diff) | |
| parent | ed493be869fa653dc14d31060375e17e2469ce11 (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.rs | 1 | ||||
| -rw-r--r-- | embassy-stm32/Cargo.toml | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l0.rs | 4 | ||||
| -rw-r--r-- | embassy-stm32/src/usb/usb.rs | 85 | ||||
| -rw-r--r-- | embassy-stm32/src/usb_otg/usb.rs | 515 | ||||
| -rw-r--r-- | embassy-sync/src/pipe.rs | 4 | ||||
| -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/stm32g4/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 |
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" | |||
| 57 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } | 57 | embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } |
| 58 | critical-section = "1.1" | 58 | critical-section = "1.1" |
| 59 | atomic-polyfill = "1.0.1" | 59 | atomic-polyfill = "1.0.1" |
| 60 | stm32-metapac = "10" | 60 | stm32-metapac = "11" |
| 61 | vcell = "0.1.3" | 61 | vcell = "0.1.3" |
| 62 | bxcan = "0.7.0" | 62 | bxcan = "0.7.0" |
| 63 | nb = "1.0.0" | 63 | nb = "1.0.0" |
| @@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] } | |||
| 74 | [build-dependencies] | 74 | [build-dependencies] |
| 75 | proc-macro2 = "1.0.36" | 75 | proc-macro2 = "1.0.36" |
| 76 | quote = "1.0.15" | 76 | quote = "1.0.15" |
| 77 | stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} | 77 | stm32-metapac = { version = "11", default-features = false, features = ["metadata"]} |
| 78 | 78 | ||
| 79 | [features] | 79 | [features] |
| 80 | default = ["rt"] | 80 | default = ["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 @@ | |||
| 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; | 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; |
| 2 | use crate::pac::RCC; | 2 | use crate::pac::RCC; |
| 3 | #[cfg(crs)] | 3 | #[cfg(crs)] |
| 4 | use crate::pac::{CRS, SYSCFG}; | 4 | use crate::pac::{crs, CRS, SYSCFG}; |
| 5 | use crate::rcc::{set_freqs, Clocks}; | 5 | use crate::rcc::{set_freqs, Clocks}; |
| 6 | use crate::time::Hertz; | 6 | use 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}; | |||
| 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(); |
| @@ -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)] | ||
| 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 | ||
| @@ -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> { | |||
| 612 | 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> { |
| 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); |
