kitesurfer1404 / WS2812FX

WS2812 FX Library for Arduino and ESP8266

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Request for improvement - Add a switch to invert output logic

Ashram56 opened this issue · comments

Good morning,

I'm currently designing a board that would need to have the flexibility to either drive WS2812 ledstrip, or other type of devices (such as high power 12V RGB leds for example, motors, etc).

To that end, the output of the Arduino is connected to a transistor gate, the emitter is connected to ground, collector to a variable voltage (depending on the output device type) through a pull up, and control pin is connected to the collector.

So output logic becomes inverted in that case, which is obviously problematic for WS2812 ledstrip control

I could add DIP switches to bypass the transistor when needed, but an even simpler solution would be for WS2812FX library to have a flag to allow for inverted data control. However, given my understanding of the bus used for WS2812 I'm not sure this is possible (as I believe it's using an hardware wired SPI interface ?)

Comments welcome

Unfortunately, the output hi/low values are hardcoded in the underlaying Adafruit_Neopixel library. If you look at the Adafruit_NeoPixel::show(void) function (near line 218 in the Adafruit_Neopixel.cpp file) you'll see several lines like this (which set the hi and low values for the WS2812 pulse train):

      hi = PORTD |  pinMask;
      lo = PORTD & ~pinMask;

If you wanted to hack the library, you could add your own patch to reverse the hi/lo values:

#if defined(INVERT_OUTPUT)
      lo = PORTD |  pinMask;
      hi = PORTD & ~pinMask;
#else
      hi = PORTD |  pinMask;
      lo = PORTD & ~pinMask;
#endif

But there are a lot of lines to patch for different CPUs and clock speeds. Probably not something worthwhile except for a proof-of-concept exercise.

I gave this a little more thought and did some experimenting to see if I could get this inversion scheme working without hacking the Adafruit_NeoPixel library. I came up with a partial solution, that's good for ESP8266 /ESP32 processors, by using a custom show() function.

The Adafruit_NeoPixel driver for ESP devices is a standalone file (esp8266.c), and only requires changing two lines of code to invert the GPIO output, so it was a good candidate to copy and tweak. I found an old, dusty 2N2222 NPN transistor at the bottom of my parts drawer and wired it to the 3.3V output of an ESP8266 to drive the 5V input of my WS2812 strip. It took a while to get the right bias resistors for the transistor, but it works!

Something like this could probably be used to drive 12V loads if you're using an ESP microprocessor. I've attached the sketch if you want to give it a look.

ws2812fx_segments_inverted.zip

Many thanks for digging into this, this is a great feedback, I'll definitely take a look at it.

And conveniently, we were looking at using an ESP8266 derivative, so that will be a perfect fit, thanks

I'm not sure I understood however the comment on the bias resistor, I would have thought the value would not have much of an impact, what did you use in the end ?

Regards

I used a 100 ohm pull-up resistor on the collector and a 4.7k ohm resistor on the base. The collector resistor is very important since it determines the rise time of the pulse, and a poor quality pulse can lead to flakey behavior. 100 ohms sounds low to me. It certainly draws a fair amount of current, but I don't have an oscilloscope to actually view the waveform, so I was just using trial and error to pick the resistor values. You can probably do better if you have the test equipment to ensure you get a nice square wave on the output for the loads you're driving.