GithubHelp home page GithubHelp logo

phip1611 / ws2818-rgb-led-spi-driver Goto Github PK

View Code? Open in Web Editor NEW
19.0 5.0 6.0 1.83 MB

Simple, educational driver for WS28xx RGB LED (chains) written in Rust. It uses SPI device for timing. Needs Linux and works definitely on Raspberry Pi.

License: MIT License

Rust 100.00%

ws2818-rgb-led-spi-driver's Introduction

WS28xx RGB LED SPI Driver

This crate is a driver for WS28XX (WS2811, WS2812, WS2812B, WS2818) RGB LED chains/strips. They are also known as "NeoPixel" devices or "Smart LEDs".

Wait, there are already so many drivers for WS2811/WS2812 on crates.io?

At the beginning I was not aware of that WS2811, WS2812, WS2812B, ..., WS2818 are basically the same. I just did not notice it. I had WS2818 LEDs and there wasn't a driver for that specific product with WS2818 in its name. See these links to learn about the differences:

It seems like all of them work use the same protocol, though. That means this driver probably works for all of them.

About this driver

It's a simple, stripped down, educational example how to bring your LEDs to life. This [0] is an example device with chained WS2818 RGB LEDs that can be used with this driver. This driver only works on Linux systems with a SPI device, like Raspberry Pi [1]. This is needed because my driver operates at 15.6MHz. This is required because I need to reach specific timings in nanoseconds according to the specification while sending data [2]. WS28xx LEDs use a one wire protocol without a clock, therefore the timings during data transmission are important.

The SPI device in your Raspberry Pi has a reliable clock with high frequencies available. Regular GPIO pins won't work! Toggling GPIO pins takes 1µs (in my testing) which is WAY TOO SLOW! Therefore I use SPI. There is a clock device in hardware - much more reliable!

Find the MOSI-Pin on your device (e.g. Raspberry Pi) and connect it with DIN-Port of the LED. That's all what's needed.

Have a look into the examples/code for further explications. :)

There is no warranty that this will work on your setup! High frequency stuff is complicated!

demo

Demo using a 8x8 RGB LED matrix. DIN is connected with MOSI (SPI Out Port).

Examples

See https://github.com/phip1611/ws2818-rgb-led-spi-driver/tree/master/examples.

Cargo.toml

[dependencies]
ws2818-rgb-led-spi-driver = "<latest version>"
# or if you need no_std
ws2818-rgb-led-spi-driver = { version = "<latest version>", default-features = false }

Code

//! Example that definitely works on Raspberry Pi.
//! Make sure you have "SPI" on your Pi enabled and that MOSI-Pin is connected
//! with DIN-Pin of the LEDs. You just need DIN pin, no clock. WS2818 uses an one-wire-protocol.
//! See the specification for details.

use ws2818_rgb_led_spi_driver::adapter_gen::WS28xxAdapter;
use ws2818_rgb_led_spi_driver::adapter_spi::WS28xxSpiAdapter;
use ws2818_rgb_led_spi_driver::encoding::encode_rgb;

fn main() {
    println!("make sure you have \"SPI\" on your Pi enabled and that MOSI-Pin is connected with DIN-Pin!");
    let mut adapter = WS28xxSpiAdapter::new("/dev/spidev0.0").unwrap();

    // Method 1: encode first and write in two step (preferred way; better performance)
    {
        let mut spi_encoded_rgb_bits = vec![];
        // set first three pixels to bright red, bright green and bright blue
        spi_encoded_rgb_bits.extend_from_slice(&encode_rgb(255, 0, 0));
        spi_encoded_rgb_bits.extend_from_slice(&encode_rgb(0, 255, 0));
        spi_encoded_rgb_bits.extend_from_slice(&encode_rgb(0, 0, 255));
        adapter.write_encoded_rgb(&spi_encoded_rgb_bits).unwrap();
    }

    // Method 2: encode and write in one step
    {
        let mut rgb_values = vec![];
        // set first three pixels to bright red, bright green and bright blue
        rgb_values.push((255, 0, 0));
        rgb_values.push((0, 255, 0));
        rgb_values.push((0, 0, 255));
        adapter.write_rgb(&rgb_values).unwrap();
    }
}

CPU-intensive spin lock

My example code uses CPU intensive spin locks in order to work properly all the time. If you experience a flickering of the LEDs when using thread::sleep() instead, then please have a look at: #9

Links

[0] https://www.az-delivery.de/products/u-64-led-panel?variant=6127700738075
[1] https://www.raspberrypi.org/documentation/hardware/raspberrypi/spi/README.md
[2] https://cdn-shop.adafruit.com/datasheets/WS2812.pdf

ws2818-rgb-led-spi-driver's People

Contributors

angelonfira avatar mannil avatar phip1611 avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar

ws2818-rgb-led-spi-driver's Issues

SPI frequency to drive LED

hey!
The library looks great however it would be super useful to define in the readme the frequency that the SPI clock line needs to be set to be able to drive the led. It seems not super clear!
Thanks

no-std support

Hi @phip1611 and thanks for your superb library!

Are you interested in adding a no-std support to the crate? Or maybe splitting into a no-std crate + linux spidev adapter?

While using linux is good for prototyping, sometimes it's better to wire everything up into a microcontroller. As far as I can tell, only minor tweaks are required to make the encoding/timings part platform-agnostic, and I guess I can make an attempt to separate the stuff.

So, what do you say?

Possible to remove CPU-intensive spinlock?

The spinlock in sleep_busy_waiting_ms takes 100% CPU power from one core of the pi. I am trying to replace it with something more efficient, with no success.

I tried replacing it with thread::sleep, but all the LEDs turn white, and I cannot figure out why that might be. The only difference I know of for these two methods is that the spinlock has ~2microsecond overhead while thread::sleep has ~100microsecond overhead. Full test commit: stonewareslord@f69279b; summary of change:

diff --git a/examples/src/bin/moving-pixel.rs b/examples/src/bin/moving-pixel.rs
--- a/examples/src/bin/moving-pixel.rs
+++ b/examples/src/bin/moving-pixel.rs
@@ -31,6 +34,28 @@ fn main() {
         adapter.write_encoded_rgb(&data).unwrap();
 
         i = (i + 1) % num_leds;
-        sleep_busy_waiting_ms(1000 / 10); // 100ms / 10Hz
+        thread::sleep(Duration::from_millis(ms));
     }
 }

I could maybe get that we need to fill the SPI buf at a consistent rate, but adding randomness to the sleep time has no effect (spinlock still works, thread::sleep still doesn't). Full test commit: stonewareslord@b12346e; summary of change:

diff --git a/examples/src/bin/moving-pixel.rs b/examples/src/bin/moving-pixel.rs
index e39faed..4d4447a 100644
--- a/examples/src/bin/moving-pixel.rs
+++ b/examples/src/bin/moving-pixel.rs
@@ -34,7 +36,7 @@ fn main() {
         adapter.write_encoded_rgb(&data).unwrap();
 
         i = (i + 1) % num_leds;
-        sleep_busy_waiting_ms(1000 / 10); // 100ms / 10Hz
+        sleep_busy_waiting_ms(1000 / 10) + rng.gen_range(0, 10); // 100ms / 10Hz
     }
 }

Is there some kind of timing issue I am not aware of here? I would expect the loop time after write_encoded_rbg should not matter and the only side effects of both of these functions is the sleep time.

P.S. Thank you for the amazing library!

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.