Skip to content
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

WS2812 example: Improve bandwidth tolerance #486

Merged
merged 1 commit into from
May 2, 2024

Conversation

nmcclatchey
Copy link
Contributor

@nmcclatchey nmcclatchey commented Mar 31, 2024

The WS2812 PIO example uses poor choices of T1, T2, and T3, leading to poor support for transmission frequencies other than 0.8 MHz. Specifically, the example PIO program, when run at a bit frequency of 0.8 MHz, is at the bounds of the tolerances specified in the WS2812B datasheet.
This PR improves the maximum bit frequency to 1.028 MHz while remaining within tolerance (a 28% improvement).

Context:

The WS2812B datasheet lists the following tolerances:

  • T0H = 0.4 us +- 0.15 us = 0.25 us .. 0.55 us
  • T1H = 0.8 us +- 0.15 us = 0.65 us .. 0.95 us
  • T0L = 0.85 us +- 0.15 us = 0.7 us .. 1 us
  • T1L = 0.45 us +- 0.15 us = 0.3 us .. 0.6 us
    Note: This gives a minimum possible time-per-bit of 0.95 us, and a maximum possible time-per-bit of 1.55 us

These relate to the example's constants T1, T2, T3 as follows:

  • T0H = T1 / (T1 + T2 + T3) / bit_frequency
  • T1H = (T1 + T2) / (T1 + T2 + T3) / bit_frequency
  • T0L = T2 / (T1 + T2 + T3) / bit_frequency
  • T1L = (T2 + T3) / (T1 + T2 + T3) / bit_frequency

Analysis of various choices of T1,T2,T3:

Here, I use T_bit to indicate the time required to transmit 1 bit, F_bit = 1 / T_bit as the maximum bit transmission frequency, and (T1,T2,T3) as a tuple of constants. In each case, I report the bounds on T_bit and F_bit required to stay within the tolerance intervals specified in the datasheet.

  1. Original example constants:
    • 1.25 us <= T_bit <= 1.25 us
    • 800,000 Hz <= F_bit <= 800,000 Hz
    • (T1,T2,T3) = (2,5,3) (total 10 PIO cycles / bit)
  2. Achieves theoretical maximum bandwidth:
    • 0.95 us <= T_bit <= 1.357 us
    • 736,843 <= F_bit <= 1,052,631 Hz
    • (T1,T2,T3) = (5,8,6) (total 19 PIO cycles / bit)
  3. High bandwidth with a nice clockdiv value when operating at 1 MHz bandwidth:
    • 0.97223 us <= T_bit <= 1.3888 us
    • 720,000 Hz <= F_bit <= 1,028,571 Hz
    • (T1,T2,T3) = (7,10,8) (total 25 PIO cycles / bit)
  4. Improved constants without increasing PIO cycles:
    • 1 us <= T_bit <= 1.357 us
    • 736,843 Hz <= F_bit <= 1,000,000 Hz
    • (T1,T2,T3) = (3,4,3) (total 10 PIO cycles / bit)
  5. Achieves theoretical minimum bandwidth:
    • 1.085 us <= T_bit <= 1.55 us
    • 645,162 Hz <= F_bit <= 921,658 Hz
    • (T1,T2,T3) = (11,8,12) (total 31 PIO cycles / bit)

Conclusion:

This PR implements timing 3., giving bandwidth options in the range 720000 Hz .. 1028571 Hz, and has been tested on a 12-LED WS2812B strip at 1 MHz. By making this adjustment, those using the WS2812 example as a starting point will have significantly greater freedom to experiment with alternate bandwidths, without replicating the work above.

Disclaimer:

Though I am currently employed by IBM, this PR is completely unrelated to my employment, and was undertaken without using either company time or resources.

@nmcclatchey nmcclatchey changed the base branch from master to develop March 31, 2024 04:09
@lurch
Copy link
Contributor

lurch commented Apr 2, 2024

See also the huge discussion in raspberrypi/pico-feedback#121

Adjusts constants to 3,3,4 to support higher bandwidths on any of WS2812, WS2812B, and SK6812 LEDs.
@nmcclatchey
Copy link
Contributor Author

nmcclatchey commented Apr 3, 2024

See also the huge discussion in raspberrypi/pico-feedback#121

Thank you. I had been unaware of that discussion. It appears to tackle a closely-related issue, though with a different focus (broad compatibility instead of bandwidth) and an additional constraint (10 PIO cycles).

In particular, that discussion focuses on maintaining compatibility with three types of LED (WS2812, WS2812B, & SK6812), implying the much-tighter timing constraints:

  • 0.25 us <= T0H <= 0.45 us
  • 0.75 us <= T0L <= 0.95 us
  • 0.65 us <= T1H <= 0.75 us
  • 0.45 us <= T1L <= 0.60 us

Notes:

  • The example PIO uses even timing for both T0 and T1 branches, so this implies 1.1 us <= T_bit <= 1.35.
    • To maximize bandwidth without knowing which LED is in use, constants 5,8,9 allow 813,397 Hz .. 909,090 Hz (1.1 us/bit .. 1.229 us/bit). Note: 22 PIO cycles
    • Constraining to 10 PIO cycles / bit, and requiring that the nominal 800,000 Hz bandwidth be supported requires constants 3,3,4, with supported bandwidths 800,000 Hz .. 888,888 Hz (1.125 us/bit .. 1.25 us/bit) regardless of which LED is targeted. These constants were also mentioned in the discussion thread.

I have updated the PR with the 3,3,4 constants mentioned in that discussion thread and analyzed above instead of closing this PR. The 2,5,3 constants appear to be unnecessarily suboptimal, and no action appears to have been taken as a result of the linked discussion.

@peterharperuk peterharperuk merged commit 51982de into raspberrypi:develop May 2, 2024
1 check passed
@peterharperuk
Copy link
Contributor

Thanks, merged

@nmcclatchey nmcclatchey deleted the improve-ws2812 branch August 15, 2024 00:00
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.

3 participants