Skip to content

fix(rp2040): replace loop counter with hw timer for USB SetAddressReq… #4796

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 2 commits into from
Mar 13, 2025

Conversation

rdon-key
Copy link
Contributor

Replacing Simple Loop Counter with Hardware Timer for USB SetAddressRequest Timeout to Improve Stability

Fix Related to Issue #4137

Overview

This pull request addresses Issue #4137, which involves USB enumeration issues on RP2040 devices.

Problem

The previous implementation relied on a simple loop counter to determine the timeout for SetAddressRequest. If SetAddressRequest fails, subsequent USB enumeration will not function correctly. This approach faces challenges due to environment-dependent timing variations caused by factors such as:

  • CPU clock speed
  • Compiler optimizations

Solution

This PR proposes replacing the timeout mechanism from a simple loop counter to a hardware timer. This ensures a precise and consistent timeout duration, eliminating variations across different environments.

Observations

  • On AMD A520 chipset systems, timeouts shorter than 500μs cause instability in SetAddressRequest
  • @sago35 measured the actual timeout value on the SAMD21, which was approximately 570μs
  • Based on this measured value, adopting a similar timeout value in this implementation improves reliability

Benefits

  • Ensures accurate timeout duration
  • Improves reliability and stability across different environments
  • Negligible overhead introduced by the hardware timer
  • Enhances the robustness of the USB protocol
  • Eliminates dependence on simple loop counters, which can vary unpredictably across systems

Test Results

Three test scenarios were observed with packet captures shown below:

Packet Capture Comparison

1. Failure (AMD PC)

No. Time Source Destination Protocol Length Info
2149 4.014954783 host broadcast USBLL 3 SOF
2150 4.015122033 host 0 USBLL 3 SETUP
2151 4.015125283 host 0.0.0 USB 11 SET ADDRESS Request
2152 4.015134033 0 host USBLL 1 ACK
2153 4.015954783 host broadcast USBLL 3 SOF
2154 4.0159612 host 0 USBLL 3 IN
2155 4.015964533 0 host USBLL 3 DATA1
2156 4.015967866 host 0 USBLL 1 ACK
2157 4.016954783 host broadcast USBLL 3 SOF
2158 4.017954783 host broadcast USBLL 3 SOF
2159 4.018954783 host broadcast USBLL 3 SOF
2160 4.019954783 host broadcast USBLL 3 SOF
2161 4.020954783 host broadcast USBLL 3 SOF
2162 4.0219547 host broadcast USBLL 3 SOF
2163 4.0229547 host broadcast USBLL 3 SOF
2164 4.0239547 host broadcast USBLL 3 SOF
2165 4.0249547 host broadcast USBLL 3 SOF
2166 4.0259547 host broadcast USBLL 3 SOF
2167 4.0268362 host 1 USBLL 3 SETUP
2168 4.02683945 host 0.1.0 USB 11 GET DESCRIPTOR Request DEVICE
2169 4.0269547 host broadcast USBLL 3 SOF
2170 4.0269612 host 1 USBLL 3 SETUP
2171 4.02696445 host 0.1.0 USB 11 GET DESCRIPTOR Request DEVICE
2172 4.0279547 host broadcast USBLL 3 SOF
2173 4.0279612 host 1 USBLL 3 SETUP
2174 4.02796445 host 0.1.0 USB 11 GET DESCRIPTOR Request DEVICE
2175 4.0289547 host broadcast USBLL 3 SOF
2176 4.0299547 host broadcast USBLL 3 SOF
2177 4.0309547 host broadcast USBLL 3 SOF
2178 4.0319547 host broadcast USBLL 3 SOF
2179 4.0329547 host broadcast USBLL 3 SOF

2. Success (Intel PC)

