Skip to content

Fix host issue with with turnaround (inter-packet) timing #179

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

Merged
merged 6 commits into from
May 13, 2025

Conversation

hathach
Copy link
Contributor

@hathach hathach commented Apr 29, 2025

USB 2.0 specs 7.1.18 specify 2 bit time for inter-packet, especially when switching bus direction.
image

This is essential when we overlock mcu to higher clock such as 240/264 Mhz. We basically send handshake too fast after EOP and give device no time to capture the bus correcly. This also occurs with some slow device such as LS gamepad in adafruit/circuitpython#10243

turnaround delay is done in cycle which is conveniently = 4 pp->clk_div_/fsls_tx.div_int. Since we also have overhead, I think it is best to do 1.5 bit time for LS and 1 bit time for FS.

  • I also notice that we mistakenly send SOF instead of Keep-alive on the LS bus, therefore fix it as well.

@tannewt @FoamyGuy @ladyada Please try to see if this fixes your issue with gamepad (direct attached) and 264Mhz overclocked with hub + mouse + keyboard on fruit jam

PS: Also include the fix workaround for the famous RP2350-E9. all rp2350 A2/B0 cannot reliably read gpio when floating. This is the root cause that pio host cannot detect the device disconnection ((floating), when it tries to read line state, it is always get J state instead of SE0.
image
image

…after received data from device

host: send keep-alive packet instead of SOF on lowspeed bus
@hathach hathach force-pushed the fix-lowspeed-turraround branch from 1173833 to 791bce4 Compare April 29, 2025 12:42
@hathach hathach marked this pull request as draft May 7, 2025 15:13
@hathach hathach force-pushed the fix-lowspeed-turraround branch from 8c89c99 to 791bce4 Compare May 8, 2025 15:01
@hathach hathach marked this pull request as ready for review May 8, 2025 15:53
@hathach
Copy link
Contributor Author

hathach commented May 8, 2025

PR is ready for review, @sekigon-gonnoc please let me know if the changes make sense to you. rp2350 still has difficulty detecting device disconnection, somehow it couldn't read SE0 on line state after device disconnected. I am still checking it, but we can fix it with another PR. This is crucial to get host working with more low speed device and/or overclock the rp2350.

src/pio_usb.c Outdated
@@ -97,7 +97,7 @@ void __not_in_flash_func(pio_usb_bus_usb_transfer)(pio_port_t *pp,
continue;
}
pp->pio_usb_tx->irq = IRQ_TX_ALL_MASK; // clear complete flag
while (*pc < PIO_USB_TX_ENCODED_DATA_COMP) {
while (*pc <= PIO_USB_TX_ENCODED_DATA_COMP) {
Copy link
Owner

Choose a reason for hiding this comment

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

This line is probably timing critical for RP2040/RP2350 without overclocking. Please consider controlling it with a compile-time option.
c1fea8c

Copy link
Contributor Author

@hathach hathach May 9, 2025

Choose a reason for hiding this comment

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

I found that this is required to work with some low speed device even e.g https://www.adafruit.com/product/6285 with standard 120Mhz espcially with rp2350. since it is M33 it runs much faster than rp2040 with the same clock. Some LS device is probably too slow without this. How about we only do this when the pp is running as low speed host only ?

Copy link
Owner

@sekigon-gonnoc sekigon-gonnoc May 9, 2025

Choose a reason for hiding this comment

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

How about we only do this when the pp is running as low speed host only ?

Sounds good

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thank you, I push the update to only wait for complet EOP sent for low speed mode only, along with some description. I hope my comment make sense to you.

@hathach hathach force-pushed the fix-lowspeed-turraround branch from ca396a0 to 08a9b06 Compare May 9, 2025 11:44
src/pio_usb.c Outdated
if (pp->low_speed) {
turnaround_in_cycle = 6 * pp->clk_div_ls_tx.div_int; // 1.5 bit time
} else {
turnaround_in_cycle = 4 * pp->clk_div_fs_tx.div_int; // 1 bit time
Copy link
Contributor Author

Choose a reason for hiding this comment

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

actually I am not sure if we should wait 1-bit time for FS, since it is rather short, maybe we can omit it ? I haven't got any issue with FS, but didn't do much testing. Maybe we can comment that out for now.

pio_usb_bus_usb_transfer(pp, sof_packet_encoded, sof_packet_encoded_len);
} else {
// Send Keep alive for low speed
pio_usb_bus_usb_transfer(pp, keepalive_encoded, 1);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

LS only regconize keep alive

@@ -141,6 +141,18 @@ void pio_usb_bus_send_token(pio_port_t *pp, uint8_t token, uint8_t addr,

static __always_inline port_pin_status_t
pio_usb_bus_get_line_state(root_port_t *root) {
#ifdef PICO_RP2350
Copy link
Contributor Author

Choose a reason for hiding this comment

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

rp2350-E9 cause host failed to read SE0 when device unplugged (floating). It always read J-state. This workaround is needed.

// detection and NRZI decoding but it is unlikely.
// Exit since we've gotten an EOP.
// Timing critical: per USB specs, handshake must be sent within 2-7 bit-time strictly
if (pp->low_speed) {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

as with the pio_usb_bus_usb_transfer(), I think for FS, the overhead is probably more than 2-bit time and additional delay is not needed. We can enable this later if having issue with FS on highly overclocked cpu later on :)

gpio_set_input_enabled(root->pin_dm, false);

// short delay to drain leaked current, required when overclocked CPU, tested with 264Mhz
__asm volatile("nop; nop; nop; nop; nop; nop; nop; nop;");
Copy link
Contributor Author

Choose a reason for hiding this comment

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

added additional delay, needed when testing with the 264Mhz overlocked rp2350

@hathach
Copy link
Contributor Author

hathach commented May 9, 2025

@sekigon-gonnoc I have update the PR to only add inter-packet delay for low speed only, and add delay for E4 to drain leaked current even with 264Mhz rp2350. I think the PR is good for merge. let me know if you liek to make any other changes :)

while (*pc <= PIO_USB_TX_ENCODED_DATA_COMP) {
continue;
}
}
Copy link
Owner

Choose a reason for hiding this comment

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

if (pp->low_speed) {
    while (*pc <= PIO_USB_TX_ENCODED_DATA_COMP) {
      continue;
    }
} else { 
    while (*pc < PIO_USB_TX_ENCODED_DATA_COMP) {
    continue;
  }
}

This change may have less impact for the FS device

Copy link
Contributor Author

Choose a reason for hiding this comment

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

right, it looks better as well.

@hathach hathach requested a review from sekigon-gonnoc May 12, 2025 08:25
@sekigon-gonnoc sekigon-gonnoc merged commit d15f0c6 into sekigon-gonnoc:main May 13, 2025
7 checks passed
@hathach
Copy link
Contributor Author

hathach commented May 13, 2025

thank you very much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants