Merge pull request #1589 from embassy-rs/otg-fixes

stm32/otg: implement VBUS detection, misc fixes so plug/unplug works.
This commit is contained in:
Dario Nieuwenhuis 2023-06-27 22:39:00 +00:00 committed by GitHub
commit 9b5d7ec061
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 469 additions and 346 deletions

View File

@ -353,6 +353,7 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
poll_fn(move |cx| { poll_fn(move |cx| {
BUS_WAKER.register(cx.waker()); BUS_WAKER.register(cx.waker());
// TODO: implement VBUS detection.
if !self.inited { if !self.inited {
self.inited = true; self.inited = true;
return Poll::Ready(Event::PowerDetected); return Poll::Ready(Event::PowerDetected);

View File

@ -57,7 +57,7 @@ sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"
stm32-metapac = "10" stm32-metapac = "11"
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -74,7 +74,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { version = "10", default-features = false, features = ["metadata"]} stm32-metapac = { version = "11", default-features = false, features = ["metadata"]}
[features] [features]
default = ["rt"] default = ["rt"]

View File

@ -1,7 +1,7 @@
use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw}; use crate::pac::rcc::vals::{Hpre, Msirange, Plldiv, Pllmul, Pllsrc, Ppre, Sw};
use crate::pac::RCC; use crate::pac::RCC;
#[cfg(crs)] #[cfg(crs)]
use crate::pac::{CRS, SYSCFG}; use crate::pac::{crs, CRS, SYSCFG};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -338,7 +338,7 @@ pub(crate) unsafe fn init(config: Config) {
CRS.cfgr().write(|w| CRS.cfgr().write(|w|
// Select LSE as synchronization source // Select LSE as synchronization source
w.set_syncsrc(0b01)); w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| { CRS.cr().modify(|w| {
w.set_autotrimen(true); w.set_autotrimen(true);
w.set_cen(true); w.set_cen(true);

View File

@ -480,56 +480,57 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
poll_fn(move |cx| { poll_fn(move |cx| {
BUS_WAKER.register(cx.waker()); BUS_WAKER.register(cx.waker());
if self.inited { // TODO: implement VBUS detection.
let regs = T::regs(); if !self.inited {
if IRQ_RESUME.load(Ordering::Acquire) {
IRQ_RESUME.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Resume);
}
if IRQ_RESET.load(Ordering::Acquire) {
IRQ_RESET.store(false, Ordering::Relaxed);
trace!("RESET");
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(0);
});
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat::NAK);
w.set_stat_tx(Stat::NAK);
});
for i in 1..EP_COUNT {
regs.epr(i).write(|w| {
w.set_ea(i as _);
w.set_ep_type(self.ep_types[i - 1]);
})
}
for w in &EP_IN_WAKERS {
w.wake()
}
for w in &EP_OUT_WAKERS {
w.wake()
}
return Poll::Ready(Event::Reset);
}
if IRQ_SUSPEND.load(Ordering::Acquire) {
IRQ_SUSPEND.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Suspend);
}
Poll::Pending
} else {
self.inited = true; self.inited = true;
return Poll::Ready(Event::PowerDetected); return Poll::Ready(Event::PowerDetected);
} }
let regs = T::regs();
if IRQ_RESUME.load(Ordering::Acquire) {
IRQ_RESUME.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Resume);
}
if IRQ_RESET.load(Ordering::Acquire) {
IRQ_RESET.store(false, Ordering::Relaxed);
trace!("RESET");
regs.daddr().write(|w| {
w.set_ef(true);
w.set_add(0);
});
regs.epr(0).write(|w| {
w.set_ep_type(EpType::CONTROL);
w.set_stat_rx(Stat::NAK);
w.set_stat_tx(Stat::NAK);
});
for i in 1..EP_COUNT {
regs.epr(i).write(|w| {
w.set_ea(i as _);
w.set_ep_type(self.ep_types[i - 1]);
})
}
for w in &EP_IN_WAKERS {
w.wake()
}
for w in &EP_OUT_WAKERS {
w.wake()
}
return Poll::Ready(Event::Reset);
}
if IRQ_SUSPEND.load(Ordering::Acquire) {
IRQ_SUSPEND.store(false, Ordering::Relaxed);
return Poll::Ready(Event::Suspend);
}
Poll::Pending
}) })
.await .await
} }