No. Time Source Destination Protocol Length Info
15366 5.06582645 host broadcast USBLL 3 SOF
15367 5.066320283 host 0 USBLL 3 SETUP
15368 5.066323533 host 0.0.0 USB 11 SET ADDRESS Request
15369 5.0663322 0 host USBLL 1 ACK
15370 5.066334283 host 0 USBLL 3 IN
15371 5.066337616 0 host USBLL 3 DATA1
15372 5.06634095 host 0 USBLL 1 ACK
15373 5.06682645 host broadcast USBLL 3 SOF
15374 5.06782645 host broadcast USBLL 3 SOF
15375 5.06882645 host broadcast USBLL 3 SOF
15376 5.06982645 host broadcast USBLL 3 SOF
15377 5.07082645 host broadcast USBLL 3 SOF
15378 5.07182645 host broadcast USBLL 3 SOF
15379 5.07282645 host broadcast USBLL 3 SOF
15380 5.07382645 host broadcast USBLL 3 SOF
15381 5.07482645 host broadcast USBLL 3 SOF
15382 5.07582645 host broadcast USBLL 3 SOF
15383 5.076411533 host 4 USBLL 3 SETUP
15384 5.076414866 host 0.4.0 USB 11 GET DESCRIPTOR Request DEVICE
15385 5.076423533 4 host USBLL 1 ACK
15386 5.076426616 host 4 USBLL 3 IN
15387 5.07642995 0.4.0 host USB 21 GET DESCRIPTOR Response DEVICE
15388 5.076445283 host 4 USBLL 1 ACK
15389 5.076447616 host 4 USBLL 3 OUT
15390 5.076450866 host 4 USBLL 3 DATA1
15391 5.0764542 4 host USBLL 1 ACK

3. Success (AMD PC with USB hub)

No. Time Source Destination Protocol Length Info
493 5.055081866 host broadcast USBLL 3 SOF
494 5.05557795 host 0 USBLL 3 SETUP
495 5.055581116 host 0.0.0 USB 11 SET ADDRESS Request
496 5.055589783 0 host USBLL 1 ACK
497 5.055711283 host 0 USBLL 3 IN
498 5.0557147 0 host USBLL 3 DATA1
499 5.055717783 host 0 USBLL 1 ACK
500 5.056081866 host broadcast USBLL 3 SOF
501 5.057081866 host broadcast USBLL 3 SOF
502 5.058081866 host broadcast USBLL 3 SOF
503 5.059081866 host broadcast USBLL 3 SOF
504 5.060081866 host broadcast USBLL 3 SOF
505 5.061081866 host broadcast USBLL 3 SOF
506 5.062081866 host broadcast USBLL 3 SOF
507 5.063081866 host broadcast USBLL 3 SOF
508 5.064081783 host broadcast USBLL 3 SOF
509 5.065081866 host broadcast USBLL 3 SOF
510 5.06579295 host 5 USBLL 3 SETUP
511 5.0657962 host 0.5.0 USB 11 GET DESCRIPTOR Request DEVICE
512 5.06580495 5 host USBLL 1 ACK
513 5.0658137 host 5 USBLL 3 IN
514 5.065817116 0.5.0 host USB 21 GET DESCRIPTOR Response DEVICE
515 5.065832366 host 5 USBLL 1 ACK
516 5.06584195 host 5 USBLL 3 OUT
517 5.0658452 host 5 USBLL 3 DATA1
518 5.065848616 5 host USBLL 1 ACK
519 5.066081866 host broadcast USBLL 3 SOF
520 5.067081783 host broadcast USBLL 3 SOF
521 5.068081783 host broadcast USBLL 3 SOF

These packet captures demonstrate how the implementation with a simple loop counter affects USB communication sequences across different platforms.

After Implementation with Hardware Timer

After implementing the hardware timer solution, all platforms showed successful USB enumeration:

1. Success (Intel PC with hardware timer)

