FastLED and NativeEthernet not playing well together

jahwerx

Member
Hey folks, continuing my quest to get a basic WebServer/LED controller working on the Teensy 4.1
Hardware: T4.1, Data pin is 7, running signal through a 3=>5V voltage shifter, Ethernet Kit for T4.1
Software: Using the latest 1.56 build of Teensyduino

I only need to drive 1 string of LEDs - under 200 pixels, but for bench testing I have 200 setup. a lightweight use case. I don't need multiple strings, or super fast processing (yet)

Issue: As soon as I enable Ethernet.begin(mac); via the NativeEthernet library only the first few pixels respond to the LED loop.
Independently, the FastLED patterns and the Ethernet Web Server both run perfectly.

The attached sketch is just a stripped down version of an LED pattern looping and my attempt to enable the bare bones Ethernet Server. The embedded video shows exactly what happens; and it's totally reproducible.
Any advice is welcome and appreciated, since I'm definitely not an expert here!
-J


Code:
#include <NativeEthernet.h>
#include <FastLED.h>


// Definitions ================
#define DATA_PIN            7
#define NUM_LEDS_PER_STRIP  200
#define NUM_STRIPS          1
#define LED_TYPE            WS2811
#define NUM_LEDS            NUM_LEDS_PER_STRIP  
#define COLOR_ORDER         BRG

// Ethernet Variables
EthernetServer server(80);              // The Web Server

// FastLED Variables
CRGB leds[NUM_LEDS_PER_STRIP * NUM_STRIPS];
uint32_t correction = TypicalLEDStrip;  // Color Correction
uint32_t temperature = OvercastSky;     // Color Temperature

uint8_t mac[6];
void teensyMAC(uint8_t *mac) {
    for(uint8_t by=0; by<2; by++) mac[by]=(HW_OCOTP_MAC1 >> ((1-by)*8)) & 0xFF;
    for(uint8_t by=0; by<4; by++) mac[by+2]=(HW_OCOTP_MAC0 >> ((3-by)*8)) & 0xFF;
    Serial.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void setup() {
  delay(3000); // 3 second delay for boot recovery, and a moment of silence
  FastLED.addLeds<NUM_STRIPS,LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS_PER_STRIP)
        .setCorrection( TypicalLEDStrip );
  Serial.begin(115200);
  teensyMAC(mac);
  //Ethernet.begin(mac);
  //MDNS.begin("DaBoosh", 2); //.local Domain name and number of services
  //MDNS.setServiceName("Teensy41_Service_Name"); //Uncomment to change service name
  //MDNS.addService("_https._tcp", 443); //Uncomment for TLS
  //MDNS.addService("_http._tcp", 80);
  //server.begin();
  //Serial.print("IP  address: ");
  //Serial.println(Ethernet.localIP());
  //Serial.send_now();
 
}

void loop()
{
  EVERY_N_MILLISECONDS( 20) {
    pacifica_loop();
    FastLED.show();
  }
}

//////////////////////////////////////////////////////////////////////////
//
// The code for this animation is more complicated than other examples, and 
// while it is "ready to run", and documented in general, it is probably not 
// the best starting point for learning.  Nevertheless, it does illustrate some
// useful techniques.
//
//////////////////////////////////////////////////////////////////////////
//
// In this animation, there are four "layers" of waves of light.  
//
// Each layer moves independently, and each is scaled separately.
//
// All four wave layers are added together on top of each other, and then 
// another filter is applied that adds "whitecaps" of brightness where the 
// waves line up with each other more.  Finally, another pass is taken
// over the led array to 'deepen' (dim) the blues and greens.
//
// The speed and scale and motion each layer varies slowly within independent 
// hand-chosen ranges, which is why the code has a lot of low-speed 'beatsin8' functions
// with a lot of oddly specific numeric ranges.
//
// These three custom blue-green color palettes were inspired by the colors found in
// the waters off the southern coast of California, https://goo.gl/maps/QQgd97jjHesHZVxQ7
//
CRGBPalette16 pacifica_palette_1 = 
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, 
      0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x14554B, 0x28AA50 };
CRGBPalette16 pacifica_palette_2 = 
    { 0x000507, 0x000409, 0x00030B, 0x00030D, 0x000210, 0x000212, 0x000114, 0x000117, 
      0x000019, 0x00001C, 0x000026, 0x000031, 0x00003B, 0x000046, 0x0C5F52, 0x19BE5F };
CRGBPalette16 pacifica_palette_3 = 
    { 0x000208, 0x00030E, 0x000514, 0x00061A, 0x000820, 0x000927, 0x000B2D, 0x000C33, 
      0x000E39, 0x001040, 0x001450, 0x001860, 0x001C70, 0x002080, 0x1040BF, 0x2060FF };