View File

@ -6,8 +6,8 @@ use atomic_polyfill::{AtomicBool, AtomicU16, Ordering};
use embassy_hal_common::{into_ref, Peripheral}; use embassy_hal_common::{into_ref, Peripheral};
use embassy_sync::waitqueue::AtomicWaker; use embassy_sync::waitqueue::AtomicWaker;
use embassy_usb_driver::{ use embassy_usb_driver::{
self, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo, EndpointOut, self, Bus as _, Direction, EndpointAddress, EndpointAllocError, EndpointError, EndpointIn, EndpointInfo,
EndpointType, Event, Unsupported, EndpointOut, EndpointType, Event, Unsupported,
}; };
use futures::future::poll_fn; use futures::future::poll_fn;
@ -31,7 +31,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
let state = T::state(); let state = T::state();
let ints = r.gintsts().read(); let ints = r.gintsts().read();
if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() { if ints.wkupint() || ints.usbsusp() || ints.usbrst() || ints.enumdne() || ints.otgint() || ints.srqint() {
// Mask interrupts and notify `Bus` to process them // Mask interrupts and notify `Bus` to process them
r.gintmsk().write(|_| {}); r.gintmsk().write(|_| {});
T::state().bus_waker.wake(); T::state().bus_waker.wake();
@ -124,7 +124,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} }
state.ep_in_wakers[ep_num].wake(); state.ep_in_wakers[ep_num].wake();
trace!("in ep={} irq val={:b}", ep_num, ep_ints.0); trace!("in ep={} irq val={:08x}", ep_num, ep_ints.0);
} }
ep_mask >>= 1; ep_mask >>= 1;
@ -144,7 +144,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
// // clear all // // clear all
// r.doepint(ep_num).write_value(ep_ints); // r.doepint(ep_num).write_value(ep_ints);
// state.ep_out_wakers[ep_num].wake(); // state.ep_out_wakers[ep_num].wake();
// trace!("out ep={} irq val={=u32:b}", ep_num, ep_ints.0); // trace!("out ep={} irq val={:08x}", ep_num, ep_ints.0);
// } // }
// ep_mask >>= 1; // ep_mask >>= 1;
@ -256,7 +256,34 @@ struct EndpointData {
fifo_size_words: u16, fifo_size_words: u16,
} }
#[non_exhaustive]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Config {
/// Enable VBUS detection.
///
/// The USB spec requires USB devices monitor for USB cable plug/unplug and react accordingly.
/// This is done by checkihg whether there is 5V on the VBUS pin or not.
///
/// If your device is bus-powered (powers itself from the USB host via VBUS), then this is optional.
/// (if there's no power in VBUS your device would be off anyway, so it's fine to always assume
/// there's power in VBUS, i.e. the USB cable is always plugged in.)
///
/// If your device is self-powered (i.e. it gets power from a source other than the USB cable, and
/// therefore can stay powered through USB cable plug/unplug) then you MUST set this to true.
///
/// If you set this to true, you must connect VBUS to PA9 for FS, PB13 for HS, possibly with a
/// voltage divider. See ST application note AN4879 and the reference manual for more details.
pub vbus_detection: bool,
}
impl Default for Config {
fn default() -> Self {
Self { vbus_detection: true }
}
}
pub struct Driver<'d, T: Instance> { pub struct Driver<'d, T: Instance> {
config: Config,
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
ep_in: [Option<EndpointData>; MAX_EP_COUNT], ep_in: [Option<EndpointData>; MAX_EP_COUNT],
ep_out: [Option<EndpointData>; MAX_EP_COUNT], ep_out: [Option<EndpointData>; MAX_EP_COUNT],
@ -279,6 +306,7 @@ impl<'d, T: Instance> Driver<'d, T> {
dp: impl Peripheral<P = impl DpPin<T>> + 'd, dp: impl Peripheral<P = impl DpPin<T>> + 'd,
dm: impl Peripheral<P = impl DmPin<T>> + 'd, dm: impl Peripheral<P = impl DmPin<T>> + 'd,
ep_out_buffer: &'d mut [u8], ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self { ) -> Self {
into_ref!(dp, dm); into_ref!(dp, dm);
@ -286,6 +314,7 @@ impl<'d, T: Instance> Driver<'d, T> {
dm.set_as_af(dm.af_num(), AFType::OutputPushPull); dm.set_as_af(dm.af_num(), AFType::OutputPushPull);
Self { Self {
config,
phantom: PhantomData, phantom: PhantomData,
ep_in: [None; MAX_EP_COUNT], ep_in: [None; MAX_EP_COUNT],
ep_out: [None; MAX_EP_COUNT], ep_out: [None; MAX_EP_COUNT],
@ -318,6 +347,7 @@ impl<'d, T: Instance> Driver<'d, T> {
ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd, ulpi_d6: impl Peripheral<P = impl UlpiD6Pin<T>> + 'd,
ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd, ulpi_d7: impl Peripheral<P = impl UlpiD7Pin<T>> + 'd,
ep_out_buffer: &'d mut [u8], ep_out_buffer: &'d mut [u8],
config: Config,
) -> Self { ) -> Self {
assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB"); assert!(T::HIGH_SPEED == true, "Peripheral is not capable of high-speed USB");
@ -327,6 +357,7 @@ impl<'d, T: Instance> Driver<'d, T> {
); );
Self { Self {
config,
phantom: PhantomData, phantom: PhantomData,
ep_in: [None; MAX_EP_COUNT], ep_in: [None; MAX_EP_COUNT],
ep_out: [None; MAX_EP_COUNT], ep_out: [None; MAX_EP_COUNT],
@ -464,11 +495,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
( (
Bus { Bus {
config: self.config,
phantom: PhantomData, phantom: PhantomData,
ep_in: self.ep_in, ep_in: self.ep_in,
ep_out: self.ep_out, ep_out: self.ep_out,
phy_type: self.phy_type, phy_type: self.phy_type,
enabled: false, inited: false,
}, },
ControlPipe { ControlPipe {
_phantom: PhantomData, _phantom: PhantomData,
@ -481,11 +513,12 @@ impl<'d, T: Instance> embassy_usb_driver::Driver<'d> for Driver<'d, T> {
} }
pub struct Bus<'d, T: Instance> { pub struct Bus<'d, T: Instance> {
config: Config,
phantom: PhantomData<&'d mut T>, phantom: PhantomData<&'d mut T>,
ep_in: [Option<EndpointData>; MAX_EP_COUNT], ep_in: [Option<EndpointData>; MAX_EP_COUNT],
ep_out: [Option<EndpointData>; MAX_EP_COUNT], ep_out: [Option<EndpointData>; MAX_EP_COUNT],
phy_type: PhyType, phy_type: PhyType,
enabled: bool, inited: bool,
} }
impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> Bus<'d, T> {
@ -498,282 +531,14 @@ impl<'d, T: Instance> Bus<'d, T> {
w.set_iepint(true); w.set_iepint(true);
w.set_oepint(true); w.set_oepint(true);
w.set_rxflvlm(true); w.set_rxflvlm(true);
w.set_srqim(true);
w.set_otgint(true);
}); });
} }
} }
impl<'d, T: Instance> Bus<'d, T> { impl<'d, T: Instance> Bus<'d, T> {
fn init_fifo(&mut self) { fn init(&mut self) {
trace!("init_fifo");
let r = T::regs();
// Configure RX fifo size. All endpoints share the same FIFO area.
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
trace!("configuring rx fifo size={}", rx_fifo_size_words);
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
// Configure TX (USB in direction) fifo size for each endpoint
let mut fifo_top = rx_fifo_size_words;
for i in 0..T::ENDPOINT_COUNT {
if let Some(ep) = self.ep_in[i] {
trace!(
"configuring tx fifo ep={}, offset={}, size={}",
i,
fifo_top,
ep.fifo_size_words
);
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top);
});
fifo_top += ep.fifo_size_words;
}
}
assert!(
fifo_top <= T::FIFO_DEPTH_WORDS,
"FIFO allocations exceeded maximum capacity"
);
}
fn configure_endpoints(&mut self) {
trace!("configure_endpoints");
let r = T::regs();
// Configure IN endpoints
for (index, ep) in self.ep_in.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.diepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
}
});
});
}
}
// Configure OUT endpoints
for (index, ep) in self.ep_out.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.doepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
}
});
r.doeptsiz(index).modify(|w| {
w.set_xfrsiz(ep.max_packet_size as _);
if index == 0 {
w.set_rxdpid_stupcnt(1);
} else {
w.set_pktcnt(1);
}
});
});
}
}
// Enable IRQs for allocated endpoints
r.daintmsk().modify(|w| {
w.set_iepm(ep_irq_mask(&self.ep_in));
// OUT interrupts not used, handled in RXFLVL
// w.set_oepm(ep_irq_mask(&self.ep_out));
});
}
fn disable(&mut self) {
T::Interrupt::disable();
<T as RccPeripheral>::disable();
#[cfg(stm32l4)]
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
// Cannot disable PWR, because other peripherals might be using it
}
}
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| {
// TODO: implement VBUS detection
if !self.enabled {
return Poll::Ready(Event::PowerDetected);
}
let r = T::regs();
T::state().bus_waker.register(cx.waker());
let ints = r.gintsts().read();
if ints.usbrst() {
trace!("reset");
self.init_fifo();
self.configure_endpoints();
// Reset address
critical_section::with(|_| {
r.dcfg().modify(|w| {
w.set_dad(0);
});
});
r.gintsts().write(|w| w.set_usbrst(true)); // clear
Self::restore_irqs();
}
if ints.enumdne() {
trace!("enumdne");
let speed = r.dsts().read().enumspd();
trace!(" speed={}", speed.0);
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
});
r.gintsts().write(|w| w.set_enumdne(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Reset);
}
if ints.usbsusp() {
trace!("suspend");
r.gintsts().write(|w| w.set_usbsusp(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Suspend);
}
if ints.wkupint() {
trace!("resume");
r.gintsts().write(|w| w.set_wkupint(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Resume);
}
Poll::Pending
})
.await
}
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
regs.doepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
regs.diepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_is_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
}
}
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_enabled index {} out of range",
ep_addr.index()
);
let r = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
r.doepctl(ep_addr.index()).modify(|w| {
w.set_snak(true);
w.set_epdis(true);
})
}
r.doepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
})
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
r.diepctl(ep_addr.index()).modify(|w| {
w.set_snak(true);
w.set_epdis(true);
})
}
r.diepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
})
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
async fn enable(&mut self) {
trace!("enable");
#[cfg(stm32l4)] #[cfg(stm32l4)]
{ {
crate::peripherals::PWR::enable(); crate::peripherals::PWR::enable();
@ -908,9 +673,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
// F429-like chips have the GCCFG.NOVBUSSENS bit // F429-like chips have the GCCFG.NOVBUSSENS bit
r.gccfg_v1().modify(|w| { r.gccfg_v1().modify(|w| {
w.set_novbussens(true); w.set_novbussens(!self.config.vbus_detection);
w.set_vbusasen(false); w.set_vbusasen(false);
w.set_vbusbsen(false); w.set_vbusbsen(self.config.vbus_detection);
w.set_sofouten(false); w.set_sofouten(false);
}); });
} }
@ -923,12 +688,12 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
}); });
r.gccfg_v2().modify(|w| { r.gccfg_v2().modify(|w| {
w.set_vbden(false); w.set_vbden(self.config.vbus_detection);
}); });
// Force B-peripheral session // Force B-peripheral session
r.gotgctl().modify(|w| { r.gotgctl().modify(|w| {
w.set_bvaloen(true); w.set_bvaloen(!self.config.vbus_detection);
w.set_bvaloval(true); w.set_bvaloval(true);
}); });
} }
@ -960,16 +725,352 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
// Connect // Connect
r.dctl().write(|w| w.set_sdis(false)); r.dctl().write(|w| w.set_sdis(false));
}
self.enabled = true; fn init_fifo(&mut self) {
trace!("init_fifo");
let r = T::regs();
// Configure RX fifo size. All endpoints share the same FIFO area.
let rx_fifo_size_words = RX_FIFO_EXTRA_SIZE_WORDS + ep_fifo_size(&self.ep_out);
trace!("configuring rx fifo size={}", rx_fifo_size_words);
r.grxfsiz().modify(|w| w.set_rxfd(rx_fifo_size_words));
// Configure TX (USB in direction) fifo size for each endpoint
let mut fifo_top = rx_fifo_size_words;
for i in 0..T::ENDPOINT_COUNT {
if let Some(ep) = self.ep_in[i] {
trace!(
"configuring tx fifo ep={}, offset={}, size={}",
i,
fifo_top,
ep.fifo_size_words
);
let dieptxf = if i == 0 { r.dieptxf0() } else { r.dieptxf(i - 1) };
dieptxf.write(|w| {
w.set_fd(ep.fifo_size_words);
w.set_sa(fifo_top);
});
fifo_top += ep.fifo_size_words;
}
}
assert!(
fifo_top <= T::FIFO_DEPTH_WORDS,
"FIFO allocations exceeded maximum capacity"
);
// Flush fifos
r.grstctl().write(|w| {
w.set_rxfflsh(true);
w.set_txfflsh(true);
w.set_txfnum(0x10);
});
loop {
let x = r.grstctl().read();
if !x.rxfflsh() && !x.txfflsh() {
break;
}
}
}
fn configure_endpoints(&mut self) {
trace!("configure_endpoints");
let r = T::regs();
// Configure IN endpoints
for (index, ep) in self.ep_in.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.diepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
w.set_txfnum(index as _);
w.set_snak(true);
}
});
});
}
}
// Configure OUT endpoints
for (index, ep) in self.ep_out.iter().enumerate() {
if let Some(ep) = ep {
critical_section::with(|_| {
r.doepctl(index).write(|w| {
if index == 0 {
w.set_mpsiz(ep0_mpsiz(ep.max_packet_size));
} else {
w.set_mpsiz(ep.max_packet_size);
w.set_eptyp(to_eptyp(ep.ep_type));
w.set_sd0pid_sevnfrm(true);
}
});
r.doeptsiz(index).modify(|w| {
w.set_xfrsiz(ep.max_packet_size as _);
if index == 0 {
w.set_rxdpid_stupcnt(1);
} else {
w.set_pktcnt(1);
}
});
});
}
}
// Enable IRQs for allocated endpoints
r.daintmsk().modify(|w| {
w.set_iepm(ep_irq_mask(&self.ep_in));
// OUT interrupts not used, handled in RXFLVL
// w.set_oepm(ep_irq_mask(&self.ep_out));
});
}
fn disable_all_endpoints(&mut self) {
for i in 0..T::ENDPOINT_COUNT {
self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::In), false);
self.endpoint_set_enabled(EndpointAddress::from_parts(i, Direction::Out), false);
}
}
fn disable(&mut self) {
T::Interrupt::disable();
<T as RccPeripheral>::disable();
#[cfg(stm32l4)]
crate::pac::PWR.cr2().modify(|w| w.set_usv(false));
// Cannot disable PWR, because other peripherals might be using it
}
}
impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
async fn poll(&mut self) -> Event {
poll_fn(move |cx| {
if !self.inited {
self.init();
self.inited = true;
// If no vbus detection, just return a single PowerDetected event at startup.
if !self.config.vbus_detection {
return Poll::Ready(Event::PowerDetected);
}
}
let r = T::regs();
T::state().bus_waker.register(cx.waker());
let ints = r.gintsts().read();
if ints.srqint() {
trace!("vbus detected");
r.gintsts().write(|w| w.set_srqint(true)); // clear
Self::restore_irqs();
if self.config.vbus_detection {
return Poll::Ready(Event::PowerDetected);
}
}
if ints.otgint() {
let otgints = r.gotgint().read();
r.gotgint().write_value(otgints); // clear all
Self::restore_irqs();
if otgints.sedet() {
trace!("vbus removed");
if self.config.vbus_detection {
self.disable_all_endpoints();
return Poll::Ready(Event::PowerRemoved);
}
}
}
if ints.usbrst() {
trace!("reset");
self.init_fifo();
self.configure_endpoints();
// Reset address
critical_section::with(|_| {
r.dcfg().modify(|w| {
w.set_dad(0);
});
});
r.gintsts().write(|w| w.set_usbrst(true)); // clear
Self::restore_irqs();
}
if ints.enumdne() {
trace!("enumdne");
let speed = r.dsts().read().enumspd();
trace!(" speed={}", speed.0);
r.gusbcfg().modify(|w| {
w.set_trdt(calculate_trdt(speed, T::frequency()));
});
r.gintsts().write(|w| w.set_enumdne(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Reset);
}
if ints.usbsusp() {
trace!("suspend");
r.gintsts().write(|w| w.set_usbsusp(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Suspend);
}
if ints.wkupint() {
trace!("resume");
r.gintsts().write(|w| w.set_wkupint(true)); // clear
Self::restore_irqs();
return Poll::Ready(Event::Resume);
}
Poll::Pending
})
.await
}
fn endpoint_set_stalled(&mut self, ep_addr: EndpointAddress, stalled: bool) {
trace!("endpoint_set_stalled ep={:?} en={}", ep_addr, stalled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
regs.doepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
regs.diepctl(ep_addr.index()).modify(|w| {
w.set_stall(stalled);
});
});
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
fn endpoint_is_stalled(&mut self, ep_addr: EndpointAddress) -> bool {
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_is_stalled index {} out of range",
ep_addr.index()
);
let regs = T::regs();
match ep_addr.direction() {
Direction::Out => regs.doepctl(ep_addr.index()).read().stall(),
Direction::In => regs.diepctl(ep_addr.index()).read().stall(),
}
}
fn endpoint_set_enabled(&mut self, ep_addr: EndpointAddress, enabled: bool) {
trace!("endpoint_set_enabled ep={:?} en={}", ep_addr, enabled);
assert!(
ep_addr.index() < T::ENDPOINT_COUNT,
"endpoint_set_enabled index {} out of range",
ep_addr.index()
);
let r = T::regs();
match ep_addr.direction() {
Direction::Out => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.doepctl(ep_addr.index()).read().epena() {
r.doepctl(ep_addr.index()).modify(|w| {
w.set_snak(true);
w.set_epdis(true);
})
}
r.doepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
});
// Flush tx fifo
r.grstctl().write(|w| {
w.set_txfflsh(true);
w.set_txfnum(ep_addr.index() as _);
});
loop {
let x = r.grstctl().read();
if !x.txfflsh() {
break;
}
}
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_out_wakers[ep_addr.index()].wake();
}
Direction::In => {
critical_section::with(|_| {
// cancel transfer if active
if !enabled && r.diepctl(ep_addr.index()).read().epena() {
r.diepctl(ep_addr.index()).modify(|w| {
w.set_snak(true); // set NAK
w.set_epdis(true);
})
}
r.diepctl(ep_addr.index()).modify(|w| {
w.set_usbaep(enabled);
w.set_cnak(enabled); // clear NAK that might've been set by SNAK above.
})
});
// Wake `Endpoint::wait_enabled()`
T::state().ep_in_wakers[ep_addr.index()].wake();
}
}
}
async fn enable(&mut self) {
trace!("enable");
// TODO: enable the peripheral once enable/disable semantics are cleared up in embassy-usb
} }
async fn disable(&mut self) { async fn disable(&mut self) {
trace!("disable"); trace!("disable");
Bus::disable(self); // TODO: disable the peripheral once enable/disable semantics are cleared up in embassy-usb
//Bus::disable(self);
self.enabled = false;
} }
async fn remote_wakeup(&mut self) -> Result<(), Unsupported> { async fn remote_wakeup(&mut self) -> Result<(), Unsupported> {
@ -1112,11 +1213,16 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
state.ep_in_wakers[index].register(cx.waker()); state.ep_in_wakers[index].register(cx.waker());
let diepctl = r.diepctl(index).read(); let diepctl = r.diepctl(index).read();
let dtxfsts = r.dtxfsts(index).read();
info!("diepctl {:08x} ftxfsts {:08x}", diepctl.0, dtxfsts.0);
if !diepctl.usbaep() { if !diepctl.usbaep() {
trace!("write ep={:?} wait for prev: error disabled", self.info.addr);
Poll::Ready(Err(EndpointError::Disabled)) Poll::Ready(Err(EndpointError::Disabled))
} else if !diepctl.epena() { } else if !diepctl.epena() {
trace!("write ep={:?} wait for prev: ready", self.info.addr);
Poll::Ready(Ok(())) Poll::Ready(Ok(()))
} else { } else {
trace!("write ep={:?} wait for prev: pending", self.info.addr);
Poll::Pending Poll::Pending
} }
}) })
@ -1141,6 +1247,7 @@ impl<'d, T: Instance> embassy_usb_driver::EndpointIn for Endpoint<'d, T, In> {
Poll::Pending Poll::Pending
} else { } else {
trace!("write ep={:?} wait for fifo: ready", self.info.addr);
Poll::Ready(()) Poll::Ready(())
} }
}) })

