DaAwesomeP/dmxusb

Inverted values with Teensy 4.0 and OP-Z

nickbec10 opened this issue · 12 comments

I am working with the Teensy 4.0 and getting some weird results with an OP-Z driving the DMX. The output seems to be opposite of the control being sent. If the sent color is purple then it comes out green, if the sent color is blue then it comes out orange and the whole strip is on and white when it should be off or black. I can only imaging that it has something different the way the Teensy is interpreting it because if I put a Arduino Nano on it will work fine. I moved to the Teensy because it can handle a lot more interrupts.

Would you mind dropping your code into a Gist (if you are able/permitted to)? The only parts of the library that are device-specific shouldn't cause the issue you are having at first glance.

Additionally, are you seeing any errors during compilation? Also, what are your compilation settings (clock speed, optimization, etc.)?

Wow, I really didn't think you would get back to me so quick. Thanks for that. I am somewhat of a noob here but I created a gist. https://gist.github.com/nickbec10/38ad44ffd29ed492da6b1de6a1b24e46
I do get this error: In file included from /Users/nbecker/Documents/dev/Arduino/DMXUSB_FastLED_Teensy/DMXUSB_FastLED_Teensy.ino:27:0:
/Users/nbecker/Documents/dev/Arduino/libraries/FastLED/FastLED.h:14:21: note: #pragma message: FastLED version 3.003.003

pragma message "FastLED version 3.003.003"

                 ^

BuT I was getting that with the Arduino Nano and it worked fine. I also would not think that this error would be device specific but I am trying to narrow down the troubleshooting.

BuT I was getting that with the Arduino Nano and it worked fine. I also would not think that this error would be device specific but I am trying to narrow down the troubleshooting.

Yeah that pragma for FastLED just shows the version number—nothing to worry about. I just wanted to make sure there was nothing else.

I can only imaging that it has something different the way the Teensy is interpreting it because if I put a Arduino Nano on it will work fine.

