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::future::poll_fn;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::sync::atomic::Ordering;
|
use core::sync::atomic::{AtomicBool, Ordering};
|
||||||
use core::task::Poll;
|
use core::task::Poll;
|
||||||
|
|
||||||
use atomic_polyfill::{AtomicBool, AtomicU8};
|
|
||||||
use embassy_hal_common::into_ref;
|
use embassy_hal_common::into_ref;
|
||||||
use embassy_sync::waitqueue::AtomicWaker;
|
use embassy_sync::waitqueue::AtomicWaker;
|
||||||
use embassy_time::{block_for, Duration};
|
use embassy_time::{block_for, Duration};
|
||||||
@ -35,10 +34,9 @@ static BUS_WAKER: AtomicWaker = NEW_AW;
|
|||||||
static EP0_SETUP: AtomicBool = AtomicBool::new(false);
|
static EP0_SETUP: AtomicBool = AtomicBool::new(false);
|
||||||
static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
|
static EP_IN_WAKERS: [AtomicWaker; EP_COUNT] = [NEW_AW; EP_COUNT];
|
||||||
static EP_OUT_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);
|
static IRQ_RESET: AtomicBool = AtomicBool::new(false);
|
||||||
const IRQ_FLAG_RESET: u8 = 0x01;
|
static IRQ_SUSPEND: AtomicBool = AtomicBool::new(false);
|
||||||
const IRQ_FLAG_SUSPEND: u8 = 0x02;
|
static IRQ_RESUME: AtomicBool = AtomicBool::new(false);
|
||||||
const IRQ_FLAG_RESUME: u8 = 0x04;
|
|
||||||
|
|
||||||
fn convert_type(t: EndpointType) -> EpType {
|
fn convert_type(t: EndpointType) -> EpType {
|
||||||
match t {
|
match t {
|
||||||
@ -184,47 +182,51 @@ impl<'d, T: Instance> Driver<'d, T> {
|
|||||||
|
|
||||||
let istr = regs.istr().read();
|
let istr = regs.istr().read();
|
||||||
|
|
||||||
let mut flags: u8 = 0;
|
|
||||||
|
|
||||||
if istr.susp() {
|
if istr.susp() {
|
||||||
//trace!("USB IRQ: susp");
|
//trace!("USB IRQ: susp");
|
||||||
flags |= IRQ_FLAG_SUSPEND;
|
IRQ_SUSPEND.store(true, Ordering::Relaxed);
|
||||||
regs.cntr().modify(|w| {
|
regs.cntr().modify(|w| {
|
||||||
w.set_fsusp(true);
|
w.set_fsusp(true);
|
||||||
w.set_lpmode(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() {
|
if istr.wkup() {
|
||||||
//trace!("USB IRQ: wkup");
|
//trace!("USB IRQ: wkup");
|
||||||
flags |= IRQ_FLAG_RESUME;
|
IRQ_RESUME.store(true, Ordering::Relaxed);
|
||||||
regs.cntr().modify(|w| {
|
regs.cntr().modify(|w| {
|
||||||
w.set_fsusp(false);
|
w.set_fsusp(false);
|
||||||
w.set_lpmode(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() {
|
if istr.reset() {
|
||||||
//trace!("USB IRQ: reset");
|
//trace!("USB IRQ: reset");
|
||||||
flags |= IRQ_FLAG_RESET;
|
IRQ_RESET.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
// Write 0 to clear.
|
// Write 0 to clear.
|
||||||
let mut clear = regs::Istr(!0);
|
let mut clear = regs::Istr(!0);
|
||||||
clear.set_reset(false);
|
clear.set_reset(false);
|
||||||
regs.istr().write_value(clear);
|
regs.istr().write_value(clear);
|
||||||
}
|
|
||||||
|
|
||||||
if flags != 0 {
|
// Wake main thread.
|
||||||
// Send irqs to main thread.
|
|
||||||
IRQ_FLAGS.fetch_or(flags, Ordering::AcqRel);
|
|
||||||
BUS_WAKER.wake();
|
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() {
|
if istr.ctr() {
|
||||||
@ -436,17 +438,15 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
if self.inited {
|
if self.inited {
|
||||||
let regs = T::regs();
|
let regs = T::regs();
|
||||||
|
|
||||||
let flags = IRQ_FLAGS.load(Ordering::Acquire);
|
if IRQ_RESUME.load(Ordering::Acquire) {
|
||||||
|
IRQ_RESUME.store(false, Ordering::Relaxed);
|
||||||
if flags & IRQ_FLAG_RESUME != 0 {
|
|
||||||
IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESUME, Ordering::AcqRel);
|
|
||||||
return Poll::Ready(Event::Resume);
|
return Poll::Ready(Event::Resume);
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags & IRQ_FLAG_RESET != 0 {
|
if IRQ_RESET.load(Ordering::Acquire) {
|
||||||
IRQ_FLAGS.fetch_and(!IRQ_FLAG_RESET, Ordering::AcqRel);
|
IRQ_RESET.store(false, Ordering::Relaxed);
|
||||||
|
|
||||||
trace!("RESET REGS WRITINGINGING");
|
trace!("RESET");
|
||||||
regs.daddr().write(|w| {
|
regs.daddr().write(|w| {
|
||||||
w.set_ef(true);
|
w.set_ef(true);
|
||||||
w.set_add(0);
|
w.set_add(0);
|
||||||
@ -475,8 +475,8 @@ impl<'d, T: Instance> driver::Bus for Bus<'d, T> {
|
|||||||
return Poll::Ready(Event::Reset);
|
return Poll::Ready(Event::Reset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if flags & IRQ_FLAG_SUSPEND != 0 {
|
if IRQ_SUSPEND.load(Ordering::Acquire) {
|
||||||
IRQ_FLAGS.fetch_and(!IRQ_FLAG_SUSPEND, Ordering::AcqRel);
|
IRQ_SUSPEND.store(false, Ordering::Relaxed);
|
||||||
return Poll::Ready(Event::Suspend);
|
return Poll::Ready(Event::Suspend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user