Skip to content

Commit

Permalink
cdc_uart: performance improvements
Browse files Browse the repository at this point in the history
This commit fixes a few deadlock scenarios and makes cdc_task more
amenable to being called in a threadable context. Full-duplex is now
reliable at fast and slow baudrates.

There is still an annoyance where if the CDC interface is deactivated
while the UART RX is still active, buffers queued to the endpoint
hardware aren't flushed. This is a tinyUSB interface bug.

Signed-off-by: Jonathan Bell <[email protected]>
  • Loading branch information
P33M committed Aug 18, 2022
1 parent fcb1fab commit 33ed0e7
Showing 1 changed file with 30 additions and 14 deletions.
44 changes: 30 additions & 14 deletions src/cdc_uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,57 @@

#include "picoprobe_config.h"

static uint8_t tx_buf[CFG_TUD_CDC_TX_BUFSIZE];
static uint8_t rx_buf[CFG_TUD_CDC_RX_BUFSIZE];

void cdc_uart_init(void) {
gpio_set_function(PICOPROBE_UART_TX, GPIO_FUNC_UART);
gpio_set_function(PICOPROBE_UART_RX, GPIO_FUNC_UART);
gpio_set_pulls(PICOPROBE_UART_TX, 1, 0);
gpio_set_pulls(PICOPROBE_UART_RX, 1, 0);
uart_init(PICOPROBE_UART_INTERFACE, PICOPROBE_UART_BAUDRATE);
}

#define MAX_UART_PKT 64
void cdc_task(void) {
uint8_t rx_buf[MAX_UART_PKT];
uint8_t tx_buf[MAX_UART_PKT];
uint rx_len = 0;

// Consume uart fifo regardless even if not connected
uint rx_len = 0;
while(uart_is_readable(PICOPROBE_UART_INTERFACE) && (rx_len < MAX_UART_PKT)) {
while(uart_is_readable(PICOPROBE_UART_INTERFACE) && (rx_len < sizeof(rx_buf))) {
rx_buf[rx_len++] = uart_getc(PICOPROBE_UART_INTERFACE);
}

if (tud_cdc_connected()) {
// Do we have anything to display on the host's terminal?
int written = 0;
/* Implicit overflow if we don't write all the bytes to the host.
* Also throw away bytes if we can't write... */
if (rx_len) {
for (uint i = 0; i < rx_len; i++) {
tud_cdc_write_char(rx_buf[i]);
}
written = MIN(tud_cdc_write_available(), rx_len);
if (written > 0) {
tud_cdc_write(rx_buf, written);
tud_cdc_write_flush();
}
}

if (tud_cdc_available()) {
// Is there any data from the host for us to tx
uint tx_len = tud_cdc_read(tx_buf, sizeof(tx_buf));
uart_write_blocking(PICOPROBE_UART_INTERFACE, tx_buf, tx_len);
}
/* Reading from a firehose and writing to a FIFO. */
size_t watermark = MIN(tud_cdc_available(), sizeof(tx_buf));
if (watermark > 0) {
size_t tx_len;
/* Batch up to half a FIFO of data - don't clog up on RX */
watermark = MIN(watermark, 16);
tx_len = tud_cdc_read(tx_buf, watermark);
uart_write_blocking(PICOPROBE_UART_INTERFACE, tx_buf, tx_len);
}
} else {
/* Clear out characters that may be left
- note that this doesn't include buffers already under hardware control */
tud_cdc_write_clear();
}
}

void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* line_coding) {
picoprobe_info("New baud rate %d\n", line_coding->bit_rate);
uart_deinit(PICOPROBE_UART_INTERFACE);
tud_cdc_write_clear();
tud_cdc_read_flush();
uart_init(PICOPROBE_UART_INTERFACE, line_coding->bit_rate);
}

0 comments on commit 33ed0e7

Please sign in to comment.