View File

@ -282,7 +282,7 @@ where
/// returns the amount of bytes written. /// returns the amount of bytes written.
/// ///
/// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full, /// If it is not possible to write a nonzero amount of bytes because the pipe's buffer is full,
/// this method will wait until it is. See [`try_write`](Self::try_write) for a variant that /// this method will wait until it isn't. See [`try_write`](Self::try_write) for a variant that
/// returns an error instead of waiting. /// returns an error instead of waiting.
/// ///
/// It is not guaranteed that all bytes in the buffer are written, even if there's enough /// It is not guaranteed that all bytes in the buffer are written, even if there's enough
@ -319,7 +319,7 @@ where
/// returns the amount of bytes read. /// returns the amount of bytes read.
/// ///
/// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty, /// If it is not possible to read a nonzero amount of bytes because the pipe's buffer is empty,
/// this method will wait until it is. See [`try_read`](Self::try_read) for a variant that /// this method will wait until it isn't. See [`try_read`](Self::try_read) for a variant that
/// returns an error instead of waiting. /// returns an error instead of waiting.
/// ///
/// It is not guaranteed that all bytes in the buffer are read, even if there's enough /// It is not guaranteed that all bytes in the buffer are read, even if there's enough

View File

@ -52,7 +52,9 @@ async fn main(spawner: Spawner) {
// Create the driver, from the HAL. // Create the driver, from the HAL.
let ep_out_buffer = &mut make_static!([0; 256])[..]; let ep_out_buffer = &mut make_static!([0; 256])[..];
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer); let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, ep_out_buffer, config);
// Create embassy-usb Config // Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);

View File

@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL. // Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256]; let mut ep_out_buffer = [0u8; 256];
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config // Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);

View File

@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL. // Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256]; let mut ep_out_buffer = [0u8; 256];
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config // Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);

View File

@ -38,7 +38,9 @@ async fn main(_spawner: Spawner) {
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");
pac::RCC.ccipr().write(|w| w.set_clk48sel(0b10)); pac::RCC.ccipr().write(|w| {
w.set_clk48sel(pac::rcc::vals::Clk48sel::PLLQCLK);
});
let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11); let driver = Driver::new(p.USB, Irqs, p.PA12, p.PA11);

View File

@ -29,7 +29,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL. // Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256]; let mut ep_out_buffer = [0u8; 256];
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config // Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);

View File

@ -30,7 +30,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL. // Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256]; let mut ep_out_buffer = [0u8; 256];
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config // Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);

View File

@ -31,7 +31,9 @@ async fn main(_spawner: Spawner) {
// Create the driver, from the HAL. // Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256]; let mut ep_out_buffer = [0u8; 256];
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer); let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config // Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe); let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);