-
-
Notifications
You must be signed in to change notification settings - Fork 8.3k
stm32/usb_cdc: Double data speed sending from micropython to computer #6172
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
Conversation
I have used this ring buffer method ever since I saw the article :-) we were just sniffing the USB traffic the other day and noticed this ... |
1 similar comment
I have used this ring buffer method ever since I saw the article :-) we were just sniffing the USB traffic the other day and noticed this ... |
ports/stm32/usbd_cdc_interface.c
Outdated
} | ||
|
||
static uint16_t inline usbd_cdc_tx_buffer_size(usbd_cdc_itf_t *cdc) { | ||
return tx_waiting = cdc->tx_buf_ptr_in - cdc->tx_buf_ptr_out; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure what the intention here is, maybe just delete tx_waiting =
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy/paste mistake - I had fixed that but the fix must have been on the test branch that didn't get pushed up here again
ports/stm32/usbd_cdc_interface.c
Outdated
|
||
static void usbd_cdc_tx_buffer_put(usbd_cdc_itf_t *cdc, uint8_t data) { | ||
cdc->tx_buf[usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_in)] = data; | ||
cdc->tx_buf_ptr_in = cdc->tx_buf_ptr_in + 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use ++
or += 1
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for sure, yes this long hand version of the line was left over from a gradual test/transition to this algorithm which missed the final clean up.
Thanks, this is a nice find! My VCP speed tests show about a 5-10% increase in throughput (up to about 9.8MBits/s on an FS port). Did you measure a double increase for a specific scenario of data transfer? This was proposed for ringbuf in #4920, and as noted there it introduces a restriction on the size of the buffer: it must be a power of 2, and the maximum size is half of the size of the index (in this case the index is 16-bit, so the maximum size would be 32767 bytes rounded to 16384 for a power-of-2, if I understand correctly). I think those restrictions are acceptable for USB buffer sizes, and the existing configuration values already satisfy them. But there's definitely going to need to be a big notice (in |
9d6b2f3
to
3a4a959
Compare
The speed up does appear to depend on the driver being used on the computer, with all my testing being on windows. Logs from firmware side using before: I presume your testing was on linux? I'm not surprised the usb driver works better there... Before this change, the ringbuffer was already restricted to powers of two sizing because it was using a mask based method of rollover, the comment on the define where the size is configured was wrong / out of date. I've updated it now. |
Yes. Sending various packet sizes in both directions, using pyserial on the PC side.
True! |
ports/stm32/usbd_cdc_interface.c
Outdated
} | ||
|
||
static uint16_t usbd_cdc_tx_send_length(usbd_cdc_itf_t *cdc) { | ||
uint16_t to_end = USBD_CDC_TX_DATA_SIZE - usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_out) ; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no space before ;
ports/stm32/usbd_cdc_interface.c
Outdated
|
||
static void usbd_cdc_tx_buffer_put(usbd_cdc_itf_t *cdc, uint8_t data) { | ||
cdc->tx_buf[usbd_cdc_tx_buffer_mask(cdc->tx_buf_ptr_in)] = data; | ||
cdc->tx_buf_ptr_in ++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no space before ++
ports/stm32/usbd_cdc_interface.c
Outdated
cdc->tx_buf_ptr_in ++; | ||
} | ||
|
||
static uint8_t* usbd_cdc_tx_buffer_getp(usbd_cdc_itf_t *cdc, uint16_t len) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
*
needs to go after the space (see uncrustify output in Travis)
3a4a959
to
40106da
Compare
Sorry yes, I need to get into a strict habit of running codeformat.py before push, particularly as you've now made it so easy to run! |
Thanks for updating, rebased and merged in e4fcd21 |
Fix supervisor.reload
stm32/usb_cdc: Fix tx ringbuffer to remove full == size-1 limitation.
The current usb virtual serial port tx ringbuffer is the basic implementation where it can only be filled to a maximum of
buffer size-1
.For a 1024 size buffer this means the largest packet that can be sent is 1023.
Once this is sent though, the next byte copied in goes to the final byte in the buffer, so must be sent as a 1 byte packet before the read pointer can be wrapped around. So in large streaming transfers, watching the usb sniffer you basically get alternating 1023 byte packets then 1 byte packets.
By switching the ringbuffer to the different scheme that doesn't have the full limitation, we can get constant 1023 packets.
For a simple explanation of the two schemes, look at the first and last implementations discussed here: https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/
Note: I have not merged this with the circular buffer from
ringbuf.h
due to the need to read from the buffer in chunks rather than single bytes, as well as the de-coupled copy of the read pointer.The RX buffer could likely do with a similar change, though as it's not read from in chunks like the TX buffer it doesn't present the same issue, all that's lost is one byte capacity of the buffer.