summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhathach <[email protected]>2026-04-23 18:10:17 +0700
committerhathach <[email protected]>2026-04-23 18:10:17 +0700
commitd808111cfd1708c25cc9ec671985f742560ebf83 (patch)
tree6007e9d21605ffbae246ef4496f9b9cc6c0870a6
parentd3b6a252b142592a3bacae5e44ab8770421812b7 (diff)
musb double packet for epout
-rw-r--r--src/portable/mentor/musb/dcd_musb.c74
-rw-r--r--src/portable/mentor/musb/musb_type.h4
-rwxr-xr-xtest/hil/hil_test.py45
3 files changed, 88 insertions, 35 deletions
diff --git a/src/portable/mentor/musb/dcd_musb.c b/src/portable/mentor/musb/dcd_musb.c
index 667102bc5..be785324c 100644
--- a/src/portable/mentor/musb/dcd_musb.c
+++ b/src/portable/mentor/musb/dcd_musb.c
@@ -239,19 +239,18 @@ static void process_setup_packet(uint8_t rhport) {
// write to txfifo using pipe_state_t info
static void pipe_write(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) {
- musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
- const unsigned mps = ep_csr->tx_maxp & MUSB_TXMAXP_PACKET_SIZE_MASK;
- const unsigned rem = pipe->remaining;
- const unsigned len = TU_MIN(mps, rem);
- volatile void *fifo_ptr = &musb_regs->fifo[epnum];
- if (len) {
+ musb_ep_csr_t* ep_csr = &musb_regs->indexed_csr;
+ const uint16_t mps = ep_csr->tx_maxp & MUSB_TXMAXP_PACKET_SIZE_M;
+ const uint16_t xact_len = tu_min16(mps, pipe->remaining);
+ volatile void *hwfifo = &musb_regs->fifo[epnum];
+ if (xact_len) {
if (pipe->use_fifo) {
- tu_hwfifo_write_from_fifo(fifo_ptr, pipe->fifo, len, NULL);
+ tu_hwfifo_write_from_fifo(hwfifo, pipe->fifo, xact_len, NULL);
} else {
- tu_hwfifo_write(fifo_ptr, pipe->buf, len, NULL);
- pipe->buf += len;
+ tu_hwfifo_write(hwfifo, pipe->buf, xact_len, NULL);
+ pipe->buf += xact_len;
}
- pipe->remaining = rem - len;
+ pipe->remaining -= xact_len;
}
ep_csr->tx_csrl = MUSB_TXCSRL1_TXRDY;
}
@@ -284,6 +283,28 @@ static void process_epin(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum)
}
}
+// Drain one packet from the Rx FIFO into pipe->buf/fifo, update pipe state, and
+// release the FIFO slot by clearing RXRDY. return true if short packet
+static bool pipe_read(musb_regs_t* musb_regs, pipe_state_t* pipe, uint8_t epnum) {
+ musb_ep_csr_t* ep_csr = &musb_regs->indexed_csr; // index already set in process_epout()
+ const uint16_t mps = ep_csr->rx_maxp & MUSB_RXMAXP_PACKET_SIZE_M;
+ const uint16_t rx_count = ep_csr->rx_count;
+ const uint16_t xact_len = tu_min16(tu_min16(pipe->remaining, mps), rx_count);
+ volatile void *hwfifo = &musb_regs->fifo[epnum];
+ if (xact_len) {
+ if (pipe->use_fifo) {
+ tu_hwfifo_read_to_fifo(hwfifo, pipe->fifo, xact_len, NULL);
+ } else {
+ tu_hwfifo_read(hwfifo, pipe->buf, xact_len, NULL);
+ pipe->buf += xact_len;
+ }
+ pipe->remaining -= xact_len;
+ }
+ ep_csr->rx_csrl = 0; /* Clear RXRDY - release this FIFO slot */
+
+ return (xact_len < mps);
+}
+
static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum, bool is_isr) {
musb_ep_csr_t* ep_csr = get_ep_csr(musb_regs, epnum);
if (ep_csr->rx_csrl & MUSB_RXCSRL1_STALLED) {
@@ -291,13 +312,12 @@ static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum,
return; // sent STALL, do nothing
}
- //Fail gracefully. Spurious interrupt.
+ // Fail gracefully. Spurious interrupt.
if (!(ep_csr->rx_csrl & MUSB_RXCSRL1_RXRDY)) {
return;
}
pipe_state_t *pipe = pipe_get(epnum, TUSB_DIR_OUT);
-
if (!pipe->armed) {
// Packet is already ACK'd by hardware and sitting in the Rx FIFO, but no transfer is
// posted. Do NOT flush (per MUSB spec ยง3.3.11 FlushFIFO) - that would silently drop
@@ -308,28 +328,14 @@ static void process_epout(uint8_t rhport, musb_regs_t *musb_regs, uint8_t epnum,
return;
}
- const unsigned mps = ep_csr->rx_maxp & MUSB_RXMAXP_PACKET_SIZE_MASK;
- const unsigned rem = pipe->remaining;
- const unsigned vld = ep_csr->rx_count;
- const unsigned len = TU_MIN(TU_MIN(rem, mps), vld);
- volatile void *fifo_ptr = &musb_regs->fifo[epnum];
- if (len) {
- if (pipe->use_fifo) {
- tu_hwfifo_read_to_fifo(fifo_ptr, pipe->fifo, len, NULL);
- } else {
- tu_hwfifo_read(fifo_ptr, pipe->buf, len, NULL);
- pipe->buf += len;
- }
- pipe->remaining = rem - len;
- }
+ const bool is_short = pipe_read(musb_regs, pipe, epnum);
- ep_csr->rx_csrl = 0; /* Always Clear RXRDY bit */
- if ((len < mps) || (rem == len)) {
+ // Transfer completes on a short packet or when the rx buffer is filled.
+ if (is_short || pipe->remaining == 0) {
const uint16_t xferred_len = pipe->length - pipe->remaining;
pipe->buf = NULL;
pipe->armed = false;
-
- dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, TUSB_DIR_OUT), xferred_len, XFER_RESULT_SUCCESS, is_isr);
+ dcd_event_xfer_complete(rhport, epnum, xferred_len, XFER_RESULT_SUCCESS, is_isr);
}
}
@@ -879,7 +885,7 @@ void dcd_int_handler(uint8_t rhport) {
process_epin(rhport, musb_regs, epnum);
intr_tx &= ~TU_BIT(epnum);
- // for Double-buffered endpoint: TxPktRdy is cleared and interrupt is generated when we write the first packet
+ // Double packet endpoint: TxPktRdy is clear, and interrupt is generated immediately when 1st packet is written.
uint_fast8_t new_intr_tx = musb_regs->intr_tx;
new_intr_tx &= musb_regs->intr_txen;
@@ -891,6 +897,12 @@ void dcd_int_handler(uint8_t rhport) {
unsigned const epnum = __builtin_ctz(intr_rx);
process_epout(rhport, musb_regs, epnum, true);
intr_rx &= ~TU_BIT(epnum);
+
+ // Double packet endpoint: RxPktRdy is set and interrupt is generated immediately if 2nd packet is received
+ uint_fast8_t new_intr_rx = musb_regs->intr_rx;
+ new_intr_rx &= musb_regs->intr_rxen;
+
+ intr_rx |= new_intr_rx;
}
musb_regs->index = saved_index; // restore endpoint index
diff --git a/src/portable/mentor/musb/musb_type.h b/src/portable/mentor/musb/musb_type.h
index dd1cd6ded..e51634f2a 100644
--- a/src/portable/mentor/musb/musb_type.h
+++ b/src/portable/mentor/musb/musb_type.h
@@ -573,8 +573,8 @@ TU_ATTR_ALWAYS_INLINE static inline musb_ep_csr_t* get_ep_csr(musb_regs_t* musb_
// numpackminus1 (HB-iso / HS-bulk multiplier - 1).
//
//*****************************************************************************
-#define MUSB_TXMAXP_PACKET_SIZE_MASK 0x07FFu
-#define MUSB_RXMAXP_PACKET_SIZE_MASK 0x07FFu
+#define MUSB_TXMAXP_PACKET_SIZE_M 0x07FFu
+#define MUSB_RXMAXP_PACKET_SIZE_M 0x07FFu
//*****************************************************************************
//
diff --git a/test/hil/hil_test.py b/test/hil/hil_test.py
index 58116fb67..447ae10ec 100755
--- a/test/hil/hil_test.py
+++ b/test/hil/hil_test.py
@@ -1285,6 +1285,32 @@ def test_example(board, f1, example):
return err_count
+def build_board(board):
+ """Build firmware for this board via tools/build.py.
+ Honors board config's build.flags_on variants and build.args defines.
+ Output goes to cmake-build/cmake-build-BOARD[-f1_...]/ (tools/build.py layout)."""
+ name = board['name']
+ bcfg = board.get('build', {})
+ flags_on_list = bcfg.get('flags_on', [''])
+ extra_defs = bcfg.get('args', [])
+
+ failed = 0
+ for f1 in flags_on_list:
+ cmd = [sys.executable, f'{TINYUSB_ROOT}/tools/build.py', '-b', name]
+ for d in extra_defs:
+ cmd += ['-D', d]
+ if f1:
+ for flag in f1.split():
+ cmd += ['-f1', flag]
+ if verbose:
+ cmd.append('-v')
+ print(f' + {" ".join(cmd)}')
+ r = subprocess.run(cmd, cwd=TINYUSB_ROOT)
+ if r.returncode != 0:
+ failed += 1
+ return name, failed
+
+
def test_board(board):
name = board['name']
flasher = board['flasher']
@@ -1346,6 +1372,7 @@ def main():
parser.add_argument('-sf', '--skip-flash', action='store_true', help='Run tests without flashing firmware (use whatever is already on the board)')
parser.add_argument('-t', '--test-only', action='append', default=[], help='Tests to run, all if not specified')
parser.add_argument('-B', '--build-dir', default='cmake-build', help='Build folder name (default: cmake-build)')
+ parser.add_argument('--build', action='store_true', help='Build firmware for selected boards with cmake before running tests')
parser.add_argument('-r', '--retry', type=int, default=3, help='Retry count for failed tests (default: 3)')
parser.add_argument('-v', '--verbose', action='store_true', help='Verbose output')
args = parser.parse_args()
@@ -1370,10 +1397,24 @@ def main():
else:
config_boards = [e for e in config['boards'] if e['name'] in boards]
- err_count = 0
+ build_err = 0
+ if args.build:
+ if build_dir != 'cmake-build':
+ print(f'warning: --build writes into cmake-build/, but -B is {build_dir!r}; '
+ f'tests will not find the freshly built firmware')
+ print('-' * 30)
+ print(f'Build phase: {len(config_boards)} board(s)')
+ print('-' * 30)
+ for board in config_boards:
+ _, nfail = build_board(board)
+ build_err += nfail
+ print('-' * 30)
+ print(f'Build phase done: {build_err} failed')
+ print('-' * 30)
+
with Pool(processes=os.cpu_count()) as pool:
mret = pool.map(test_board, config_boards)
- err_count = sum(e[1] for e in mret)
+ err_count = build_err + sum(e[1] for e in mret)
# generate skip list for next re-run if failed
skip_fname = f'{config_file}.skip'
if err_count > 0: