examples: write the host cdc console over RTT when that is the console console_write() forwards what the attached CDC device sent back to the board's console, and reached for board_uart_write() directly to stay non-blocking. On a board whose console is the debug probe there is no UART: board_uart_write() is a stub returning -1, so everything the device echoed was dropped, and the do/while loop retried a write that could never make progress and spun until more data arrived. Send it through SEGGER_RTT_Write() on LOGGER_RTT builds -- already non-blocking in the default NO_BLOCK_SKIP mode, which is what the UART path wanted board_uart_write() for. The retry is also bounded now. board_uart_write() is only documented to return the number of bytes sent, and the stubs disagree on how they say "no console here" -- lpc40 returns -1, apm32f0xx returns 0 -- so the loop cannot decide from the return value alone when to stop. It gives up after 10 ms without progress instead, which no draining console ever hits, and keeps the negative return as a fast path so a stub UART does not cost that wait on every read. The RTT header include lives in board_api.h so any example can reach it; the include path only exists when LOGGER=rtt defines LOGGER_RTT. host/cdc_msc_hid now passes on ea4088_quickstart, whose probe (LPC-Link2) has no VCOM: the CDC echo round-trips through a CH340 with TX-RX shorted.
diff --git a/examples/host/cdc_msc_hid/src/cdc_app.c b/examples/host/cdc_msc_hid/src/cdc_app.c index e6c1907..b77f7b0 100644 --- a/examples/host/cdc_msc_hid/src/cdc_app.c +++ b/examples/host/cdc_msc_hid/src/cdc_app.c
@@ -42,11 +42,24 @@ return count; } -static size_t console_write(const uint8_t *buf, size_t bufsize) { +// Give up forwarding to the console after this long without progress. Not every board's +// board_uart_write() reports "no console here" the same way, so the loop below cannot rely +// on the return value alone to know when to stop. +enum { CONSOLE_STALL_MS = 10 }; + +// Returns bytes written, 0 if the console cannot take them right now, negative if this +// board has no console at all. +static int console_write(const uint8_t *buf, size_t bufsize) { +#if defined(LOGGER_RTT) + // The console is the debug probe, not a UART: board_uart_write() is a stub on those + // boards. NO_BLOCK_SKIP writes all or nothing, so 0 means the probe has not drained the + // up-buffer yet. + return (int) SEGGER_RTT_Write(0, buf, (unsigned) bufsize); +#else // Use board_uart_write directly for non-blocking behavior. // board_putchar -> sys_write has a blocking retry loop that causes UART RX overrun. - int wr = board_uart_write(buf, (int) bufsize); - return (wr > 0) ? (size_t) wr : 0; + return board_uart_write(buf, (int) bufsize); +#endif } // forward from console to usbh @@ -70,11 +83,23 @@ uint8_t buf[64]; uint32_t count = tuh_cdc_read(idx, buf, sizeof(buf)); uint32_t wr = 0; + uint32_t progress_ms = tusb_time_millis_api(); do { - // uart write is slow, while waiting forward uart -> usbh else uart rx can be overflow + // console write is slow, while waiting forward console -> usbh else its rx can overflow if (count) { - wr += console_write(buf + wr, count - wr); + const int written = console_write(buf + wr, count - wr); + if (written < 0) { + break; // no console on this board at all + } + if (written > 0) { + wr += (uint32_t) written; + progress_ms = tusb_time_millis_api(); + } else if (tusb_time_millis_api() - progress_ms > CONSOLE_STALL_MS) { + // a TX FIFO or an RTT up-buffer is only ever transiently full: nothing draining it + // must not stall the host task, so drop the rest + break; + } } console_to_usbh(idx); } while (wr < count);
diff --git a/hw/bsp/board_api.h b/hw/bsp/board_api.h index 73c0607..27316af 100644 --- a/hw/bsp/board_api.h +++ b/hw/bsp/board_api.h
@@ -39,6 +39,10 @@ #include "tusb.h" +#if defined(LOGGER_RTT) +#include "SEGGER_RTT.h" +#endif + #if CFG_TUSB_OS == OPT_OS_ZEPHYR #include <zephyr/kernel.h> #elif CFG_TUSB_OS == OPT_OS_FREERTOS