TeensyDMX icon indicating copy to clipboard operation
TeensyDMX copied to clipboard

USBWidgetPro Example Correction

Open welshcoder opened this issue 2 years ago • 28 comments

Hi,

First of all, thank you for this great library!

I've been using this for a couple of projects of mine, and it works very well. One of the projects is to upgrade the Velleman VM116/K8062 USB Controller DMX Interface by removing the original PIC and replacing it with a TeensyLC running TeensyDMX in send mode. I essentially used the USBWidgetPro example pretty much as is, and it works well with FreeStyler and the fixtures I tested it on.

However, when I tried to use it controlling another one of my projects, I was getting quite a lot of glitches coming through. To cut a long story short, it turned out that the problem was that the TeensyLC was pausing briefly to process data received from the USB port.

The issue is this block of code in handleMessage (line 508):

if (len != dmxTx.packetSize()) {
   __disable_irq();
   dmxTx.setPacketSize(len);
   dmxTx.set(0, msg.data, len);
   __enable_irq();
   } else {
     dmxTx.set(0, msg.data, len);
}

The data can be set whilst a transmission is taking place, causing a brief delay in the DMX data stream and glitching the receiver. I propose changing this block to:

if (len != dmxTx.packetSize()) {
  dmxTx.pause();
  while(dmxTx.isTransmitting()) { yield(); }
  dmxTx.setPacketSize(len);
  dmxTx.set(0, msg.data, len);
  dmxTx.resume();
} else {
  dmxTx.pause();
  while(dmxTx.isTransmitting()) { yield(); }
  dmxTx.set(0, msg.data, len);
  dmxTx.resume();
}

After this change, the glitches disappeared and it all works perfectly!

I hope it helps!

welshcoder avatar Jun 20 '22 20:06 welshcoder

Thanks for this report and I’m really happy you’re using this successfully in your projects. :)

Question: why would slightly longer delays (due to the stopped interrupts?) in the DMX data stream affect the receiver? To me, that would mean the receiver doesn’t conform to the DMX spec. DMX data doesn’t have to be regular.

Do you happen to have oscilloscope or logic analyzer captures of the DMX output that causes a receiver glitch? Do you know how long the pauses are? Are the pauses, in fact, outside the maximum allowed by the DMX spec? (Which would mean, of course, that the receiver is in spec.)

ssilverman avatar Jun 20 '22 23:06 ssilverman

Thanks for getting back to me.

The receiver in this case is a Teensy 4.1 with an isolated RS485 interface to the DMX connector. I'm using the TeensyDMX library to process the incoming DMX data on the 4.1. I tried using the Rx monitor option for the timing, but it didn't seem to make much difference. What I was seeing on the receiver using the readPacket function was a series of zeros when it was glitching, followed by the correct (non-zero) data. When I connected a commercial stand-alone DMX controller to the receiver, it worked perfectly - no glitching whatsoever.

I do have an oscilloscope, and I was using it to monitor the USB data lines and the DMX output. Unfortunately, I didn't take screen captures! If I have time later on, I'll hook it up again and capture the issue using the original code. In a nutshell, what I was seeing is shortly after the burst of USB data, the output of the DMX would freeze mid-frame for a period of about 50-100 us (from memory - need to confirm) before continuing. With the revised code, that delay is added to the end of the frame and does not affect the frame timing.

Does that help?

welshcoder avatar Jun 21 '22 09:06 welshcoder

Some questions:

  1. Which version of Teensyduino?
  2. Which version of TeensyDMX?
  3. Can you show me what your receiver code looks like?
  4. Where exactly is that extra 50-100us located in the transmitted frame? For example, is it between bits? Is it between bytes? Is it between frames? Etc.

ssilverman avatar Jun 21 '22 10:06 ssilverman

