Skip to content

Commit a50be14

Browse files
committed
Add hack to detect interrupted IN transfers
1 parent 5db68fa commit a50be14

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

nrf-hal-common/src/usbd/mod.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,16 @@ impl Buffers {
5353

5454
unsafe impl Sync for Buffers {}
5555

56+
#[derive(Copy, Clone)]
57+
enum TransferState {
58+
NoTransfer,
59+
Started(u16),
60+
}
61+
5662
#[derive(Copy, Clone)]
5763
struct EP0State {
5864
direction: UsbDirection,
65+
in_transfer_state: TransferState,
5966
}
6067

6168
/// USB device implementation.
@@ -101,6 +108,7 @@ impl<'c> Usbd<'c> {
101108
iso_out_used: false,
102109
ep0_state: Mutex::new(Cell::new(EP0State {
103110
direction: UsbDirection::Out,
111+
in_transfer_state: TransferState::NoTransfer,
104112
})),
105113
_clocks: &(),
106114
})
@@ -478,6 +486,13 @@ impl UsbBus for Usbd<'_> {
478486
w.ep0datadone_ep0status().clear_bit()
479487
}
480488
});
489+
490+
// Hack: send status stage if the IN transfer is not acknowledged after a few frames
491+
let frame_counter = regs.framecntr.read().framecntr().bits();
492+
let ep0_state = self.ep0_state.borrow(cs);
493+
let mut state = ep0_state.get();
494+
state.in_transfer_state = TransferState::Started(frame_counter);
495+
ep0_state.set(state);
481496
}
482497

483498
// Clear ENDEPIN[i] flag
@@ -647,6 +662,25 @@ impl UsbBus for Usbd<'_> {
647662
}
648663
}
649664

665+
if regs.events_sof.read().events_sof().bit_is_set() {
666+
regs.events_sof.reset();
667+
668+
// Check if we have a timeout for EP0 IN transfer
669+
let ep0_state = self.ep0_state.borrow(cs);
670+
let mut state = ep0_state.get();
671+
if let TransferState::Started(counter) = state.in_transfer_state {
672+
let frame_counter = regs.framecntr.read().framecntr().bits();
673+
if frame_counter.wrapping_sub(counter) >= 5 {
674+
// Send a status stage to ACK a pending OUT transfer
675+
regs.tasks_ep0status.write(|w| w.tasks_ep0status().set_bit());
676+
677+
// reset the state
678+
state.in_transfer_state = TransferState::NoTransfer;
679+
ep0_state.set(state);
680+
}
681+
}
682+
}
683+
650684
// Check for any finished transmissions.
651685
let mut in_complete = 0;
652686
let mut out_complete = 0;
@@ -657,6 +691,12 @@ impl UsbBus for Usbd<'_> {
657691
regs.events_ep0datadone.reset();
658692

659693
in_complete |= 1;
694+
695+
// Reset a timeout for the IN transfer
696+
let ep0_state = self.ep0_state.borrow(cs);
697+
let mut state = ep0_state.get();
698+
state.in_transfer_state = TransferState::NoTransfer;
699+
ep0_state.set(state);
660700
} else {
661701
// Do not clear OUT events, since we have to continue reporting them until the
662702
// buffer is read.

0 commit comments

Comments
 (0)