8000 rp2: fix usb endpoint handling by hoihu · Pull Request #8040 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

rp2: fix usb endpoint handling #8040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from

Conversation

hoihu
Copy link
Contributor
@hoihu hoihu commented Nov 27, 2021

fixes #7996

Copy link
Member
@dpgeorge dpgeorge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that there's a tud_cdc_rx_cb function, the tud_cdc_rx_wanted_cb can be removed and its functionality moved into tud_cdc_rx_cb (otherwise there will be two passes over all incoming data).

Also, the functionality here should be put in samd and mimxrt ports, because they will have the same issue. Would be best to put it all in shared/... and let the ports pull in the same code.

if (ringbuf_free(&usb_ringbuf)) {
ringbuf_put(&usb_ringbuf, tud_cdc_read_char());
} else {
break;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this returns with bytes still available in the CDC buffer, and there's no more USB activity, I think those bytes will never be processed (because there's no further callback here, and mp_hal_stdin_rx_chr will only check in the ringbuf).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to check against this condition and while testing this with a bigger text buffer copy&pasted into the repl, I noticed that the board freezes (may happen after several chunks of say 600 bytes strings pasted into REPL). With freezing I mean that it no longer reacts on the REPL.

I then reverted back before I made the callback changes (current upstream master), and there it seems to work fine. Pasting many blocks of data in the REPL worked until a memoryError was thrown..

So I'm not convinced anymore if handling this callback is actually a good idea.. not until the source of the freeze is found.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem could be because there is now some processing for each char in this callback, and that means the USB stack misses some IRQs.

This could be related to the fact that on rp2 the tud_task() is called from MICROPY_VM_HOOK_POLL, whereas on other tinyusb ports like mimxrt and samd, it's called directly from the USB IRQ (calling from MICROPY_VM_HOOK_POLL introduces some latency).

Given that those other ports work well calling tud_task() from IRQ context, it would be good to see if rp2 can do the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm I just realized that tud_int_handler() does not seem to get called. At least I did not see any references to it. Or am I missing something here? Perhaps that would also explain some issues.

I can try to include the USB IRQ handling (which would then call tud_int_handler() and tud_task(), in line with the Mimxrt and Samd port).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the IRQ handler gets registered with the pico-sdk, see lib/tinyusb/src/portable/raspberrypi/rp2040/dcd_rp2040.c:

irq_set_exclusive_handler(USBCTRL_IRQ, dcd_rp2040_irq);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Further digging and thoughts...

hathach/tinyusb#52 suggests that tud_task() should not be called in IRQ context.

The comment here discourages to install a custom USB irq for the rp2040

CircuitPython does seems to deregister the original IRQ and install a separate handler though (https://github.com/adafruit/circuitpython/blob/main/ports/raspberrypi/supervisor/usb.c#L37). Likely due to reducing the latency introduced when a USB irq is fired until tud_task() is called: A usb background task is scheduled in the irq, seems to be a CircuitPython addition there.

I guess we could try to do similar things and improve latency. Perhaps re-installing the IRQ and adding a callback as done by CircuitPython could be beneficial. But how could we signal to call tud_task() from the IRQ? Maybe re-use something from the machinery of micropython.schedule()?

On a general note, it does bother me that this is going to change a lot of things. And from all I've read so far, the existing approach how MicroPython handles the USB stack should be fine. It may not be very good in terms of latency, but it should still satisfy the requirments given by the tinyUSB stack. It's still unclear to me why the endpoint behaves the way it does in #7996... Perhaps it would really be better to report this upstream and get an opinion from there. Maybe this is a real bug and should be solved in the stack, rather than trying to circumfence it in the upper layers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this returns with bytes still available in the CDC buffer, and there's no more USB activity, I think those bytes will never be processed (because there's no further callback here, and mp_hal_stdin_rx_chr will only check in the ringbuf).

this is addressed now. There is a separate check in mp_hal_stdio_poll

Copy link
Member
@dpgeorge dpgeorge Mar 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like the pending_cdc_bytes=0 at the end of this function will overwrite the pending_cdc_bytes = bytes_avail line. Also it seems a waste to use 5 bytes for what is effectively a flag. And also this won't work with multiple CDC interfaces (the cdc_itf_nr will be clobbered by the next interface if all are full).

I suggest the following: have a uint8_t cdc_itf_pending set of bits which are 1 if the corresponding interface needs attention. Then in this function it'll be set like cdc_itf_pending |= 1 << itf, cleared like cdc_itf_pending &= ~(1 << itf) at the top of the function, and then in poll will be something like:

if (cdc_itf_pending) {
    for (uint8_t itf = 0; itf < MAX; ++itf) {
        if (cdc_itf_pending & (1 << itf)) {
            tud_cdc_rx_cb(itf);
        }
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for (uint8_t itf = 0; itf < MAX; ++itf)

Hmm what would MAX be? In the stm32 port, there is MICROPY_HW_USB_CDC_NUM, should that be reused here?

@hoihu
Copy link
Contributor Author
hoihu commented Dec 19, 2021

Maybe even mp_hal_set_interrupt_char() could be deleted too and interrupt_char.c included.

@hoihu
Copy link
Contributor Author
hoihu commented Dec 22, 2021

@dpgeorge I pushed an update. I could not address all your review points unfortunately. I played around with subscribing the USB IRQ, but I couldn't get it to a reliable working state. The issue was always that when pasting larger amount of text in the REPL, it will freeze.

So I moved back to my original solution. I discovered that when not calling tud_task() in mp_hal_stdout_tx_strn() then pasting worked flawlessly. As soon as I used tud_task() it started to freeze after a few paste's.

The state I now pushed solves the original problem with CTRL+C not working in the REPL and seems to work ok for larger text pasting too. I did not experience any freezing.

But I did not syncronize it with the other ports. I also do not feel comfortable in doing so because I neither have a mimixrt nor a samd board at hand.

@hoihu
Copy link
Contributor Author
hoihu commented Jan 8, 2022

I placed hathach/tinyusb#1273