summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2021-02-02 12:09:33 +1100
committerDamien George <damien@micropython.org>2021-02-02 12:09:33 +1100
commit7be1f7790278d2c40e7a828e340c43f257c7d748 (patch)
treecb9a4e57f4c3189a989efbd2eeb6a912944aaed7
parent3ea05e499d52beaecf4c9c54a67510ac031fe27b (diff)
stm32/usbd_cdc_interface: Don't wait in usbd_cdc_tx_always if suspended.
MCUs with device-only USB peripherals (eg L0, WB) do not implement (at least not in the ST HAL) the HAL_PCD_DisconnectCallback event. So if a USB cable is disconnected the USB driver does not deinitialise itself (usbd_cdc_deinit is not called) and the CDC driver can stay in the USBD_CDC_CONNECT_STATE_CONNECTED state. Then if the USB was attached to the REPL, output can become very slow waiting in usbd_cdc_tx_always for 500ms for each character. The disconnect event is not implemented on these MCUs but the suspend event is. And in the situation where the USB cable is disconnected the suspend event is raised because SOF packets are no longer received. The issue of very slow output on these MCUs is fixed in this commit (really worked around) by adding a check in usbd_cdc_tx_always to see if the USB device state is suspended, and, if so, breaking out of the 500ms wait loop. This should also help all MCUs for a real USB suspend. A proper fix for MCUs with device-only USB would be to implement or somehow synthesise the HAL_PCD_DisconnectCallback event. See issue #6672. Signed-off-by: Damien George <damien@micropython.org>
-rw-r--r--ports/stm32/usbd_cdc_interface.c4
1 files changed, 4 insertions, 0 deletions
diff --git a/ports/stm32/usbd_cdc_interface.c b/ports/stm32/usbd_cdc_interface.c
index a8261a958..a465f608a 100644
--- a/ports/stm32/usbd_cdc_interface.c
+++ b/ports/stm32/usbd_cdc_interface.c
@@ -382,6 +382,10 @@ void usbd_cdc_tx_always(usbd_cdc_itf_t *cdc, const uint8_t *buf, uint32_t len) {
uint32_t start = HAL_GetTick();
while (usbd_cdc_tx_buffer_full(cdc) && HAL_GetTick() - start <= 500) {
usbd_cdc_try_tx(cdc);
+ if (cdc->base.usbd->pdev->dev_state == USBD_STATE_SUSPENDED) {
+ // The USB is suspended so buffer will never be drained; exit loop
+ break;
+ }
if (query_irq() == IRQ_STATE_DISABLED) {
// IRQs disabled so buffer will never be drained; exit loop
break;