No. Time Source Destination Protocol Length Info
1445 2.336244366 host broadcast USBLL 3 SOF
1446 2.336799033 host 0 USBLL 3 SETUP
1447 2.336802283 host 0.0.0 USB 11 SET ADDRESS Request
1448 2.336811033 0 host USBLL 1 ACK
1449 2.336813116 host 0 USBLL 3 IN
1450 2.33681645 0 host USBLL 3 DATA1
1451 2.336819783 host 0 USBLL 1 ACK
1452 2.337244366 host broadcast USBLL 3 SOF
1453 2.338244366 host broadcast USBLL 3 SOF
1454 2.339244366 host broadcast USBLL 3 SOF
1455 2.340244366 host broadcast USBLL 3 SOF
1456 2.341244366 host broadcast USBLL 3 SOF
1457 2.342244366 host broadcast USBLL 3 SOF
1458 2.343244366 host broadcast USBLL 3 SOF
1459 2.344244366 host broadcast USBLL 3 SOF
1460 2.345244366 host broadcast USBLL 3 SOF
1461 2.346244366 host broadcast USBLL 3 SOF
1462 2.347244366 host broadcast USBLL 3 SOF
1463 2.347296116 host 4 USBLL 3 SETUP
1464 2.347299366 host 0.4.0 USB 11 GET DESCRIPTOR Request DEVICE
1465 2.347308116 4 host USBLL 1 ACK
1466 2.347311116 host 4 USBLL 3 IN
1467 2.347314533 0.4.0 host USB 21 GET DESCRIPTOR Response DEVICE
1468 2.347329783 host 4 USBLL 1 ACK
1469 2.347332116 host 4 USBLL 3 OUT
1470 2.347335366 host 4 USBLL 3 DATA1
1471 2.347338783 4 host USBLL 1 ACK
1472 2.348244366 host broadcast USBLL 3 SOF
1473 2.349244366 host broadcast USBLL 3 SOF

2. Success (AMD PC with USB hub with hardware timer)

No. Time Source Destination Protocol Length Info
1123 3.698225716 host broadcast USBLL 3 SOF
1124 3.69858605 host 0 USBLL 3 SETUP
1125 3.698589216 host 0.0.0 USB 11 SET ADDRESS Request
1126 3.698597966 0 host USBLL 1 ACK
1127 3.698730216 host 0 USBLL 3 IN
1128 3.69873355 0 host USBLL 3 DATA1
1129 3.698736883 host 0 USBLL 1 ACK
1130 3.699225716 host broadcast USBLL 3 SOF
1131 3.700225716 host broadcast USBLL 3 SOF
1132 3.701225716 host broadcast USBLL 3 SOF
1133 3.702225716 host broadcast USBLL 3 SOF
1134 3.703225716 host broadcast USBLL 3 SOF
1135 3.704225716 host broadcast USBLL 3 SOF
1136 3.705225716 host broadcast USBLL 3 SOF
1137 3.706225716 host broadcast USBLL 3 SOF
1138 3.707225716 host broadcast USBLL 3 SOF
1139 3.708225716 host broadcast USBLL 3 SOF
1140 3.70896355 host 5 USBLL 3 SETUP
1141 3.708966716 host 0.5.0 USB 11 GET DESCRIPTOR Request DEVICE
1142 3.708975466 5 host USBLL 1 ACK
1143 3.708983966 host 5 USBLL 3 IN
1144 3.708987383 0.5.0 host USB 21 GET DESCRIPTOR Response DEVICE
1145 3.70900255 host 5 USBLL 1 ACK
1146 3.709225716 host broadcast USBLL 3 SOF
1147 3.70923055 host 5 USBLL 3 OUT
1148 3.709233716 host 5 USBLL 3 DATA1
1149 3.70923705 5 host USBLL 1 ACK
1150 3.710225716 host broadcast USBLL 3 SOF
1151 3.711225716 host broadcast USBLL 3 SOF

3. Success (AMD PC with hardware timer)

