Git Product home page Git Product logo

esp32-neopixel-ws2812-rmt's Introduction

ESP32-NeoPixel-WS2812-RMT

NeoPixel (WS2812) Driver Example code using RMT peripheral

This project contains example code for driving a chain of NeoPixels connected to an ESP32 using the RMT peripheral build into the micro.

This code assumes you are using FreeRTOS.

Pros

  • It's very simple to use!
  • The code utilizes hardware to drive the data out line so your application can be free to do other things.
  • Easily and consistently meets the timing requirements spec'd out by the WS2812 datasheet.

Cons

Because of the way the ESP32 RMT peripheral works this technique for driving NeoPixels is a little heavy on memory usage. It requires (4 bytes * 24 * NUM_LEDS) of dedicated memory.

Usage

Copy the source and header files into your project. Update the following config options based on your project needs / arrangement.

  • CONFIG_WS2812_NUM_LEDS
  • CONFIG_WS2812_LED_RMT_TX_GPIO
  • CONFIG_WS2812_T0H // 0 bit high time
  • CONFIG_WS2812_T1H // 1 bit high time
  • CONFIG_WS2812_T0L // 0 bit low time
  • CONFIG_WS2812_T1L // 1 bit low time

To calculate values for these configuration times, multiply the desired time in micro seconds (μs or us in data sheets) by the default clock rate in MHz and divide by 2. E.g., for 280ns (0.28μs) on an ESP32 with an 80MHz clock: 0.28 * 80 / 2 = 11.2 => 11 (rounded when needed)

In your application init section call void ws2812_control_init(void) to initialize the RMT peripheral with the correct configuration.

Whenever you need to update the LEDs simply call void ws2812_write_leds(struct led_state new_state). The led_state structure just contains an array of 32-bit integers - one for each LED - that you must set to the desired RGB values. The bottom three bytes of each value are R, G and B.

Note: many surface-mount addressable LEDs that use this protocol arrange the bytes G, R, B instead of R, G, B.

Example

#include "ws2812_control.h"

#define RED   0xFF0000
#define GREEN 0x00FF00
#define BLUE  0x0000FF

int main(void)
{
  ws2812_control_init();

  struct led_state new_state;
  new_state.leds[0] = RED;
  new_state.leds[1] = GREEN;
  new_state.leds[2] = BLUE;

  ws2812_write_leds(new_state);
}

Timing

This code is tuned based on the timing specifications indicated in the following datasheet provided by Sparkfun: https://cdn.sparkfun.com/datasheets/Components/LED/COM-12877.pdf

LED TIMINGS, per their datasheets:

WS2811: (2.5us bit time, 400Kbps)
T0H: 0.5us <-- 0 bit
T0L: 2.0us
T1H: 1.2us <-- 1 bit
T1L: 1.3us
RES: 50us
WS2812: (1.25us bit time, 800Kbps)
T0H: 0.35us <-- 0 bit
T0L: 0.8us
T1H: 0.7us <-- 1 bit
T1L: 0.6us
RES: 50us
WS2812b: (1.25us bit time, 800Kbps)
T0H: 0.4us <-- 0 bit
T0L: 0.85us
T1H: 0.8us <-- 1 bit
T1L: 0.45us
RES: 50us

If you use WiFi, you may find that it causes problems with the LEDs not being set correctly. You can use xTaskCreatePinnedToCore to run the thread which initializes the library (and registers the rtm_isr), to run on core 1.

Contribution

If you find a problem or have ideas about how to improve this please submit a PR and I will happily review and merge. Thanks!

Enjoy!

esp32-neopixel-ws2812-rmt's People

Contributors

bcran avatar datanoisetv avatar davidhbrown avatar jschaenzle avatar justintconroy avatar nicholas-gh avatar odx avatar thomascastleman avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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  avatar

esp32-neopixel-ws2812-rmt's Issues

Bad pixel values with Wifi

The project works GREAT. However, When I add Wifi to my project - I often get pixels set incorrectly/randomly. The problem predictably gets much worse if I start pinging the ESP32 like crazy (more network traffic).

I have seen similar cases in other project where interrupts are enabled and it throws the timing of of the pixel updates. I am assuming this is is a problem where network interrupts (or threads?) are being prioritized over the RMT interrupts, making the additional "half" buffer fills happen too late?

I'm struggling to fix this - don't know if anyone else has any more insight for me,

not work without flag = 0

With this module ESP32-NeoPixel-WS2812-RMT not work.
http://github.com/wuxx/nanoesp32-s2/blob/master/doc/nanoESP32-S2.jpg
When add attribute flag = 0 then it works!

void ws2812_control_init(void)
{
  rmt_config_t config;// = RMT_DEFAULT_CONFIG_TX(LED_RMT_TX_GPIO, LED_RMT_TX_CHANNEL);
  config.rmt_mode = RMT_MODE_TX;
  config.channel = LED_RMT_TX_CHANNEL;
  config.gpio_num = LED_RMT_TX_GPIO;
  config.mem_block_num = 3;
  config.flags = 0;             <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<fix
  config.tx_config.loop_en = false;
  config.tx_config.carrier_en = false;
  config.tx_config.idle_output_en = true;
  config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
  config.clk_div = 2;

  ESP_ERROR_CHECK(rmt_config(&config));
  ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0));
}

Thanks for the project.

Hello Jordan,

