Switching and porting from Arduino Mega to Teensy 4.1 led strip project

Status
Not open for further replies.

AleMonti

Member
Hi everyone,
I'm doing a pre-programmed lighting show synced to a video (~1.5h long) with 435 + 448 + 162 WS2812B 5V and 6 5050 12V strips. I'm now running an Arduino Mega but after programming the first 5 minutes I noticed that the flash storage is way too small for the whole show. My current approach is using endless lines of code to "encode" the lighting sequences. To save space I could have stored them as data on an SD to then be ran through an interpreter and displayed, but even though it's not the ideal solution I'm going on with the "endless sketch" approach because it's way easier to implement. I, therefore, want to switch to a Teensy 4.1, which not only gives me all the storage I need but also has way faster processing capabilities which are a plus for what I'm trying to achieve.

I'm completely new to the Teensy platform and I still don't consider myself an advanced user of microcontrollers so I have a few questions about the setup and about some electronics as well.

  • I'm planning to use the Teensyduino IDE. Do you think porting will be easy?
  • It looks like Teensy's logic of 3.3V is not good for the WS2812B data lines. I'm planning to use a 74HCT245 like this to step up at 5V. The only difference is that I'll use A2-B2 and A3-B3 too as I have 3 strips.
  • I plan to use FastLED together with OctoWS2811 to drive the leds, similar to how is illustrated here. Is this the best approach?
  • On the Mega staying in sync with the video required a frame counter based off an RTC as I need ~10ms accuracy over the whole 1,5h show. Briefly, the problem was that the calls to FastLED.show() disabled interrupts and for long strip interfered with the accuracy of millis(). I solved the problem by using the 32K output of a ZS-042 RTC and interrupts to make a timer that increments just 25 times a second (the video frame rate) to time all updates to the lights. Will this kind of solution be needed on the Teensy or the required level of accuracy can be achieved more easily?
  • To control the 5050 strips (2 RGB, 4 white) I currently use 10 IRL540N MOSFETs (at 1.5A max each). To comply with the 3.3V logic what should I swap them with if I have to? Also now I have 220Ω resistors between gates and the output pins. Max current on the output pins of the Teensy should be 4mA, so I have to swap them for 1kΩ ones right?

Thanks!
 
Do you think porting will be easy?

The answer to this first question really depends on how you've written your code. The quick way to find out is to run the Teensyduino installer, restart Arduino, select Teensy 4.1 from the Tools > Boards menu, and then click Verify. Quick and easy to try before you buy or solder anything.

No errors, or compile errors you can understand and know how to solve are a good sign. Usually when code compiles, the remaining problems are often things like needing to add small delays. The most common case is with scanning a matrix of pushbuttons, where AVR code often needs no extra delay from changing the rows to reading the columns, but Teensy 4.1 is much too fast and the read happens before the actual voltage at the pins can change.


I plan to use FastLED together with OctoWS2811 to drive the leds, similar to how is illustrated here. Is this the best approach?

Yes, use of the non-blocking library gives best performance. You can also use a few instances of WS2812Serial instead of OctoWS2811, if you like.


I need ~10ms accuracy over the whole 1,5h show. Briefly, the problem was that the calls to FastLED.show() disabled interrupts and for long strip interfered with the accuracy of millis().

This problem is completely eliminated by use of non-blocking libraries like OctoWS2811 or WS2812Serial.


I solved the problem by using the 32K output of a ZS-042 RTC and interrupts to make a timer that increments just 25 times a second (the video frame rate) to time all updates to the lights. Will this kind of solution be needed on the Teensy or the required level of accuracy can be achieved more easily

Should not be needed if using the non-blocking libraries to drive the LEDs. You can use millis(), micros(), elapsedMillis, elapsedMicros.

If you use FastLED's built-in driver, or Adafruit_NeoPixel, then you will have the same problem with LED updates interfering with timing functions. You can get an accurate interrupt without the extra hardware. Use IntervalTimer. But again, should only be needed if you use the blocking libraries for the LEDs.


Regarding your hardware question, difficult to say with certainty when I can't see the circuitry. But I'm going to guess whatever circuitry you're using probably will not work as well if the voltage driven onto the mosfet gate is only 3.3V rather than 5V. Maybe a workaround would be to use some of the leftover 74HCT245 buffers to step up Teensy's output to a similar 5V signal as you get from Arduino Mega. However, this is based on some guesswork about how you've built this stuff.
 
