Skip to content

Commit ce81b01

Browse files
committed
improving transfer tracking and adding support for un-armed Rx data handling
1 parent 723e016 commit ce81b01

2 files changed

Lines changed: 61 additions & 30 deletions

File tree

src/portable/mentor/musb/dcd_musb.c

Lines changed: 58 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,18 @@ typedef union {
5858
volatile uint32_t u32;
5959
} hw_fifo_t;
6060

61-
typedef struct TU_ATTR_PACKED
62-
{
63-
void *buf; /* the start address of a transfer data buffer */
61+
typedef struct {
62+
union {
63+
uint8_t *buf; /* the start address of a transfer data buffer */
64+
tu_fifo_t *fifo;
65+
};
6466
uint16_t length; /* the number of bytes in the buffer */
6567
uint16_t remaining; /* the number of bytes remaining in the buffer */
68+
bool armed; /* true while a transfer is posted */
69+
bool use_fifo; /* true: buf is tu_fifo_t*; false: buf is plain byte pointer. */
6670
} pipe_state_t;
6771

68-
typedef struct
69-
{
72+
typedef struct {
7073
union {
7174
tusb_control_request_t setup_packet;
7275
uint32_t setup_buffer[2];
@@ -75,7 +78,6 @@ typedef struct
7578
int8_t status_out;
7679
pipe_state_t pipe0;
7780
pipe_state_t pipe[2][TUP_DCD_ENDPOINT_MAX-1]; /* pipe[direction][endpoint number - 1] */
78-
uint16_t pipe_buf_is_fifo[2]; /* Bitmap. Each bit means whether 1:TU_FIFO or 0:POD. */
7981
} dcd_data_t;
8082

8183
static dcd_data_t _dcd;
@@ -197,22 +199,21 @@ static bool handle_xfer_in(uint8_t rhport, uint_fast8_t ep_addr) {
197199

198200
if (rem == 0 && pipe->length > 0) {
199201
pipe->buf = NULL;
202+
pipe->armed = false;
200203
return true;
201204
}
202205

203206
musb_regs_t* musb_regs = MUSB_REGS(rhport);
204207
musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
205208
const unsigned mps = ep_csr->tx_maxp;
206209
const unsigned len = TU_MIN(mps, rem);
207-
void *buf = pipe->buf;
208210
volatile void *fifo_ptr = &musb_regs->fifo[epnum];
209-
// TU_LOG1(" %p mps %d len %d rem %d\r\n", buf, mps, len, rem);
210211
if (len) {
211-
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
212-
tu_hwfifo_write_from_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
212+
if (pipe->use_fifo) {
213+
tu_hwfifo_write_from_fifo(fifo_ptr, pipe->fifo, len, NULL);
213214
} else {
214-
tu_hwfifo_write(fifo_ptr, buf, len, NULL);
215-
pipe->buf = (uint8_t*)buf + len;
215+
tu_hwfifo_write(fifo_ptr, pipe->buf, len, NULL);
216+
pipe->buf += len;
216217
}
217218
pipe->remaining = rem - len;
218219
}
@@ -231,11 +232,17 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
231232
// TU_LOG1(" RXCSRL%d = %x\r\n", epnum_minus1 + 1, ep_csr->rx_csrl);
232233

233234
//Fail gracefully. Spurious interrupt.
234-
if (!(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY)) return false;
235+
if (!(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY)) {
236+
return false;
237+
}
235238

236-
void *buf = pipe->buf;
237-
if (buf == NULL) {
238-
ep_csr->rx_csrl = MUSB_RXCSRL1_FLUSH;
239+
if (!pipe->armed) {
240+
// Packet is already ACK'd by hardware and sitting in the Rx FIFO, but no transfer is
241+
// posted. Do NOT flush (per MUSB spec §3.3.11 FlushFIFO) - that would silently drop
242+
// acknowledged data. Mask this endpoint's Rx interrupt so the ISR stops re-firing;
243+
// the FIFO stays occupied so hardware NAKs further OUT tokens (natural backpressure).
244+
// The next dcd_edpt_xfer() on this endpoint will drain the staged packet.
245+
musb_regs->intr_rxen &= (uint16_t) ~TU_BIT(epnum);
239246
return false;
240247
}
241248

@@ -245,40 +252,58 @@ static bool handle_xfer_out(uint8_t rhport, uint_fast8_t ep_addr)
245252
const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
246253
volatile void *fifo_ptr = &musb_regs->fifo[epnum];
247254
if (len) {
248-
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
249-
tu_hwfifo_read_to_fifo(fifo_ptr, (tu_fifo_t *)buf, len, NULL);
255+
if (pipe->use_fifo) {
256+
tu_hwfifo_read_to_fifo(fifo_ptr, pipe->fifo, len, NULL);
250257
} else {
251-
tu_hwfifo_read(fifo_ptr, buf, len, NULL);
252-
pipe->buf = (uint8_t*)buf + len;
258+
tu_hwfifo_read(fifo_ptr, pipe->buf, len, NULL);
259+
pipe->buf += len;
253260
}
254261
pipe->remaining = rem - len;
255262
}
256263

257264
ep_csr->rx_csrl = 0; /* Always Clear RXRDY bit */
258265
if ((len < mps) || (rem == len)) {
259266
pipe->buf = NULL;
260-
return NULL != buf;
267+
pipe->armed = false;
268+
return true;
261269
}
262270
return false;
263271
}
264272

265-
static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes)
273+
static bool edpt_n_xfer(uint8_t rhport, uint8_t ep_addr, void *buffer, uint16_t total_bytes, bool use_fifo)
266274
{
267275
unsigned epnum = tu_edpt_number(ep_addr);
268276
unsigned epnum_minus1 = epnum - 1;
269277
unsigned dir_in = tu_edpt_dir(ep_addr);
270278

271279
pipe_state_t *pipe = &_dcd.pipe[dir_in][epnum_minus1];
272-
pipe->buf = buffer;
280+
if (use_fifo) {
281+
pipe->fifo = (tu_fifo_t *) buffer;
282+
} else {
283+
pipe->buf = (uint8_t *) buffer;
284+
}
273285
pipe->length = total_bytes;
274286
pipe->remaining = total_bytes;
287+
pipe->use_fifo = use_fifo;
288+
pipe->armed = true;
275289

276290
if (dir_in) {
277291
handle_xfer_in(rhport, ep_addr);
278292
} else {
279293
musb_regs_t* musb_regs = MUSB_REGS(rhport);
280294
musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
281-
if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) ep_csr->rx_csrl = 0;
295+
296+
// Re-enable Rx interrupt (may have been masked by the no-buffer path in handle_xfer_out)
297+
musb_regs->intr_rxen |= (uint16_t) TU_BIT(epnum);
298+
299+
// Drain any packet staged in the Rx FIFO from a prior no-buffer interrupt
300+
if (ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY) {
301+
if (handle_xfer_out(rhport, ep_addr)) {
302+
dcd_event_xfer_complete(rhport, ep_addr,
303+
pipe->length - pipe->remaining,
304+
XFER_RESULT_SUCCESS, false);
305+
}
306+
}
282307
}
283308
return true;
284309
}
@@ -411,7 +436,7 @@ static void process_ep0(uint8_t rhport)
411436
return;
412437
}
413438

414-
/* When CSRL0 is zero, it means that completion of sending a any length packet
439+
/* When CSRL0 is zero, it means that completion of sending any length packet
415440
* or receiving a zero length packet. */
416441
if (req != REQUEST_TYPE_INVALID && !tu_edpt_dir(req)) {
417442
/* STATUS IN */
@@ -611,6 +636,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * ep_desc) {
611636
pipe->buf = NULL;
612637
pipe->length = 0;
613638
pipe->remaining = 0;
639+
pipe->armed = false;
614640

615641
musb_regs_t* musb = MUSB_REGS(rhport);
616642
musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn);
@@ -656,6 +682,7 @@ bool dcd_edpt_iso_activate(uint8_t rhport, tusb_desc_endpoint_t const *ep_desc )
656682
pipe->buf = NULL;
657683
pipe->length = 0;
658684
pipe->remaining = 0;
685+
pipe->armed = false;
659686

660687
musb_regs_t* musb = MUSB_REGS(rhport);
661688
musb_ep_csr_t* ep_csr = get_ep_csr(musb, epn);
@@ -722,13 +749,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t
722749
musb_dcd_int_disable(rhport);
723750

724751
if (epnum) {
725-
_dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] &= ~TU_BIT(epnum - 1);
726-
ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes);
752+
ret = edpt_n_xfer(rhport, ep_addr, buffer, total_bytes, false);
727753
} else {
728754
ret = edpt0_xfer(rhport, ep_addr, buffer, total_bytes);
729755
}
730756