I grabbed the code and put it in my project. It works fine (on 1 LED).
I will be hacking it up a bit, I will change the hardcoded pin-numbers into runtime parameters.
Your solution using the RMT was the most elegant one I found for controlling the WS2812 devices, no assembly or dependencies. Very good.

The best wishes from The Netherlands,
Edwin

After some time I found a serious bug in the code : reference to uninitialized data. Not so good!
Here is the fix (ws2812_control.c about line 24)

void ws2812_control_init(void)
{
    rmt_config_t config = {
        .rmt_mode = RMT_MODE_TX,
        .channel = LED_RMT_TX_CHANNEL,
        .gpio_num = LED_RMT_TX_GPIO,
        .mem_block_num = 3,
        .tx_config.loop_en = false,
        .tx_config.carrier_en = false,
        .tx_config.idle_output_en = true,
        .tx_config.idle_level = RMT_IDLE_LEVEL_LOW,
        .clk_div = 2,
    };

bug : partly uninitialized struct used, random errors, use RAII

rmt_config_t config;

is created on the stack but only some values of the memory are filled in.
This leads to the .flag part not being 0x00 when it should be, (it thinks RMT_CHANNEL_FLAGS_ALWAYS_ON) which leads to using the wrong clock source (1 MHz ref instead of RMT_BASECLK_APB)

The solution is simple, RAII : Resource Acquisition Is Initialization.

Just do it like this :

rmt_config_t config = {0,};

or even better:

rmt_config_t config = {
        .rmt_mode = RMT_MODE_TX,
        .channel = LED_RMT_TX_CHANNEL,
        .gpio_num = LED_RMT_TX_GPIO,
        .mem_block_num = 3,
        .tx_config.loop_en = false,
        .tx_config.carrier_en = false,
        .tx_config.idle_output_en = true,
        .tx_config.idle_level = RMT_IDLE_LEVEL_LOW,
        .clk_div = 2,
    };

Would like to see timings for other common LED types

Hi, I'm going to try to incorporate your lib into my project, but I'm going to have to arrive at the RMT bit timings by trial and error since I don't have access to a logic analyzer and I don't use WS2812 (I use WS2812b or WS2811). Below are some bit timing values that I've collected from the various WS28xx datasheets.

That said, I don't understand your "low" timing values. All bits should have a constant time, meaning the microseconds of a 0 bit should be the same as a 1 bit. Unfortunately, the WS2812 datasheet contradicts itself by saying all bit times are 1.25us, then it gives TH/TL values that don't add up to 1.25 (as the other datasheets do). The SparkFun datasheet you reference does give equal 0/1 bit times, but they are 1.71us each. The lights must be able to accept a lot of variance, but it's probably best to get as close as possible to the datasheet values for stability and transmission rate.

I assume that your CPU and peripheral clock speeds are the default values?

Thanks, dave

/* LED TIMINGS, per their datasheets:
*

  • WS2811: (1.25 or 2.5us bit time, 800 or 400Kbps)
  • T0H: 0.25 or 0.5us <-- 0 bit
  • T0L: 1.0 or 2.0us
  • T1H: 0.6 or 1.2us <-- 1 bit
  • T1L: 0.65 or 1.3us
  • RES: 50us
  • WS2812: (1.25us bit time, 800Kbps)
  • T0H: 0.35us <-- 0 bit
  • T0L: 0.8us
  • T1H: 0.7us <-- 1 bit
  • T1L: 0.6us
  • RES: 50us
  • WS2812b: (1.25us bit time, 800Kbps)
  • T0H: 0.4us <-- 0 bit
  • T0L: 0.85us
  • T1H: 0.8us <-- 1 bit
  • T1L: 0.45us
  • RES: 50us
    */

Invalid conversion from 'int' to 'gpio_num_t'

Hello there,
Just downloaded the code, and I'm getting the above compile error on line 27 of ws2812_control.c ("config.gpio_num = LED_RMT_TX_GPIO;"). Arduino IDE v1.8.9. Just thought I'd mention it here.

[Feature] Predefined LED's in ESP-IDF configuration tool?

Predefined LED's?

Got this idea when I was messing about with LED timings in Issue #13 and found it somewhat useful to have predefined LED timings instead of having to write them down somewhere else. This is a small detail since most WS28xx LEDs have similar timing specs but it might still be useful to easily ensure that all LEDs operate within the proper specifications.

I forked your repo and made the necessary changes to implement such a thing.
Also added a range limitation on the RMT channel configuration, the help text states "Defines that RMT Channel that will be used to modulate the signal. Valid values are defined by enum rmt_channel_t (0-7)" but the input data field is not sanity checked. Limited the input to channel 0-7.

Tested the code on an ESP32 and WS2812B and it works fine.
Below is a demo video of the esp-idf configuration tool with the predefined LEDs.

The README.md is also adjusted, it was never updated when migrating the code to the esp-idf configurator.

NOTE: The timings should be double checked, I don't own all of the LEDs so I'm unable to test them.

IDF Config Demo

Clock Speed Setting for IN-PI554FCH

Good day,

I am attempting to make this work with another digital LED (Specifically, the IN-PI554FCH).
This LED has the following timing specifications T0H = 0.3uS, T1H = 0.6uS, T0L = 0.9uS, T1L = 0.6uS.
I would just like to know what the clock speed should be set to. I do now have a very good scope so it is difficult for me to get the timing of the signals.

Thank you in advance.

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.