stm32/usb: use separate irq flags.
- Fixes race condition that could cause losing irqs (because `if flags != 0` was clearing all) - Doesn't need CAS, which is nice for thumbv6.
This commit is contained in:
parent
40ef66cdfb
commit
cd9a65ba39
@ -2,10 +2,9 @@
|
||||
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::sync::atomic::Ordering;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use atomic_polyfill::{AtomicBool, AtomicU8};
|
||||
use embassy_hal_common::into_ref;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
use embassy_time::{block_for, Duration};
|
||||
@ -35,10 +34,9 @@ static BUS_WAKER: AtomicWaker = NEW_AW;
|
||||
static EP0_SETUP: AtomicBool = AtomicBool::new(false);
|
||||
static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
|
||||
static EP_OUT_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
|
||||
static IRQ_FLAGS: AtomicU8 = AtomicU8::new(0);
|
||||
const IRQ_FLAG_RESET: u8 = 0x01;
|
||||
const IRQ_FLAG_SUSPEND: u8 = 0x02;
|
||||
const IRQ_FLAG_RESUME: u8 = 0x04;
|
||||
static IRQ_RESET: AtomicBool = AtomicBool::new(false);
|
||||
static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false);
|
||||
static IRQ_RESUME: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
fn convert_type(t: EndpointType) -> EpType {
|
||||
match t {
|
||||
@ -184,47 +182,51 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||
|
||||
let istr = regs.istr().read();
|
||||
|
||||
let mut flags: u8 = 0;
|
||||
|
||||
if istr.susp() {
|
||||
//trace!("USB IRQ: susp");
|
||||
flags |= IRQ_FLAG_SUSPEND;
|
||||
IRQ_SUSPEND.store(true, Ordering::Relaxed);
|
||||
regs.cntr().modify(|w| {
|
||||
w.set_fsusp(true);
|
||||
w.set_lpmode(true);
|
||||
})
|
||||
});
|
||||
|
||||
// Write 0 to clear.
|
||||
let mut clear = regs::Istr(!0);
|
||||
clear.set_susp(false);
|
||||
regs.istr().write_value(clear);
|
||||
|
||||
// Wake main thread.
|
||||
BUS_WAKER.wake();
|
||||
}
|
||||
|
||||
if istr.wkup() {
|
||||
//trace!("USB IRQ: wkup");
|
||||
flags |= IRQ_FLAG_RESUME;
|
||||
IRQ_RESUME.store(true, Ordering::Relaxed);
|
||||
regs.cntr().modify(|w| {
|
||||
w.set_fsusp(false);
|
||||
w.set_lpmode(false);
|
||||
})
|
||||
});
|
||||
|
||||
// Write 0 to clear.
|
||||
let mut clear = regs::Istr(!0);
|
||||
clear.set_wkup(false);
|
||||
regs.istr().write_value(clear);
|
||||
|
||||
// Wake main thread.
|
||||
BUS_WAKER.wake();
|
||||
}
|
||||
|
||||
if istr.reset() {
|
||||
//trace!("USB IRQ: reset");
|
||||
flags |= IRQ_FLAG_RESET;
|
||||
IRQ_RESET.store(true, Ordering::Relaxed);
|
||||
|
||||
// Write 0 to clear.
|
||||
let mut clear = regs::Istr(!0);
|
||||
clear.set_reset(false);
|
||||
regs.istr().write_value(clear);
|
||||
}
|
||||
|
||||
if flags != 0 {
|
||||
// Send irqs to main thread.
|
||||
IRQ_FLAGS.fetch_or(flags, Ordering::AcqRel);
|
||||
// Wake main thread.
|
||||
BUS_WAKER.wake();
|
||||
|
||||
// Clear them
|
||||
let mut mask = regs::Istr(0);
|
||||
mask.set_wkup(true);
|
||||
mask.set_susp(true);
|
||||
mask.set_reset(true);
|
||||
regs.istr().write_value(regs::Istr(!(istr.0 & mask.0)));
|
||||
}
|
||||
|
||||
if istr.ctr() {
|
||||
@ -436,17 +438,15 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||
if self.inited {
|
||||
let regs = T::regs();
|
||||
|
||||
let flags = IRQ_FLAGS.load(Ordering::Acquire);
|
||||
|
||||
if flags & IRQ_FLAG_RESUME != 0 {
|
||||
IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
|
||||
if IRQ_RESUME.load(Ordering::Acquire) {
|
||||
IRQ_RESUME.store(false, Ordering::Relaxed);
|
||||
return Poll::Ready(Event::Resume);
|
||||
}
|
||||
|
||||
if flags & IRQ_FLAG_RESET != 0 {
|
||||
IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel);
|
||||
if IRQ_RESET.load(Ordering::Acquire) {
|
||||
IRQ_RESET.store(false, Ordering::Relaxed);
|
||||
|
||||
trace!("RESET REGS WRITINGINGING");
|
||||
trace!("RESET");
|
||||
regs.daddr().write(|w| {
|
||||
w.set_ef(true);
|
||||
w.set_add(0);
|
||||
@ -475,8 +475,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
||||
return Poll::Ready(Event::Reset);
|
||||
}
|
||||
|
||||
if flags & IRQ_FLAG_SUSPEND != 0 {
|
||||
IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel);
|
||||
if IRQ_SUSPEND.load(Ordering::Acquire) {
|
||||
IRQ_SUSPEND.store(false, Ordering::Relaxed);
|
||||
return Poll::Ready(Event::Suspend);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user