The quick way to find out is to run the Teensyduino installer, restart Arduino, select Teensy 4.1 from the Tools > Boards menu, and then click Verify. Quick and easy to try before you buy or solder anything.
How could I haven't thought of that! I now tried and except for some easily fixable warnings the code compiles fine. Great!


Yes, use of the non-blocking library gives best performance. You can also use a few instances of WS2812Serial instead of OctoWS2811
I'll try both of them and see what works best with FastLED functions.


Should not be needed if using the non-blocking libraries to drive the LEDs. You can use millis(), micros(), elapsedMillis, elapsedMicros.
You can get an accurate interrupt without the extra hardware. Use IntervalTimer.
This is great news, my only concern is the accuracy of those time-keeping methods. I need the timer to drift the least amount possible to keep the lights in sync with the video for the whole 1,5h. These functions run off an oscillator or an RTC? My concerns come from the fact that on the Mega all of the built-in timing functions are based on an oscillator and (interrupts problem aside) they were drifting a considerable amount.


Regarding your hardware question, difficult to say with certainty when I can't see the circuitry.
Put simply I was asking if the MOSFETs that I'm using now with 5V logic could work at 3.3V. I looked at their data sheet but I can't figure it out. If they're not good like you said I could use the 74HCT245 to step up, or better directly change them for more appropriate ones. Do you know any models that work nicely for this purpose? It's a simple circuit that uses the PWM outputs to drive the MOSFETs like it's done here. With 5V the resistors are 220Ω since the max current on the pins of the Mega is 20mA. On the Teensy it's 4mA, so I think the correct resistor should be 825Ω. (1kΩ may be good as well).
 
For the time, you just need clever programming.

Don't set your counter (or whatever you use) to zero. Do that only one time, when the show starts.
Everything else is an offset to the starttime.
If you do that, millis() will work. It's pretty exact.
For ease of use, try elapsedMillis
 
Don't set your counter (or whatever you use) to zero. Do that only one time, when the show starts.
Everything else is an offset to the starttime.
That's exactly what I was planning to do. I'm only worried that the hardware that runs millis(), elapsedMillis() etc will drift too much during the 1.5h and therefore get the lights out of sync by the end of the show.
 
Put simply I was asking if the MOSFETs that I'm using now with 5V logic could work at 3.3V. I looked at their data sheet but I can't figure it out.
I did a bit more research and they may not be suitable for 3.3V gate drive. I found the IRF3708, what do you think?
 
That's exactly what I was planning to do. I'm only worried that the hardware that runs millis(), elapsedMillis() etc will drift too much during the 1.5h and therefore get the lights out of sync by the end of the show.

Teensy has a pretty good crystal, but it's not a special (expensive) temperature compensated type.

Many Arduino Uno & Mega boards have a low quality ceramic resonator, not a real quartz crystal. If your Mega is one of those, you'll find Teensy will perform so much better. But if you have a Mega made with a good quality quartz crystal, and the designer went to some effort to use the right capacitors rather than just copy someone else's board without carefully measuring the oscillator performance, then it should be similar to Teensy.

But odds are whatever other gear is running that show probably also has an ordinary (not special temperature compensated or oven heated) crystal. Ordinary crystals tend to have errors in a 10 to 50 ppm range (if the circuitry is designed well with properly matched capacitors). If you get unlucky and Teensy's crystal is 30 ppm too fast and the other gear is 40 ppm too slow, a bad case scenario might look like 70 ppm total error. So you could expect a total drift of 1.5 * 3600 * 70 / 1e6 = 0.378 seconds in that case. If the other gear is good quality, odds are good you'll probably do better than this.
 
Choosing mosfets can be tricky. Generally as the on resistance gets lower, and as the required gate voltage is lower, you tend to see the "total gate charge" spec grow larger. Sometimes a lot larger!

If you will only turn the mosfet on once and leave it on, maybe that's ok. Larger gate charge means more electrons have to flow in/out of the gate to make the transistor work. Usually something intentionally limits the current, either resistors or a special chip. More charge needed and limited rate of charging means it will take longer to turn on or off. The problem is what happens when it's partially on.
 
Welcome to Teensy. I think you will find this device much better than anything Arduino has and this forum is very helpful.

PS. 435 + 448 + 162 WS2812B 5V and 6 5050 12V strips? I'm dying to see a photo of this setup as it must be a wall of lights!
 
Welcome to Teensy. I think you will find this device much better than anything Arduino has
Thank you, I'll receive mine next week and I'm super excited.