731-
if (ie) musb_dcd_int_enable(rhport);
757+
if (ie) {
758+
musb_dcd_int_enable(rhport);
759+
}
732760
return ret;
733761
}
734762

@@ -744,8 +772,7 @@ bool dcd_edpt_xfer_fifo(uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_
744772
TU_ASSERT(epnum);
745773
unsigned const ie = musb_dcd_get_int_enable(rhport);
746774
musb_dcd_int_disable(rhport);
747-
_dcd.pipe_buf_is_fifo[tu_edpt_dir(ep_addr)] |= TU_BIT(epnum - 1);
748-
ret = edpt_n_xfer(rhport, ep_addr, (uint8_t*)ff, total_bytes);
775+
ret = edpt_n_xfer(rhport, ep_addr, ff, total_bytes, true);
749776
if (ie) musb_dcd_int_enable(rhport);
750777
return ret;
751778
}
@@ -768,6 +795,7 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
768795
} else {
769796
const uint8_t is_rx = 1 - tu_edpt_dir(ep_addr);
770797
ep_csr->maxp_csr[is_rx].csrl = MUSB_CSRL_SEND_STALL(is_rx);
798+
_dcd.pipe[tu_edpt_dir(ep_addr)][epn - 1].armed = false;
771799
}
772800

773801
if (ie) musb_dcd_int_enable(rhport);

test/hil/tinyusb.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@
226226
{
227227
"name": "stm32f072disco",
228228
"uid": "3A001A001357364230353532",
229+
"tests": {
230+
"device": true, "host": false, "dual": false
231+
},
229232
"flasher": {
230233
"name": "jlink",
231234
"uid": "779541626",

0 commit comments

Comments
 (0)