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

Request for improvement - Add a switch to invert output logic #294

Closed
Ashram56 opened this issue Oct 2, 2021 · 5 comments
Closed

Request for improvement - Add a switch to invert output logic #294

Ashram56 opened this issue Oct 2, 2021 · 5 comments

Comments

@Ashram56
Copy link

Ashram56 commented Oct 2, 2021

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

@moose4lord
Copy link
Collaborator

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.

@moose4lord
Copy link
Collaborator

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

@Ashram56
Copy link
Author

Ashram56 commented Oct 5, 2021

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

@moose4lord
Copy link
Collaborator

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.

@Ashram56
Copy link
Author

Ashram56 commented Oct 5, 2021 via email

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

No branches or pull requests

2 participants