Sure, no problem.

  1. Version 1.156
  2. Both are using the version available through PlatformIO library manager: version 4.3.0-snapshot?
  3. Here is the complete DMX setup and loop sections in my code. It should be fairly straightforward: setupDMXSubSystem is run during the setup() process, and loopDMXSubSystem runs during the loop() process. DMXValues is the array containing the relevant DMX values to the receiver starting from mSettings.DMXStartAddress.
#ifndef _DMX_SUB_SYSTEM_H_
#define _DMX_SUB_SYSTEM_H_

#include <TeensyDMX.h>

using namespace ::qindesign::teensydmx;

Receiver DMXRx{Serial8};

enum DMXChannelDef : uint8_t {
    DMX_CH_MODE = 0,
    DMX_CH_RED1,
    DMX_CH_GREEN1,
    DMX_CH_BLUE1,
    DMX_CH_STROBE,
    DMX_CH_RED2,
    DMX_CH_GREEN2,
    DMX_CH_BLUE2,
    DMX_CH_DIMMER,
    DMX_CH_LENGTH
};

enum DMXModeDef : uint8_t {
    DMX_MODE_FULL_SCREEN = 0x00,
    DMX_MODE_HALF_SCREEN = 0x10,
    DMX_MODE_QURT_SCREEN = 0x20,
    DMX_MODE_ANIM_MODULE = 0x30,
    DMX_MODE_FRCT_MODULE = 0x40,
    DMX_MODE_VIDO_MODULE = 0x50,
};

array<uint8_t,DMX_CH_LENGTH> DMXValues;


void enableDMXTx(bool en=true)
{
    DMXRx.setTXEnabled(en);
    digitalWriteFast(DMX_TX_EN_PIN,en?HIGH:LOW);
}


void setupDMXSubSystem()
{
    pinMode(DMX_TX_EN_PIN,OUTPUT);
    enableDMXTx(false);

    DMXRx.begin();
}

bool loopDMXSubSystem()
{
    uint8_t packetBuf[DMX_CH_LENGTH];
    int read=DMXRx.readPacket(packetBuf,mSettings.DMXStartAddress,DMX_CH_LENGTH);

    if(read==DMX_CH_LENGTH)
    {
        if(memcmp(packetBuf,DMXValues.data(),DMX_CH_LENGTH)!=0)
        {
            memcpy(DMXValues.begin(),packetBuf,DMX_CH_LENGTH);

            return true;
        }
    }

    return false;
}


#endif
  1. I don't think it was anywhere in particular in the frame. If I remember correctly, it was pretty consistent from the timing of the USB data burst, regardless of what the transmitted DMX data stream was doing at the time. I would need to confirm that though. It was definitely occurring at seemingly random times in the frame, as I could see the glitch jumping around when I zoomed out to see the whole frame on the scope.

I believe the "else" block of the original code that doesn't have the interrupt control was being executed, so I can see how this may come about.

welshcoder avatar Jun 21 '22 11:06 welshcoder