No. Time Source Destination Protocol Length Info
104 3.196348616 host broadcast USBLL 3 SOF
105 3.196902866 host 0 USBLL 3 SETUP
106 3.196906116 host 0.0.0 USB 11 SET ADDRESS Request
107 3.196914783 0 host USBLL 1 ACK
108 3.197348616 host broadcast USBLL 3 SOF
109 3.197355033 host 0 USBLL 3 IN
110 3.19735845 0 host USBLL 3 DATA1
111 3.197361783 host 0 USBLL 1 ACK
112 3.198348616 host broadcast USBLL 3 SOF
113 3.199348616 host broadcast USBLL 3 SOF
114 3.200348616 host broadcast USBLL 3 SOF
115 3.201348616 host broadcast USBLL 3 SOF
116 3.202348616 host broadcast USBLL 3 SOF
117 3.203348616 host broadcast USBLL 3 SOF
118 3.204348616 host broadcast USBLL 3 SOF
119 3.205348533 host broadcast USBLL 3 SOF
120 3.206348533 host broadcast USBLL 3 SOF
121 3.207348533 host broadcast USBLL 3 SOF
122 3.207794116 host 1 USBLL 3 SETUP
123 3.207797366 host 0.1.0 USB 11 GET DESCRIPTOR Request DEVICE
124 3.207806116 1 host USBLL 1 ACK
125 3.208348533 host broadcast USBLL 3 SOF
126 3.20835495 host 1 USBLL 3 IN
127 3.208358283 0.1.0 host USB 21 GET DESCRIPTOR Response DEVICE
128 3.208373616 host 1 USBLL 1 ACK
129 3.209348533 host broadcast USBLL 3 SOF
130 3.20935495 host 1 USBLL 3 OUT
131 3.2093582 host 1 USBLL 3 DATA1
132 3.209361616 1 host USBLL 1 ACK

The most significant improvement is seen in the third scenario (AMD PC), which previously failed with the loop counter implementation but now successfully completes the SetAddressRequest and proceeds with enumeration when using the hardware timer.

These results conclusively demonstrate that the hardware timer implementation provides consistent behavior across all tested platforms, eliminating the timing variability issues that previously caused failures on certain systems.

@deadprogram
Copy link
Member

Hello @rdon-key thank you for your PR.

Looks like you need to run go fmt on your changes:

Unformatted:
  src/machine/machine_rp2040_usb.go
make: *** [GNUmakefile:185: fmt-check] Error 1

Can you please correct that and then rebase those changes into this PR? Thanks!

@rdon-key rdon-key force-pushed the fix/usb-set-address-hw-timer branch from 97cdc50 to bc7d82b Compare March 11, 2025 13:41
@rdon-key
Copy link
Contributor Author

@deadprogram
Thank you for your feedback.

I've fixed the formatting issue and rebased the changes into a single commit. I ran go fmt to adjust the code style and updated the PR.

Copy link
Contributor

@eliasnaur eliasnaur left a comment

Choose a reason for hiding this comment

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

Nice find. I'd like to see the fix ported to rp2350 as well, or merely making the delay portable. See comments.

// last, set the device address to that requested by host
// wait for transfer to complete
timeout := 3000
rp.USBCTRL_REGS.SIE_STATUS.Set(rp.USBCTRL_REGS_SIE_STATUS_ACK_REC)
start := rp.TIMER.TIMERAWL.Get()
Copy link
Contributor

@eliasnaur eliasnaur Mar 11, 2025

Choose a reason for hiding this comment

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

For portability to rp2350, I suggest using the global variable machine.timer and adding a method for short delays.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@eliasnaur Thank you for your review. Based on your suggestion, I've added the waitUntil function to machine.timer. Looking forward to your further feedback.

Copy link
Contributor Author

@rdon-key rdon-key Mar 12, 2025

Choose a reason for hiding this comment

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

@eliasnaur
As you can see, the implementation successfully handles the SET ADDRESS Request and proceeds with enumeration on rp2350 as well.

