Giter Club home page Giter Club logo

ws2812-pio-rs's People

Contributors

9names avatar ithinuel avatar jannic avatar lu15w1r7h avatar mgottschlag avatar weirdconstructor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ws2812-pio-rs's Issues

Clock divider calculation

Hello,
i'm trying to connect to a ws2812e led strip with my pi_pico board.
I'm having a rather terrible level shifter on my setup which leads to messy signals, the level shifters struggles to push the voltage to 5v5 on the output side which leads to most of the pwm signal beeing closer to 3v3 for most of the high phases of the signal.
That's my problem really but just for the explanation.
The issue is i tested this setup with the ws2812 micropython library and had no issues with my led strip.
Once i switched to rust and your library, i started to notice issues with the signal and incorrect outputs on my led strips.
After diving into both code bases pio state machine setup i noticed a difference in calculating the clock divider value.

this is how the c implementation of the micropython code calculates the divider values.

// Frequency given in Hz, compute clkdiv from it.
uint64_t div = (uint64_t)clock_get_hz(clk_sys) * 256ULL / (uint64_t)args[ARG_freq].u_int;
if (!(div >= 1 * 256 && div <= 65536 * 256)) {
  mp_raise_ValueError(MP_ERROR_TEXT("freq out of range"));
}
clkdiv_int = div / 256;
clkdiv_frac = div & 0xff;

and this is your solution.

// Configure the PIO state machine.
let bit_freq = FREQ * CYCLES_PER_BIT;
let mut int = clock_freq / bit_freq;
let rem = clock_freq - (int * bit_freq);
let frac = (rem * 256) / bit_freq;
assert!(
    (1..=65536).contains(&int) && (int != 65536 || frac == 0),
    "(System Clock / {}) must be within [1.0, 65536.0].",
    bit_freq.to_kHz()
);

// 65536.0 is represented as 0 in the pio's clock divider
if int == 65536 {
    int = 0;
}
// Using lossy conversion because range have been checked
let int: u16 = int as u16;
let frac: u8 = frac as u8;

the problem with your solution might be that dividing the clock freq and after that multiplying it by 256 is that the calculation increases the interger maths error.
By expanding the calculation to 64 bits as in the python base solution and then multiplying it by 256 and dividing it by 256 again after the divisions is that the incluence of calcualtion errors goes down.

After i have to confess rather clumsily trying to port the python code to rust i came up with this solution and experience no further errors in my led output.

let bit_freq = FREQ * CYCLES_PER_BIT;
let div: u64 = ((clock_freq.to_Hz() as u64)  * 256u64) / (bit_freq.to_Hz() as u64);
       
assert!(div >= 1 * 256 && div <= 65536 * 256,
    "(System Clock / {}) must be within [1.0, 65536.0].",
    bit_freq.to_kHz()
);

// Using lossy conversion because range have been checked
let int: u16 = (div / 256u64) as u16;
let frac: u8 = div as u8;

Reset signal duration

I'm curious how the reset signal duration value of 60us was calculated?

The timing seems very tight to the tolerances of the chip (>50us) and I can't find any code which accommodates any flush of the 8-word FIFO buffer. Ws2812::write adds 60us onto Ws2812Direct::write but that only blocks until the write to the FIFO buffer is complete, not until the PIO has processed it. In the worst case I think this lag could be -

8 (word tx only FIFO buffer) x  3 (colours) x 8 (bits) x 1.25e-6 (800kHz) = 2.4e-4 = 2.4ms

The original example from the RP Pico datasheet uses a value of 10ms. This seems large enough to cover any required flush and the reset signal itself. However, 60us does not.

Please note I haven't taken a probe to the actual output or observed any real-world problems. I'm just trying to understand it from the specifications and the code written. A perfectly reasonable answer would be that someone attached a scope to the pin and observed the real-world timings (assuming sufficient data to fill the buffer)!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.