Do either of the following changes still cause a glitch (I want to see which of the cases gets executed --- it's the change-one-thing-at-a-time approach):

First:

if (len != dmxTx.packetSize()) {
  __disable_irq();
   dmxTx.setPacketSize(len);
   dmxTx.set(0, msg.data, len);
   __enable_irq();
} else {
  dmxTx.pause();
  while(dmxTx.isTransmitting()) { yield(); }
  dmxTx.set(0, msg.data, len);
  dmxTx.resume();
}

Second:

if (len != dmxTx.packetSize()) {
  dmxTx.pause();
  while(dmxTx.isTransmitting()) { yield(); }
  dmxTx.setPacketSize(len);
  dmxTx.set(0, msg.data, len);
  dmxTx.resume();
} else {
  dmxTx.set(0, msg.data, len);
}

More questions:

  1. Why are you enabling TX on the receiver? Are you trying to do RDM or something? (DMXRx.setTXEnabled(en))
  2. Can you describe what you mean by “glitch”? Are you seeing unexpected data?

ssilverman avatar Jun 21 '22 11:06 ssilverman

Hopefully, I'll get a chance to try out the code tonight and let you know how it goes.

In the meantime, the answer to your questions are:

  1. I wrote the function with the intention of implementing RDM in the future, but I set it to false in setupDMXSubSystem, and doesn't change from there. Therefore, the receiver is always in receive-only mode.
  2. It manifests itself by the block of data I obtain from readPacket being all zeros on the receiver, and then the receiver is acting on that data as if it's valid. Since the TeensyLC is constantly writing DMX data, the receiver then obtains the correct data in the next frame for the channels I need (i.e. the DMX stream to that point has no glitches). I've confirmed that the mSettings.DMXStartAddress is unchanged for all the calls made to that function. This behaviour appeared to be random too. When I implement my proposed code changes, this behaviour disappeared completely and no glitching occurs.

Edit: I've checked the two code blocks, and the first one does not glitch, but the second one does.

welshcoder avatar Jun 21 '22 13:06 welshcoder

Ok, got some captures from the scope with and without the glitching. In all the captures, the yellow trace is the DMX stream, and the blue(ish) trace is the USB data line. I used the second code you asked me to try above for the glitching version, and my proposed code changes for the no-glitch version.

Glitching 1 NewFile1 In this image, you can see the data burst on the USB line, followed about 1.5 ms later by the DMX stream freezing slightly (stays high). All the DMX values in that section are meant to be 0, hence should be a regular pattern.

Glitching 2 NewFile1a Here's another example showing the same thing but at a different time. The first few channels have non-zero values in them, hence you see some data near the beginning of the frame.

Glitching 3 NewFile1b This is showing the same as above. However, note that the USB burst is at a different position relative to the DMX frame start, but the glitch in the DMX stream occurs more-or-less at the same interval after the USB data burst has ended.

No glitch 1 NewFile1d This is the situation after I've implemented my changes. You'll notice there is no glitching after the USB data bursts. The frame start after the first USB data burst is slightly longer than the next one, as the processing of the incoming data has been delayed until the end of the frame.

No glitch 2 NewFile1e Same as the previous one, but zoomed in to show that the glitch doesn't appear in the DMX stream after the code change.

welshcoder avatar Jun 21 '22 21:06 welshcoder

I’m hearing some contradictory things. On one hand you’re saying that the glitch on the receiver side happens when it sees all zeros. On the other hand you’re saying that there’s a glitch when the transmitter leaves the line high. The line staying high between bits or bytes or frames in the DMX packet is allowed and won’t show up as zeros in the receiver.

Do you have a close-up of what a glitching frame looks like?

More comments and questions:

  1. Did you know that when you read a packet, you’re also reading the start code? Is DMX_CH_MODE considered the start code or the first channel?
  2. How big are the glitchy frames? You can find this out by using a 513-byte buffer and looking at the return value for the actual number of bytes received (including the start code). 513 bytes allows for reading up to a full packet. I’m curious just how big the system sees the size of those glitching packets.
  3. What happens if, in the check for valid received data, you exclude a start code of non-zero? Would they solve the problem maybe?
  4. I still don’t see how the receiver is receiving all zero bytes when (and it’s hard to tell from those captures) none of those bytes are zero.
  5. I’m still wondering which of the two sides of the if/else causes the issue. Before your change, the “if” part disables all interrupts while the “else” part only disables the UART interrupts. That’s why I need this data point, to understand which one is happening.

My understanding of disabling interrupts here is that the UART still finishes the bytes it’s currently sending. That’s why I’m skeptical that this is creating invalid DMX packets. Unless it has something to do with the BREAK, Mark After Break, or Mark Before Break being too long… I doubt this, however, because these are allowed to be “really long”.

I have two more code changes for you to try when I get a chance:

  1. Using the “Atomic” macro to disable the interrupts instead of the __enable/__disable_irq() functions.
  2. I’ll try making an atomic “set packet size and packet data at the same time” function. But only if the cause is the “if” side of your original code change suggestion. (Point 5 above.)

I do believe that your changes do fix the problem, I’m just trying to understand why there’s a problem in the first place. Something’s not adding up for me. Maybe my code still needs work on the Teensy LC. Or maybe something’s wrong with the application code.

ssilverman avatar Jun 22 '22 01:06 ssilverman

I just noticed your edit on one of your comments saying the glitch happens in my second test code block (i.e. the “else” block). Can you try this block of code:

if (len != dmxTx.packetSize()) {
  __disable_irq();
  dmxTx.setPacketSize(len);
  dmxTx.set(0, msg.data, len);
  __enable_irq();
} else {
  __disable_irq();
  dmxTx.set(0, msg.data, len);
  __enable_irq();
}

ssilverman avatar Jun 23 '22 06:06 ssilverman

Sorry for the delay in getting back to you, it's been a rather busy couple of days for me.

There are a few things to cover here, so I'll try to do this as methodically as possible!

Regarding the atomic interrupt blocks, I used this code to try it out:

      if (len != dmxTx.packetSize()) {
        ATOMIC_BLOCK(ATOMIC_FORCEON)
        {
            dmxTx.setPacketSize(len);
            dmxTx.set(0, msg.data, len);
        }
      } else {
        ATOMIC_BLOCK(ATOMIC_FORCEON)
        {
            dmxTx.set(0, msg.data, len);
        }
      }

This code causes the glitching too.

In reference to https://github.com/ssilverman/TeensyDMX/issues/15#issuecomment-1163988662, this code causes the glitching as before.

One thing I did notice, which I don't think I noticed before, is that the Teensy 4.1 in the receiver crashed after a short period of time. Now, that could be entirely due to an unrelated problem, but reverting to my version of the TeensyLC code that stops the glitching doesn't cause this and the T4.1 is pretty stable. The T4.1 is doing a lot of work in the background (it's running SmartMatrix library and driving a 128 x 128 RGB matrix), so it could have something to do with that. Although I have already spent quite a lot of time on the receiver code before raising this issue on here, I've had a closer look on what's going on.

I did the test of using readPacket to gather all the data from the frame, and the value was not consistent on each frame with both the glitching and non-glitching code, see below (ignore the '0:' - that's just the start address I was using). Glitching code

0: 513
0: 325
0: 361
0: 172
0: 19
0: 451
0: 451
0: 513
0: 513
0: 513
0: 513
0: 193
0: 513
0: 513
0: 513
0: 513
0: 513
0: 355
0: 513
0: 397
0: 184
0: 513
0: 513
0: 513
0: 513
0: 513
0: 199
0: 513
0: 513

Non-glitching code

0: 513
0: 235
0: 250
0: 513
0: 513
0: 410
0: 55
0: 513
0: 513
0: 438
0: 508
0: 513
0: 241
0: 76
0: 513
0: 513
0: 513
0: 358
0: 260
0: 250
0: 513
0: 513
0: 315
0: 513
0: 46
0: 513
0: 513
0: 446
0: 275
0: 287
0: 268
0: 116
0: 361
0: 296
0: 513
0: 513
0: 513
0: 513
0: 513
0: 513
0: 258
0: 513
0: 513
0: 513
0: 513
0: 486
0: 259
0: 513
0: 382
0: 513
0: 513
0: 513
0: 268
0: 513
0: 513
0: 101
0: 307
0: 513
0: 371
0: 229
0: 513
0: 513
0: 513
0: 79
0: 304
0: 232
0: 161
0: 234
0: 449
0: 513
0: 247
0: 513
0: 513
0: 513
0: 513
0: 292
0: 513
0: 7
0: 513
0: 513
0: 513
0: 301
0: 76
0: 370
0: 151
0: 327

After that test, I went back to a bare-bones code for the T4.1 - a cut-down version of the BasicReceive example - and nothing else. Guess what? All glitching in the receiver disappeared! The original code as written in the USBWidgetPro example works without glitching too.

So, the issue is in the receiver, not the TeensyLC. I'm now suspecting that there is an interrupt clash, most probably with the SmartMatrix library. I'll need more time to investigate this further. The T4.1 crashes I mentioned above might provide a pointer for it. I'll see if I can track this down over the next few days, and keep you posted.

welshcoder avatar Jun 23 '22 17:06 welshcoder

Just some extra info on this. I've been trying to see how the TeensyDMX library works with the SmartMatrix one, and I've captured some data here: https://gist.github.com/welshcoder/c994c9ca2ba84acc634edfa1db52fa61

This will need a bit of an explanation!! I placed a serial.print in various points in the code to see what runs and when. For TeensyDMX, I placed an "I" at the beginning of LPUARTReceiveHandler::irqHandler() routine, and "E\n" just before completePacket(RecvStates::kIdle); in Receiver::receiveByte(). The "C" and the "S" take place in two interrupts in the SmartMatrix library, and you can see they trigger with a consistent regular pattern (triggered using DMA).

In the main loop of the program, I use readPacket to capture the whole frame. If the returned value isn't 513 or -1, then it prints the value of read plus values from some channels in the form of "7: 134 000 231 230 120".

On most lines, you see an "E" on the end which indicates that the DMX frame end has been reached. Since the output of readPacket isn't printed, we assume that all is well.

If you do a search for a colon, you find the areas that have the output of readPacket was printed, indicating a problem. The consistent issue I see is that in the previous line, the "I" disappears for a period of time, indicating that the receive interrupt in TeensyDMX seems to stop. I haven't quite worked out why yet, because it seems to play nicely with the other interrupts for most of the time.

Unfortunately, I haven't got time to look further into this until the weekend, but I'm happy to investigate further if there's anything in particular you'd like me to try. Also, if you have a T4.1, I can send you the code I'm using so you can try it out.

welshcoder avatar Jun 23 '22 21:06 welshcoder

I've been looking at this issue this morning, and I've concluded the issue seems to be with the Lock process in the Receiver class.

I was trying to figure out why the receiver interrupt was having a problem, and after placing some Serial.print statements around the code, I found that for most of the time, packetRead would execute very quickly and the interrupt routine would work on a very regular pattern as expected. However, if packetRead was executing when an interrupt was expected, the Lock causes the interrupt to not trigger. There are two effects of this that I noticed. The first is that packetRead seemed to take quite a bit longer to execute (using the SmartMatrix regular interrupt as a clock). The second effect I noticed is that the value of avail in the irqHandler on line 132 of LPUARTReceiveHandler.cpp: uint8_t avail = (port_->WATER >> 24) & 0x07; // RXCOUNT ...becomes 4 instead of the usual 3. Therefore, I suspect that the LPUART buffer is overflowing perhaps?

Although the glitching occurs pretty randomly, the above behaviour is rather consistent when it does glitch. If I comment out the Lock statement in the packetRead function (line 357 of Receiver.cpp), the glitching disappears. Clearly, there is a potential for a clash in accessing the same memory location, although in my testing this morning, I haven't seen any obvious effects of that.

welshcoder avatar Jun 25 '22 10:06 welshcoder

Just to make sure I understand: even with your fix, you still sometimes see an issue on the receiver side?

The Lock class uses RAII to simply disable and then re-enable the UART interrupt so that a certain action can be done atomically. What happens if bytes come in while the UART interrupt is disabled is they will be buffered. All you're seeing is the buffer holding one more byte than usual (4 instead of 3). The system will still process it. See the code below that and notice that it loops over avail. In your case, It will loop 4 times instead of 3.

Is it possible that the SmartMatrix interrupts occur for longer than the duration necessary for buffering unprocessed bytes? I wonder what would happen if the UART interrupt priority is increased to something greater than the SmartMatrix interrupt (or the SmartMatrix priority reduced). Do you happen to know what priority the SmartMatrix interrupt has?

Side note regarding your code:

      if (len != dmxTx.packetSize()) {
        ATOMIC_BLOCK(ATOMIC_FORCEON)
        {
            dmxTx.setPacketSize(len);
            dmxTx.set(0, msg.data, len);
        }
      } else {
        ATOMIC_BLOCK(ATOMIC_FORCEON)
        {
            dmxTx.set(0, msg.data, len);
        }
      }

It appears, from your statements above, that only the "else" part causes the glitching if we disable interrupts vs. pausing. In the spirit of changing only one thing at a time, let's just focus on changes to the "else" part.

ssilverman avatar Jun 27 '22 16:06 ssilverman

Just to make sure I understand: even with your fix, you still sometimes see an issue on the receiver side?

Yes, that's right, but the difference was that I wouldn't get the DMX values briefly changing to zeros and back to the proper value. It was very odd.

The Lock class uses RAII to simply disable and then re-enable the UART interrupt so that a certain action can be done atomically. What happens if bytes come in while the UART interrupt is disabled is they will be buffered. All you're seeing is the buffer holding one more byte than usual (4 instead of 3). The system will still process it. See the code below that and notice that it loops over avail. In your case, It will loop 4 times instead of 3.

Fair enough. I think there's more going on that I can't seem to work out (see below).

Is it possible that the SmartMatrix interrupts occur for longer than the duration necessary for buffering unprocessed bytes? I wonder what would happen if the UART interrupt priority is increased to something greater than the SmartMatrix interrupt (or the SmartMatrix priority reduced). Do you happen to know what priority the SmartMatrix interrupt has?

This was my thought too, but it didn't seem to be. There would be several calls to the SM interrupt routine, during which packetRead would just sit there during the glitch. The SM interrupt is timed off DMA triggers, and it seems to be the highest interrupt priority available.

I'm chasing another, possibly entirely unrelated, glitch. I noticed that after running for about 30 mins with DMX constantly being received, the T4.1 would seemingly just freeze for about 7 - 10 seconds, and then continue as before. In fact, the glitch was consistent to virtually the same millis() value: 1889520 ms! After this time, packetCount() returns a value of 82289. This happens after I've disabled SM (i.e. it's loaded into memory, but its interrupts are not running) too. I'm slowly disabling different parts of the code to see that triggers the glitch. Again, I can't confirm if this is a problem with TeensyDMX or some other part of the code. But, getting there slowly!

welshcoder avatar Jun 28 '22 21:06 welshcoder

Thank you for diving into this with me. If it’s a problem with TeensyDMX, I’d love to fix it. It’s either that or some interaction with other libraries in certain circumstances and I’d like to identify those potential issues. Thanks for drilling down into the code to find it.

Question: with that 30-minute glitch you mention, does it still occur even without having the SmartMatrix code? For example, do you see it under the same conditions with, say, the BasicReceive example app?

ssilverman avatar Jun 29 '22 01:06 ssilverman

No problem at all! I like your library, so I'd like to contribute what I can! :-)

Question: with that 30-minute glitch you mention, does it still occur even without having the SmartMatrix code? For example, do you see it under the same conditions with, say, the BasicReceive example app?

I don't think it does, but I cannot confirm that at the moment (work gets in the way!). I have noticed that it doesn't seem to happen when I've got a cut-down version of my code with SM working. ~~I have noticed during the glitch that millis() and micros() seem to stop during that time, so it's as if the Teensy just hangs for a bit and then recovers.~~ Just before leaving for work this morning, I added 1880000000 to eventTime in line 90 of LPUARTReceiverHandler.cpp, and that triggered the glitch after a few seconds without having to wait 30 minutes every time. Out of curiosity, I commented out intervalTimer_.end(); on line 674 of Receiver.cpp, and the glitch didn't occur. Unfortunately, I ran out of time to investigate further this morning, but I'll try to carry on over then next couple of days. Btw, this is all with the Lock class doing nothing as I mentioned above.

Edit: millis() and micros() does not stop.

welshcoder avatar Jun 29 '22 09:06 welshcoder

Well, I've spent a bit of time commenting out bits of code, adding Serial.prints and looking around various bits and pieces, and I think I've managed to remove that 30 minute glitch thing.

To cut a long story short, I think the problem is in PeriodicTimer::end(), specifically around this code (lines 347 - 349 in PeriodicTimer.cpp):

    if (oldISR == unused_interrupt_vector) {
      NVIC_DISABLE_IRQ(IRQ_PIT);
    }

When I removed the if statement so that the macro always runs unconditionally, that glitch disappears. The problem is, I can't see why that is the case, nor can I see the relevance of the value of eventTime variable in LPUARTReceiveHandler::irqHandler() to this issue. Any thoughts on what it might be?

This "fix" doesn't change the issue with Lock I mentioned above. The frequent glitching still occurs if I enable the Lock once again. I've had the software with all the SM and USB host libraries, and my code, running pretty solidly when I implement these changes though.

welshcoder avatar Jun 29 '22 22:06 welshcoder

Unless you’ve defined TEENSYDMX_USE_PERIODICTIMER for your build, the PeriodicTimer class isn’t used.

ssilverman avatar Jun 30 '22 04:06 ssilverman

I can't find TEENSYDMX_USE_PERIODICTIMER anywhere in the code (I will double-check this later on). Looking through, I have to define USE_INTERVALTIMER to using the IntervalTimer class though?

welshcoder avatar Jun 30 '22 13:06 welshcoder

Try getting the latest version of the library (via git or via a download). I’m curious if the behaviour will change. (It’s possible it won’t, but I’d like to rule that out.) I’m not sure which version you’re testing with.

ssilverman avatar Jun 30 '22 13:06 ssilverman

Good news and some bad news!

First, the good news: there is quite a difference between the version I have and the current version. So, I cloned the library, pointed my software at it, and it all seems to be well on the receiver except for that Lock glitching thing still. Commenting out the r_.setIRQState(...) lines in the Lock class fixed that.

The bad news is that I then decided to update the TeensyLC (the DMX transmitter) to use the latest library version. Unfortunately, I got nothing out of the transmitter, even when using the BasicSend example. So, I whipped out the scope, and captured these DMX traces. On both cases, I set channels 50-54 to 0x7F, 0x00, 0x44, 0x88 and 0xCC respectively.

Working code

NewFile4 NewFile1

Not working Code NewFile3 NewFile2

In the working code, you can see that when I've zoomed out, you can see the individual frames, and when I zoom in on channel 50, the scope correctly decodes the values. When I do the same with the non-working code, both the overview and the zoomed in images look completely different.

The working code used the library state at commit 9bbee08. The non-working code is anything from a2ac5f0 onwards (I went through them!). Something in the code change of a2ac5f0 broke it on a TeensyLC. Unfortunately, I'm too tired tonight to investigate further. I might get a chance over the next few days to look into it further. In the meantime, any thoughts on this?

welshcoder avatar Jun 30 '22 21:06 welshcoder

Thanks for finding that. I’ll have a closer look at that commit.

ssilverman avatar Jul 01 '22 14:07 ssilverman

Hi,

I just thought I'd give you an update on this. In a nutshell, I've struggled to get the SmartMatrix and TeensyDMX behaving well together. It may be that the screen resolution of 128 x 128, and the interrupt process to service the screen, is just too much for both libraries to work together (this is on top of the image processing routines to generate an image). One thing I do note is that the receive ISR in TeensyDMX seems to be processing quite a lot (relative to other ISRs), so that might be an area that can be improved perhaps?

As an aside, I did hack together a T4.1 version of the LXTeensy4DMX library (https://github.com/claudeheintz/LXTeensy4DMX_Library) just for the receiver, and I've managed to get stable DMX control of the display with it (no glitching at all), under the same conditions. Perhaps it could be worth seeing if there's something in that library that could make this library work better under heavier CPU loads?

welshcoder avatar Jul 15 '22 17:07 welshcoder

Just to make sure I’ve got it right: you’re seeing issues with TeensyDMX (receive) and SmartMatrix on a Teensy 4.1?

Are you willing to show me your code? I’d like to have a look to see how TeensyDMX is being used. For example, there’s no need to use an RX watch pin if you don’t care about measuring timings (for example, for testing purposes). That will free up some interrupt calls.

ssilverman avatar Jul 15 '22 18:07 ssilverman

Yes, that's right. Changing the priorities (SM was lower priority than TeensyDMX as it happens) didn't really help. When I made SM higher priority, the display worked fine, but virtually every single packet would be bad. Flipped it the other way, and I get the glitching of the display and some packets marked bad. By marked bad, I mean that the receivedBadBreak would be called.

Re: code - sure, no problem. I've put it here: https://gist.github.com/welshcoder/dc75fe40ff30a641028204670b0fc860. I've removed a lot of the commented out test code so that it's clearer as to what's going on. I think most of it is pretty self-explanatory, but let me know if you need anything else.

Edit: just to clarify, the setupDMXSubSystem() function is called from the main setup() function, and loopDMXSubSystem() is caller from the main loop() function.

welshcoder avatar Jul 17 '22 20:07 welshcoder

Let me know how this fix works for you: https://github.com/ssilverman/TeensyDMX/tree/atomic-packet-size-and-data

See the commit log, but essentially I added a new Sender::setPacketSizeAndData() function.

ssilverman avatar Aug 23 '22 15:08 ssilverman

Sorry for the delay in getting back to you, and just a quick message to say that I haven't yet had an opportunity to look into this. I'll try to do it over the weekend and let you know if the fix works.

welshcoder avatar Sep 06 '22 20:09 welshcoder

That would be amazing. Thank you.

ssilverman avatar Sep 10 '22 22:09 ssilverman

Sorry once again for the delay in getting back to you on this. I've spent a bit of time tonight looking into this. I'm now pretty convinced there are two issues here that I'll explain separately.

  1. I couldn't get the fix to work. I think this is the a2ac5f0 commit problem that I mentioned earlier. I just wasn't getting any data out, no matter what I did, including using my version of the fix. That was confirmed with a scope too, and it looked like the "Not working code" in the earlier post. I think that needs to be looked at first.

  2. The second problem is, IMHO, with the DMX receiver interrupt taking up too much time. This manifests itself as interrupting the SmartMatrix routines in the display, causing the display to breakdown for a second or two. I've managed to confirm this using a standalone DMX controller connected directly to the display (to remove the possibility of the DMX transmitter causing the problem), and I get the display glitching every now and again. Changing the DMX receiver to the LXTeensy4DMX library I mentioned before, and the glitching goes away.

I hope that helps. Just to let you know, I'm going to be away for a couple of weeks, so I won't be able to test anything in that time. Otherwise, I'm happy to help you where I can.

welshcoder avatar Sep 18 '22 21:09 welshcoder

I'd like to address these one at a time and go back to your first post, where you said that changing the interrupt disable/enable in the USBProWidget example to pause/resume seemed to fix the initial problem, the problem being the DMX transmitter wasn't behaving well with the display The change in the https://github.com/ssilverman/TeensyDMX/tree/atomic-packet-size-and-data branch does almost exactly the same thing as your suggested working code, but without pausing/resuming and without using disable-/enable-interrupts. The only difference is that there's one more line of code inside a "lock":

activePacketSize_ = size;

If the suggested code from your first post works, I'm at a loss to explain why the code in that branch (atomic-packet-size-and-data) doesn't work. Did you retry USBProWidget, per your first post, but with the new branch? Your original post is what this branch targets. Which brings me to: Does your suggested first-post fix still work, or was that erroneous since you've done more discovery?

Second, what happens if you define TEENSYDMX_USE_PERIODICTIMER for your build? It uses a slightly different incarnation of the internal periodic interval timer.

Third: When you say, "I couldn't get the fix to work," does this mean your first-post fix doesn't work unless you rewind back to before commit a2ac5f0?

ssilverman avatar Oct 26 '22 15:10 ssilverman