So I do not own nor have ever used an OP-Z, but if I remember correctly from reading a forum somewhere, people seemed to prefer the Nano over the Teensy 3 because the OP-Z required an FTDI-based device to output DMX properly or at all (I don't remember which). This is most likely because the Enttec devices most likely use FTDI chips for serial, so the OP-Z only bothers to look for or support FTDI-based devices. The Teensy is more complex under the hood than the Arduino Nano in that it has 100% control of what kind of device it appears to be to the USB host—Teensies can act as serial devices (as being use here) or you can emulate MIDI devices, gamepads, keyboards, etc.

However this is really strange because it is working, just not properly. It is interesting that it is inverting and not shifting. This sounds like some compilation error still. Do the other FastLED demos work as expected or do they have the same issue? Can you test this with another piece of software other than the OP-Z to see if only the OP-Z causes the issue?

Please screenshot and send your Arduino IDE tools menu as I have done here. I suspect it may be related to the optimization setting:
arduino_tools

I moved to the Teensy because it can handle a lot more interrupts.

I assume by interrupts you mean hardware interrupts for user input like buttons, etc. I am not really familiar with how the OP-Z works, but if it is able to send the DMX data and receive input at the same time on the same USB/serial port, then I guess that will work. It is possible that you could also use the "Dual Serial" USB mode in the "USB Type" menu for the Teensy, but I am unsure how the OP-Z handles multiple serial devices (there are also modes like Serial + MIDI which may be of interest to you).

However I am not sure that you want interrupts and LED driving on the same board, as the interrupts will most likely stop/interrupt FastLED from finishing writing to all of the LEDs every time an interrupt fires, when the interrupt resumes and FastLED continues I am unsure if it will write to the LEDs properly. You possibly will see a bit of lag or jitter when interrupts fire. This could be mitigated by a library that uses DMA (FastLED does not), but I am honestly not sure how the Teensy handles that and I have never tried it. I am interested to know what you find!

I am somewhat of a noob here but I created a gist.

I'm happy to help as best I can!

This stuck out to me in the code:

if (colorChannel == 1) leds[ledIDUse].r = value; // If the channel is red, write the red value of the LED
if (colorChannel == 0) leds[ledIDUse].g = value; // If the channel is green, write the green value of the LED
if (colorChannel == 2) leds[ledIDUse].b = value; // If the channel is blue, write the blue value of the LED

This is probably a specific feature of the OP-Z, but this means that it outputs its DMX channels in the order (G, R, B) instead of (R, G, B). This doesn't explain why black/white are flipped but could explain the issues with other colors. Again, not sure why this would affect one board and not the other.

Also this:

for (int count=1; count < NUM_LEDS; count++){
  int ledMulti = count * NUM_BLOCKS - NUM_BLOCKS+1;
  int ledToCopy = count * NUM_BLOCKS;
  for (int i=0; i<NUM_BLOCKS-1; i++){
    leds[ledMulti] =  leds[ledToCopy];
    ledMulti++;
  }
}

With how few LEDs you have this is probably fine, but if you scale up to many more LEDs then this will become pretty inefficient—you should try to merge this with the first for loop. You are also running this 511 times more than necessary, as it runs for every single channel in the DMX universe. You only need to run this once for every DMX packet.

Though your code is also really confusing to me. Let's say you have NUM_LEDS = 4 and NUM_BLOCKS = 3 and the following DMX comes in (I have it formatted nicely to make it easier to read):

001 002 003
101 102 103
201 202 203
301 302 303

After all of the DMX values are assigned in the first half of the function, you have this:

leds[000] = 002 001 003
leds[001] = 000 000 000
leds[002] = 000 000 000
leds[003] = 102 101 103
leds[004] = 000 000 000
leds[005] = 000 000 000
leds[006] = 202 201 203
leds[007] = 000 000 000
leds[008] = 000 000 000
leds[009] = 302 301 303
leds[010] = 000 000 000
leds[011] = 000 000 000

And after the second half they look like this:

leds[000] = 002 001 003
leds[001] = 102 101 103
leds[002] = 102 101 103
leds[003] = 102 101 103
leds[004] = 202 201 203
leds[005] = 202 201 203
leds[006] = 202 201 203
leds[007] = 302 301 303
leds[008] = 302 301 303
leds[009] = 302 301 303
leds[010] = 000 000 000
leds[011] = 000 000 000

The issues are that you start counting from 1 instead of 0, and your copying has an off-by-one error. You can simplify this by doing it all in the first part (more efficient and I think this is what you are trying to do):

for (int index=0; index < 512; index++) { // for each channel, universe starts at 0
  int value = buffer[index]; // DMX value 0 to 255
  int LEDchannel = (universe*510) + index; // Find the LED number; can't fit a 3-channel fixture on the remaining two channels
  if (LEDchannel <= (NUM_LEDS*3)-1) { // If DMX channel (LEDchannel starts at 0) is in range of LEDs (3 channels per LED for RGB)
    int colorChannel = LEDchannel % 3; // Find the color channel of the LED addressed
    int ledID = (LEDchannel - colorChannel) / 3; // Find the FastLED index of the LED addressed
    int ledIDBase = NUM_BLOCKS*ledID;
    int ledIDUse = ledIDBase - 0;
    for (int block=0; block < NUM_BLOCKS; block++) { // ***ADDED THIS
      if (colorChannel == 1) leds[ledIDUse + block].r = value; // ***NOTE THAT WE ADD THE BLOCK // If the channel is red, write the red value of the LED
      if (colorChannel == 0) leds[ledIDUse + block].g = value; // If the channel is green, write the green value of the LED
      if (colorChannel == 2) leds[ledIDUse + block].b = value; // If the channel is blue, write the blue value of the LED
    }
  }
}

This is much simpler and your runtime complexity drops a ton. The LED output would be:

leds[000] = 002 001 003
leds[001] = 002 001 003
leds[002] = 002 001 003
leds[003] = 102 101 103
leds[004] = 102 101 103
leds[005] = 102 101 103
leds[006] = 202 201 203
leds[007] = 202 201 203
leds[008] = 202 201 203
leds[009] = 302 301 303
leds[010] = 302 301 303
leds[011] = 302 301 303

Note this code is untested, but I think this is what you are trying to do!

I am working with the Teensy 4.0 and getting some weird results with an OP-Z driving the DMX. The output seems to be opposite of the control being sent. If the sent color is purple then it comes out green, if the sent color is blue then it comes out orange and the whole strip is on and white when it should be off or black. I can only imaging that it has something different the way the Teensy is interpreting it because if I put a Arduino Nano on it will work fine. I moved to the Teensy because it can handle a lot more interrupts.

Could it be the setup in dmx.json on the op-z that is giving you trouble? In what order are the color channels defined there?

I plan to attempt something similar, but primarily with a Teensy 3.2, sometime in the next few days. I have an OP-Z and I am experimenting a bit with the DMX output over USB.

Making a cheap and simple USB to DMX adapter was easy, though I have yet to test it with an actual DMX device. I made one like this.

Thanks for the feed back DaAwesomeP and johanadler. I think I need to clarify, the main issue is the inverted nature of black(off) and white(all on), and all other colors are also reversed as well. I can tell it is overdriving the strip because the LEDs at the end have a yellow tint which I believe means the data channel through the strip is loosing current. This shouldn't be happening anyway because the LEDs should actually be off unless being told to be a specific color. (A video would probably help to explain so I will try to make one if I can)

I should also explain my hardware a little more. I am using a Sparkfun FTDI chip for true FTDI interface to the OP-Z, you are right that I think the OP-Z only recognizes a real FTDI chip. I also have seen people post that they were using a off brand FTDI and it does not work. The LED strip is WS2812b 5m 60leds/Pixels/m so 300 LEDs total and I am powering it with a DC5V 20A 100W power supply.
Screen Shot 2020-05-19 at 6 25 59 PM

OP-Z dmx.json - I have tried several variations on the colorChannel part of the code with no luck, it seems just to shift the colors around and not to revert/invert off and on.
color channels - "name": "rgb", "channels": ["red", "green", "blue"]

If I run Adafruit_NeoPixel.ino through the Teensy 4.0 I get no problem, all colors are the same as if I run it through the Arduino Nano. I will try some of the code you suggested tomorrow to see if I get some different results.
IMG_2870

I plan to attempt something similar, but primarily with a Teensy 3.2, sometime in the next few days. I have an OP-Z and I am experimenting a bit with the DMX output over USB.

@johanadler This is the device that I primarily use to test and in the field, so I am quite sure that it will work fine so long as you have the correct hardware.

I think I need to clarify, the main issue is the inverted nature of black(off) and white(all on), and all other colors are also reversed as well.

I think the color reversal may be an issue with either data coming in from the OP-Z—I know that you disagree but it is hard to rule out this issue. First see if you can correct the issue in code (this is not necessarily the correct solution, but it will help debug what is happening). Try value = 255 - value; and also switching around which channels are red, green, and blue. Please give this a try so I can know what data might be incoming. Another idea would be to send your OP-Z config to @johanadler since he could test on a completely different piece of hardware which may also help me figure out what is happening.

I am using a Sparkfun FTDI chip for true FTDI interface to the OP-Z

You should stick to a baud rate of 250000 since you are using an FTDI. I do not know the FTDI data loss specs, but you can find the Teensy specs and lots of other useful info here: https://www.pjrc.com/teensy/td_uart.html

Since you have a separate FTDI device for the OP-Z, you can use the Teensy's built-in USB serial to debug what is going on. Move the FTDI to the second set of serial pins and use the built-in USB to debug by sending values to your computer. Be sure to see the paragraph below about being careful with what is powering what.

In general, you should actually not have the Teensy USB serial and FTDI on the same serial line. Use a separate one anway. Also, I am unsure if the OP-Z or your breakout make use of Transmit Enable, RTS, or CTS, but you should connected them so that those interrupts are being used properly. The pins are in the link above. You will also need to enable them in code.

Also try setting the Optimize setting to "Fast" or "Fastest." I have occasionally had issues with this.

I can tell it is overdriving the strip because the LEDs at the end have a yellow tint which I believe means the data channel through the strip is loosing current. This shouldn't be happening anyway because the LEDs should actually be off unless being told to be a specific color.

The yellow tint could be a myriad of things without knowing your setup entirely. I don't know what you mean by overdriving. The LEDs hold their last known value until they receive a value again. If there is data loss on the line, then they will hold the last value or flicker or make strange colors. If they are lighting up at all immediately on power-up with no data, then you have an electrical/wiring problem—I have seen this many times. This could definitely be why you are seeing white instead of black if that doesn't happen to the whole strip.

First, the Teensy operates at 3.3V and will output a 3.3V GPIO signal. You need to use a logic level convertor like a 74AHCT125 to step it up to 5V using your power supply as a reference voltage on the output side. If you absolutely must use 3.3V, then your power line for the LEDs should also be 3.3V, as the LEDs use the power line (roughly) as a reference for the high/low values of the data line. But the Neopixels are really designed for 5V, so you should do that. I suppose the tint may be caused by the voltage drop on the data line, but it is more likely that voltage is dropping on both the power and data lines and so the LEDs are not operating properly.

If you fix the above issue and you still have the problem, then it is most common for the tint to be caused by the wayyy too small traces on the strips. This is often an issue after as little as 3 feet. For large installs I have almost always have power leads going to both ends of the strip and often at points in the middle too. This issue is from voltage drop. Calculate the correct wire gauge to use (this is also for your safety), and use proper copper wire (avoid some cheaper wires i.e. cheap speaker wire that are not pure copper).

You should power the LEDs directly from your power supply (a.k.a. PSU) and NOT through the Teensy. You should connect the ground between your PSU, Teensy, and LED strips. You should be careful that everything only receives power from one place. If you have USB plugged into the Teensy, do not power it from the FTDI or PSU. If you are powering the Teensy from the FTDI, then do not plug in the power for the PSU to the Teensy. Everything must share a ground, but that is the only requirement.

I strongly recommend reading through this entire guide: https://learn.adafruit.com/adafruit-neopixel-uberguide/the-magic-of-neopixels (yes, the whole guide). It covers what I said above and many other things.

Be sure to test only changing one thing at a time so that you can figure out exactly where the issue is!

I apologize for the long replies or if you are already doing all of these things—I am just doing my best to help and debug! 😄

Quick update: I made the change regarding the for "block" loop and on the Teensy there was no difference to the LED output but it does work and is more efficient. I went back to the Arduino Nano and tested the code and everything worked as expected (no inverted colors) with limiting to 16 LEDs.

// Number of LEDs on the strip
#define NUM_LEDS 16
#define NUM_BLOCKS 1
#define NUM_LEDSSTRING 16

Previously I was only able to get about 48 LEDs on the nano to work stable which is why I went to the Teensy. Now I can get 128 of the 300 LEDs working which is a great improvement.

// Number of LEDs on the strip
#define NUM_LEDS 16
#define NUM_BLOCKS 8
#define NUM_LEDSSTRING 128

If I bump it up to 9 blocks I can't compile and get an error: Sketch uses 6344 bytes (20%) of program storage space. Maximum is 30720 bytes.data section exceeds available space in board
Global variables use 2180 bytes (106%) of dynamic memory, leaving -132 bytes for local variables. Maximum is 2048 bytes.

To be honest, it doesn't matter to me if I use the Teensy or Arduino, I just would like to get all 300 (or more) LEDs to work.

I am actually using the 5V FTDI chip so I am running the Teensy at 5V also and made sure I am only running power from one source(through the FTDI) to the Teensy. The LED strip is powered only from the PSU. Looking at the Hardware Serial Ports it seems I cannot connect the CTS (there is no CTS on Teensy 4.0, RTS (there is no RTS on the FTDI chip, they swapped it for DTR) and I am not sure about how to cable Transmit Enable. I did add the TX back to the FTDI RX.

Some other things I tried: It seems that I cannot use DMX baud rate of 250000, I don't think the FTDI can handle that so I went back to 115200. Finally, I played around with and verified the color settings on the nano for RGB as

if (colorChannel == 1) leds[ledIDUse + block].r = value; 
if (colorChannel == 0) leds[ledIDUse + block].g = value; 
if (colorChannel == 2) leds[ledIDUse + block].b = value; 

I actually have time today to set up debugging and continue playing around to see if I can get any further. Thanks, all long replies appreciated. 😀

I went back to the Teensy and tried value = 255 - value; and that seems to get me 99% to where I need to be. The colors are correct, the only thing is that where the LEDs are supposed to be off they are on but appear to be at the very dimmest setting.

If I bump it up to 9 blocks I can't compile and get an error: Sketch uses 6344 bytes (20%) of program storage space. Maximum is 30720 bytes.data section exceeds available space in board
Global variables use 2180 bytes (106%) of dynamic memory, leaving -132 bytes for local variables. Maximum is 2048 bytes.

I believe your CRGB array is three times as large as it should be: CRGB leds[NUM_LEDSSTRING*3]; Try CRGB leds[NUM_LEDSSTRING]; If I remember the FastLED semantics correctly, you need one CRGB struct per LED. This will cut down on required memory.

I am actually using the 5V FTDI chip so I am running the Teensy at 5V also and made sure I am only running power from one source(through the FTDI) to the Teensy.

Uh, no, sorry that's not correct. The Teensy does not have 3.3V and 5V modes. In fact, the Teensy 4x is different from the 3x in that its pins are NOT 3.3V tolerant. You are probably damaging your Teensy by feeding it 5V on anything other than the VIN pin, and again I can't say its not malfunctioning if you are using it incorrectly. You should either use a 3.3V FTDI or add in a logic level convertor between the FTDI and Teensy.

Please also read through the Adafruit guide I sent before and fix the similar 3.3/5 issue with the LED strip and Teensy. You need to power the strip from both ends using the correct thickness wire and add in a logic level convertor. The Teensy will always output 3.3V logic on its I/O pins. The LEDs are definitely sensitive to incorrect voltages and even more so with voltage drop. I know it is unfortunate that you need more pieces of hardware, but I am quite sure the issues and setup you are describing are directly correlated.

Looking at the Hardware Serial Ports it seems I cannot connect the CTS (there is no CTS on Teensy 4.0, RTS (there is no RTS on the FTDI chip, they swapped it for DTR) and I am not sure about how to cable Transmit Enable. I did add the TX back to the FTDI RX.

If you look at the Teensy UART link I sent before, you can see that Serial3 supports CTS. If you scroll down you will see the functions Serial3.transmitterEnable(pin), Serial3.attachRts(pin), and Serial3.attachCts(pin), and it says where to run them. Also note that you would connect RTS to CTS—Google how these signals work and what they do. Though honestly I would try this last, as the FTDI probably ignores it if they aren't plugged in. It is way much more likely to be the voltage issue.

I went back to the Teensy and tried value = 255 - value; and that seems to get me 99% to where I need to be. The colors are correct, the only thing is that where the LEDs are supposed to be off they are on but appear to be at the very dimmest setting.

So this is either a wiring problem or a data input problem. Please fix the LED and FTDI wiring/voltage issues and also possibly try using the Teensy built-in USB serial to debug the data input from the FTDI.

Closing for now, though please continue the discussion and I will reopen if a direct issue with DMXUSB is found. It is not possible to verify that this is not a hardware setup issue so far.