No. Time Source Destination Protocol Length Info
876 5.087713700 host broadcast USBLL 3 SOF
877 5.088171533 host 0.0 USBLL 3 SETUP
878 5.088174783 host 0.0.0 USB 11 SET ADDRESS Request
879 5.088183450 0.0 host USBLL 1 ACK
880 5.088713700 host broadcast USBLL 3 SOF
881 5.088720116 host 0.0 USBLL 3 IN
882 5.088723450 0.0 host USBLL 3 DATA1
883 5.088726783 host 0.0 USBLL 1 ACK
884 5.089713700 host broadcast USBLL 3 SOF
885 5.090713700 host broadcast USBLL 3 SOF
886 5.091713700 host broadcast USBLL 3 SOF
887 5.092713700 host broadcast USBLL 3 SOF
888 5.093713700 host broadcast USBLL 3 SOF
889 5.094713700 host broadcast USBLL 3 SOF
890 5.095713700 host broadcast USBLL 3 SOF
891 5.096713700 host broadcast USBLL 3 SOF
892 5.097713700 host broadcast USBLL 3 SOF
893 5.098713700 host broadcast USBLL 3 SOF
894 5.098936033 host 1.0 USBLL 3 SETUP
895 5.098939283 host 0.1.0 USB 11 GET DESCRIPTOR Request DEVICE
896 5.098947950 1.0 host USBLL 1 ACK
897 5.099713700 host broadcast USBLL 3 SOF
898 5.099720116 host 1.0 USBLL 3 IN
899 5.099723450 0.1.0 host USB 21 GET DESCRIPTOR Response DEVICE
900 5.099738783 host 1.0 USBLL 1 ACK
901 5.100713616 host broadcast USBLL 3 SOF
902 5.100720033 host 1.0 USBLL 3 OUT
903 5.100723283 host 1.0 USBLL 3 DATA1
904 5.100726700 1.0 host USBLL 1 ACK

@rdon-key rdon-key force-pushed the fix/usb-set-address-hw-timer branch from 4328d19 to 6ff0baf Compare March 12, 2025 09:10
@rdon-key rdon-key force-pushed the fix/usb-set-address-hw-timer branch from 6ff0baf to 8135eb3 Compare March 12, 2025 11:47
@sago35
Copy link
Member

sago35 commented Mar 12, 2025

You can safely rebase, so please rebase onto the latest dev branch as the target. @rdon-key

$ git checkout usb-set-address-hw-timer
$ git rebase upstream/dev 
$ git push origin usb-set-address-hw-timer --force-with-lease --force-if-included

@sago35
Copy link
Member

sago35 commented Mar 12, 2025

It’s difficult to determine whether 570us is truly the correct value. However, on RP2040—or more specifically, RP2350—the timeout might be too short.

Also, simply using a counter-based wait can cause issues when overclocking, so using a timer-based wait is a good approach.

At this point, I believe this PR improves the situation, so I’m in favor of it.

@rdon-key rdon-key force-pushed the fix/usb-set-address-hw-timer branch from 74ae3bc to ebe7781 Compare March 12, 2025 15:26
@sago35 sago35 changed the base branch from release to dev March 12, 2025 15:27
Copy link
Member

@sago35 sago35 left a comment

Choose a reason for hiding this comment

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

LGTM

@deadprogram
Copy link
Member

Now squash/merging. Thanks for working on this @rdon-key and to @sago35 @eliasnaur for review.

@deadprogram deadprogram merged commit 4f7c64c into tinygo-org:dev Mar 13, 2025
18 checks passed
@rdon-key
Copy link
Contributor Author

@deadprogram @sago35 @eliasnaur
Thank you for merging this PR. I appreciate your guidance with my novice contribution. This has been a great learning experience. I look forward to continuing to contribute to the TinyGo project in the future.

@rdon-key rdon-key deleted the fix/usb-set-address-hw-timer branch March 14, 2025 07:14
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.

4 participants