void pacifica_loop()
{
  // Increment the four "color index start" counters, one for each wave layer.
  // Each is incremented at a different speed, and the speeds vary over time.
  static uint16_t sCIStart1, sCIStart2, sCIStart3, sCIStart4;
  static uint32_t sLastms = 0;
  uint32_t ms = GET_MILLIS();
  uint32_t deltams = ms - sLastms;
  sLastms = ms;
  uint16_t speedfactor1 = beatsin16(3, 179, 269);
  uint16_t speedfactor2 = beatsin16(4, 179, 269);
  uint32_t deltams1 = (deltams * speedfactor1) / 256;
  uint32_t deltams2 = (deltams * speedfactor2) / 256;
  uint32_t deltams21 = (deltams1 + deltams2) / 2;
  sCIStart1 += (deltams1 * beatsin88(1011,10,13));
  sCIStart2 -= (deltams21 * beatsin88(777,8,11));
  sCIStart3 -= (deltams1 * beatsin88(501,5,7));
  sCIStart4 -= (deltams2 * beatsin88(257,4,6));

  // Clear out the LED array to a dim background blue-green
  fill_solid( leds, NUM_LEDS, CRGB( 2, 6, 10));

  // Render each of four layers, with different scales and speeds, that vary over time
  pacifica_one_layer( pacifica_palette_1, sCIStart1, beatsin16( 3, 11 * 256, 14 * 256), beatsin8( 10, 70, 130), 0-beat16( 301) );
  pacifica_one_layer( pacifica_palette_2, sCIStart2, beatsin16( 4,  6 * 256,  9 * 256), beatsin8( 17, 40,  80), beat16( 401) );
  pacifica_one_layer( pacifica_palette_3, sCIStart3, 6 * 256, beatsin8( 9, 10,38), 0-beat16(503));
  pacifica_one_layer( pacifica_palette_3, sCIStart4, 5 * 256, beatsin8( 8, 10,28), beat16(601));

  // Add brighter 'whitecaps' where the waves lines up more
  pacifica_add_whitecaps();

  // Deepen the blues and greens a bit
  pacifica_deepen_colors();
}

// Add one layer of waves into the led array
void pacifica_one_layer( CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff)
{
  uint16_t ci = cistart;
  uint16_t waveangle = ioff;
  uint16_t wavescale_half = (wavescale / 2) + 20;
  for( uint16_t i = 0; i < NUM_LEDS; i++) {
    waveangle += 250;
    uint16_t s16 = sin16( waveangle ) + 32768;
    uint16_t cs = scale16( s16 , wavescale_half ) + wavescale_half;
    ci += cs;
    uint16_t sindex16 = sin16( ci) + 32768;
    uint8_t sindex8 = scale16( sindex16, 240);
    CRGB c = ColorFromPalette( p, sindex8, bri, LINEARBLEND);
    leds[i] += c;
  }
}

// Add extra 'white' to areas where the four layers of light have lined up brightly
void pacifica_add_whitecaps()
{
  uint8_t basethreshold = beatsin8( 9, 55, 65);
  uint8_t wave = beat8( 7 );
  
  for( uint16_t i = 0; i < NUM_LEDS; i++) {
    uint8_t threshold = scale8( sin8( wave), 20) + basethreshold;
    wave += 7;
    uint8_t l = leds[i].getAverageLight();
    if( l > threshold) {
      uint8_t overage = l - threshold;
      uint8_t overage2 = qadd8( overage, overage);
      leds[i] += CRGB( overage, overage2, qadd8( overage2, overage2));
    }
  }
}

// Deepen the blues and greens
void pacifica_deepen_colors()
{
  for( uint16_t i = 0; i < NUM_LEDS; i++) {
    leds[i].blue = scale8( leds[i].blue,  145); 
    leds[i].green= scale8( leds[i].green, 200); 
    leds[i] |= CRGB( 2, 5, 7);
  }
}
 
Through trial and error, I've made some marginal success.

I've introduced Octo into the mix, and now my LEDs are working again (with Ethernet).

I found this code and it seems to manage the FastLED issue.
https://gist.github.com/Flavourdynamics/f051a94b97b586900b3bd06563266275

When I look at the 2 OctoWS2811 Example sketches ("BasicTest_FastLED" and "Teensy4_PinList") they seem so much more simple... but I couldn't figure out how to marry those 2 together. but thankfully someone did :)

cheers,
J
 
At first I was wondering if the NativeEthernet library's 1ms timer interrupt is causing issues. The OctoWS2811 adapter code uses DMA, so I _think_ that will not let that timer interrupt affect things, which is why it might work better. Curious, which versions of FastLED and Teensyduino are you using? There've been some recent library updates and I believe Paul has already included those in the FastLED version included with the Teensyduino install. These changes include:
1. WS2811B timing fixes for Teensy 4.x, and
2. A fixed OctoWS2811 adapter for Teensy 4.x.

I.e. if you're using the latest Teensyduino (v1.56), or you're not and have recently updated your own FastLED version (in wherever Arduino puts the libraries on your particular system), then FastLED should work just fine without having to import additional OctoWS2811 adapter fixes.
 
Back
Top