So you could expect a total drift of 1.5 * 3600 * 70 / 1e6 = 0.378 seconds in that case.
This would be way too much since 0,378s at 25fps is 9 frames, which is too noticeable in tight patterns synced to music. I'll try to use the same RTC board I was using with the Mega and the same approach. It's a DS3231N chip (accuracy is ±2ppm) that can output a 32678Hz square wave. I use that along with a 16-bit counter/timer to generate an interrupt every 1/25 of a second to increment the frame counter.
This is the code I was running on the Mega.
Code:
#include <FastLED.h>
#include "RTClib.h" //RTClib library

RTC_DS3231 rtc;

#define NUM_LEDS 448
#define DATA_PIN 3
CRGB leds[NUM_LEDS];

CRGB testimage[NUM_LEDS]; //for testing purposes only

volatile uint32_t frameCounter = 0;
uint32_t frameCount;
uint32_t frameCountPrev;

void setup() {
  //create some random LED data to ensure compiler does not remove the FastLED code
  for (size_t i = 0; i < NUM_LEDS; i++) {
    testimage[i] = CRGB(random(256), random(256), random(256));
  }
  
  Serial.begin(115200);
  Serial.println("startup");
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  
  if (!rtc.isEnabled32K()) { //verify 32K output is enabled
    rtc.enable32K();
  }
  
  TCCR5A = 0; //clear control register A
  TCCR5B = 0; //clear control register B
  TCNT5 = 0;  //clear counter
  OCR5A = 1309; //set value for output compare register A  (32768Hz * 1/25 second) - 1 = 1309
  TCCR5B |= (1 << WGM52); //Set CTC mode (WGM5 = 0100);
  TCCR5B |= (1 << CS52) | (1 << CS51) | (1 << CS50) ; //External Clock mode using D47 as input
  TIMSK5 |= (1 << OCIE5A); //Set the interrupt request
  sei(); //Enable interrupt

  FastLED.addLeds<WS2812B, DATA_PIN>(leds, NUM_LEDS);
}



void loop() {
  //temporarily disable interrupts while making a copy of frameCounter
  noInterrupts();
  frameCount = frameCounter;
  interrupts();

  if (frameCount != frameCountPrev) { //only execute once per frame
    if ((frameCount - frameCountPrev) != 1) {
      Serial.println("missed frame");
      while (1) {};
    }
    frameCountPrev = frameCount;
    for (size_t i = 0; i < NUM_LEDS; i++) { //copy testimage to LED array
      leds[i] = testimage[i];
    }
    FastLED.show();
    Serial.print(frameCount);
    //print millis every 25 frames to test discrepancy
    if ((frameCount % 25) == 0) {
      Serial.print('\t');
      Serial.print(millis());
    }
    Serial.println();
  }
}

ISR(TIMER5_COMPA_vect) {   //This is the interrupt request
  static byte cycleCount = 24;
  //adjustment to compensate for 32768 not being evenly divisible by 25
  //counter will count ( (7 * 1310) + (18 * 1311) ) = 32768 pulses over 25 frames
  if ((cycleCount & 0x03) == 0) {
    OCR5A = 1309; //1310 clock pulses
  } else {
    OCR5A = 1310; //1311 clock pulses
  }
  if (cycleCount == 0) {
    cycleCount = 25;
  }
  cycleCount--;

  frameCounter++; //actual frame counter
}
This of course does not compile on the Teensyduino, the register's names are proprietary of the Mega. Is it just a matter of changing to the new registers of the Teensy to port the code?


Choosing mosfets can be tricky.
For real! Everyone seems to have a different opinion on them.

If you will only turn the mosfet on once and leave it on, maybe that's ok.
Not really, I mostly have them off or at low brightness, and sometimes flash them at full brightness very quickly. Actually the ones I was using with the Mega (IRL540N) slowly opened themselves after a few minutes if not driven.
I did some more research and the ones that get suggested the most are the one I linked you before (IRF3708) and the IRLZ44N.


I'm dying to see a photo of this setup
I'll try to remember and post a picture when I finish it. It isn't a wall but basically a narrow black room with strips on top and bottom, some cool hanging matrices and shapes with a big tv screen at the end.
 
Last edited:
Hi, I just stumbled upon this thread while looking for something else. You and I are doing a lot of the same stuff, and I'd be happy to share my solutions to some of your questions. If you respond here then we can exchange contact info for follow-ups.
-Keith
 
I would recommend you to use VisualStudio-Code if you use both boards.
Its easy to install and to switch between projects, copying software-parts etc.
I did so for my camera remote project
 
Status
Not open for further replies.
Back
Top