8000 samd/mphalport: Fix USB CDC RX handling to not block when unprocessed. · micropython/micropython@13bb2c0 · GitHub 8000
[go: up one dir, main page]

Skip to content

Commit 13bb2c0

Browse files
committed
samd/mphalport: Fix USB CDC RX handling to not block when unprocessed.
Porting PR #8040 of @hoihu for SAMD, following the commit 5873390. --- Issue: This PR unveils an issue of the port and is made to have a working example for easily reproducing the fault. USB locks up almost immediately if charaters at the input arrive too fast, when they are echoed. That happens for instance in REPL. This issue is present in the actual master branch as well, but requires much higher input symbol frequency and is hard to reproce. Addition: Temporary add a function mp_hal_time_ns() to please the linker when built with DEBUG=1.
1 parent 9d7c168 commit 13bb2c0

File tree

4 files changed

+61
-19
lines changed

4 files changed

+61
-19
lines changed

ports/samd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ SRC_C = \
103103
shared/libc/string0.c \
104104
shared/readline/readline.c \
105105
shared/runtime/gchelper_native.c \
106+
shared/runtime/interrupt_char.c \
106107
shared/runtime/pyexec.c \
107108
shared/runtime/stdout_helpers.c \
108109
shared/runtime/sys_stdio_mphal.c \

ports/samd/mphalport.c

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,55 @@
2727
#include "py/runtime.h"
2828
#include "py/mphal.h"
2929
#include "py/stream.h"
30+
#include "shared/runtime/interrupt_char.h"
3031
#include "samd_soc.h"
3132
#include "tusb.h"
3233

33-
#if MICROPY_KBD_EXCEPTION
34+
#ifndef MICROPY_HW_STDIN_BUFFER_LEN
35+
#define MICROPY_HW_STDIN_BUFFER_LEN 256
36+
#endif
3437

35-
void tud_cdc_rx_wanted_cb(uint8_t itf, char wanted_char) {
36-
(void)itf;
37-
(void)wanted_char;
38-
tud_cdc_read_char(); // discard interrupt char
39-
mp_sched_keyboard_interrupt();
40-
}
38+
STATIC uint8_t stdin_ringbuf_array[MICROPY_HW_STDIN_BUFFER_LEN];
39+
ringbuf_t stdin_ringbuf = { stdin_ringbuf_array, sizeof(stdin_ringbuf_array) };
4140

42-
void mp_hal_set_interrupt_char(int c) {
43-
tud_cdc_set_wanted_char(c);
41+
uint8_t cdc_itf_pending; // keep track of cdc interfaces which need attention to poll
42+
43+
void poll_cdc_interfaces(void) {
44+
// any CDC interfaces left to poll?
45+
if (cdc_itf_pending && ringbuf_free(&stdin_ringbuf)) {
46+
for (uint8_t itf = 0; itf < 8; ++itf) {
47+
if (cdc_itf_pending & (1 << itf)) {
48+
tud_cdc_rx_cb(itf);
49+
if (!cdc_itf_pending) {
50+
break;
51+
}
52+
}
53+
}
54+
}
4455
}
4556

46-
#endif
57+
void tud_cdc_rx_cb(uint8_t itf) {
58+
// consume pending USB data immediately to free usb buffer and keep the endpoint from stalling.
59+
// in case the ringbuffer is full, mark the CDC interface that need attention later on for polling
60+
cdc_itf_pending &= ~(1 << itf);
61+
for (uint32_t bytes_avail = tud_cdc_n_available(itf); bytes_avail > 0; --bytes_avail) {
62+
if (ringbuf_free(&stdin_ringbuf)) {
63+
int data_char = tud_cdc_read_char();
64+
#if MICROPY_KBD_EXCEPTION
65+
if (data_char == mp_interrupt_char) {
66+
mp_sched_keyboard_interrupt();
67+
} else {
68+
ringbuf_put(&stdin_ringbuf, data_char);
69+
}
70+
#else
71+
ringbuf_put(&stdin_ringbuf, data_char);
72+
#endif
73+
} else {
74+
cdc_itf_pending |= (1 << itf);
75+
return;
76+
}
77+
}
78+
}
4779

4880
void mp_hal_delay_ms(mp_uint_t ms) {
4981
ms += 1;
@@ -63,7 +95,11 @@ void mp_hal_delay_us(mp_uint_t us) {
6395

6496
uintptr_t mp_hal_stdio_poll(uintptr_t poll_flags) {
6597
uintptr_t ret = 0;
66-
if (tud_cdc_connected() && tud_cdc_available()) {
98+
poll_cdc_interfaces();
99+
if ((poll_flags & MP_STREAM_POLL_RD) && ringbuf_peek(&stdin_ringbuf) != -1) {
100+
ret |= MP_STREAM_POLL_RD;
101+
}
102+
if (USARTx->USART.INTFLAG.bit.RXC) {
67103
ret |= MP_STREAM_POLL_RD;
68104
}
69105
return ret;
@@ -74,12 +110,11 @@ int mp_hal_stdin_rx_chr(void) {
74110
if (USARTx->USART.INTFLAG.bit.RXC) {
75111
return USARTx->USART.DATA.bit.DATA;
76112
}
77-
if (tud_cdc_connected() && tud_cdc_available()) {
78-
uint8_t buf[1];
79-
uint32_t count = tud_cdc_read(buf, sizeof(buf));
80-
if (count) {
81-
return buf[0];
82-
}
113+
114+
poll_cdc_interfaces();
115+
int c = ringbuf_get(&stdin_ringbuf);
116+
if (c != -1) {
117+
return c;
83118
}
84119
__WFI();
85120
}

ports/samd/mphalport.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,18 @@ void mp_hal_set_interrupt_char(int c);
4141
static inline mp_uint_t mp_hal_ticks_ms(void) {
4242
return systick_ms;
4343
}
44+
4445
static inline mp_uint_t mp_hal_ticks_us(void) {
4546
return systick_ms * 1000;
4647
}
48+
4749
static inline mp_uint_t mp_hal_ticks_cpu(void) {
4850
return 0;
4951
}
5052

53+
static inline uint64_t mp_hal_time_ns(void) {
54+
return systick_ms * 1000000;
55+
}
5156
// C-level pin HAL
5257

5358
#include "py/obj.h"

ports/samd/tusb_config.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141

4242
#define CFG_TUD_ENDOINT0_SIZE (64)
4343
#define CFG_TUD_CDC (1)
44-
#define CFG_TUD_CDC_RX_BUFSIZE (64)
45-
#define CFG_TUD_CDC_TX_BUFSIZE (64)
44+
#define CFG_TUD_CDC_EP_BUFSIZE (256)
45+
#define CFG_TUD_CDC_RX_BUFSIZE (256)
46+
#define CFG_TUD_CDC_TX_BUFSIZE (256)
4647

4748
#endif // MICROPY_INCLUDED_SAMD_TUSB_CONFIG_H

0 commit comments

Comments
 (0)
0