Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 18 of 18

Thread: Serial Issues with Neopixel

  1. #1
    Junior Member
    Join Date
    Dec 2019
    Posts
    8

    Serial Issues with Neopixel

    I was looking for some help with; understanding DMA, Serial, managing interrupts and blocking code.

    I have an ESP32 DEVKITC v4 that I'm using to handle user Input both from hardware such as rotary encoders and from wifi. The ESP32 is also responsible for driving an 20x4 LCD to display a menu for the user to interact with.

    I then have a Teensy 3.5 handling the pixel driving. It's handles generating the pixels frame, loading it to the buffer and outputting the signal. I'm running a modified version of the Adafruit Neopixel Library to control my TM1814 LED's

    The trouble I'm having at the moment is the communication between the ESP32 and Teensy. The neopixel's code requires blocking in order to get right the timings for the LED driver IC's. while the ESP has interrupts used for the rotary encoder to keep an accurate count, both of these mess with the Serial communication. Here is my test code so far, it is a stripped back version of the final project's code to make it simple to identify problems and help build complexity slowly.

    TEENSY3.5_RECEIVER:

    Code:
    // include the library code:
    #include <Adafruit_NeoPixel.h>
    
    //number of LEDs in Strip
    int NUM_LEDS = 52;
    
    //data and clock pin RGB
    #define DATA_PINA 11
    
    #define RTR_PIN 28
    
    uint32_t amp = ((uint32_t)63 << 24) | ((uint32_t)63 << 16) | ((uint32_t)63 <<  8) | 63;
    
    Adafruit_NeoPixel pixelsA(NUM_LEDS, DATA_PINA, NEO_WRGB + NEO_KHZ800);
    
    struct Received_Data_t {
      char startMarker;
      int rgbwArrayFromESP;
      char comma;
      int rgbwFromESP;
      char endMarker;
    };
    
    union Channel_Packet_t {
      Received_Data_t rgbwLED;
      byte ChannelPacket[sizeof(Received_Data_t)];
    };
    
    Channel_Packet_t LEDon;
    
    //apeture controls
    int apeture = NUM_LEDS;
    int apeturePosition = NUM_LEDS / 2;
    
    //RGB Sub Menu Variables
    int rgbArraySelector;
    uint8_t subRed;
    uint8_t subGreen;
    uint8_t subBlue;
    uint8_t subWhite;
    
    uint8_t rgbwArray [] = {subRed, subGreen, subBlue, subWhite};
    
    const byte numChars = sizeof(Received_Data_t);
    char receivedChars[numChars];
    
    int rgbwFromESP = 0;
    
    boolean newData = false;
    
    void setup() {
      Serial1.setTX(26);
      Serial1.setRX(27);
      Serial1.begin(115200);
      Serial.begin(9600);
    
      while (!Serial);
      while (!Serial1);
    
      pixelsA.begin(); // INITIALIZE NeoPixel strip object
    
      //clear the LEDS
      pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
      pixelsA.show();
    
      pinMode(RTR_PIN, OUTPUT);
      digitalWrite(RTR_PIN, LOW);
    
    }
    
    void loop() {
      Read_to_Receive(); //activate transmission 
      recvWithStartEndMarkers(); //read buffer
      if (newData == true) {
        parseData();
        showParsedData();
        newData = false;
      }
    }
    
    void LED_clear() {
    
      pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
      pixelsA.show();
    
    }
    
    void LED_RGBW() {
      pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
      pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition, apeture / 2);
      pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition - (apeture / 2), apeture / 2);
      pixelsA.show();
    }
    
    void recvWithStartEndMarkers() {
      static boolean recvInProgress = false;
      static byte ndx = 0;
      char startMarker = '<';
      char endMarker = '>';
      char rc;
      while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();
    
        if (recvInProgress == true) {
          if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
              ndx = numChars - 1;
            }
          }
          else {
            receivedChars[ndx] = rc; // terminate the string
            recvInProgress = false;
            ndx = 0;
            newData = true;
          }
        }
    
        else if (rc == startMarker) {
          receivedChars[ndx] = rc;
          ndx++;
          recvInProgress = true;
        }
      }
    }
    //============
    
    void Read_to_Receive() {
    
      pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
      pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition, apeture / 2);
      pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition - (apeture / 2), apeture / 2);
      digitalWrite(RTR_PIN, LOW);
      pixelsA.show();
      digitalWrite(RTR_PIN, HIGH);
      //wait for ESP to transmit
      delay(1);
    }
    
    //============
    
    void parseData() {      // split the data into its parts
      for (uint8_t k = 0; k < sizeof(Received_Data_t); k++) {
        LEDon.ChannelPacket[k] = receivedChars[k];
      }
      rgbArraySelector = LEDon.rgbwLED.rgbwArrayFromESP;
      rgbwFromESP = LEDon.rgbwLED.rgbwFromESP;
    
      rgbwArray[rgbArraySelector] = rgbwFromESP;
    }
    
    //============
    void showParsedData() {
      Serial.print("Array ");
      Serial.println(rgbArraySelector);
      Serial.print("Intensity ");
      Serial.println(rgbwFromESP);
    
    }
    Although this code mostly works I still get errors in transmission while turning the encoder quickly. This is where I'm hoping DMA might be a solution. If I understand DMA correctly I can use it and uart, Serial, to send data between the two MCU's and ignore the blocking code and interrupts. Then in the main loop poll DMA buffer and parse the received data but I'm unable to find a solid example of using DMA and Uart. Does anyone know if this will work and if so are there some examples you can link for me to check out?

    I would prefer to find a software solution but As a hardware solution I was also looking at using this or an external SRAM that both MCU's have access to. To act as a buffer to store the user generated variables to be polled when appropriate.

    I'm still fairly new to all this so any further questions are welcome and I want to know people's thoughts on this.

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,588
    Probably better threads - but look at :: Non-Blocking-WS2812-LED-Library-and-Teensy-4-0

    This won't help issues if ESP32 breaking Serial tracking encoder - but there is a non-blocking version of the WS2812 for Teensy.

    See also this post : TeensyLC-Fried-by-5V-Tx-Rx-from-Serial-communication-with-UNO?p=224613&viewfull=1#post224613

  3. #3
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,588
    Here is a proper link to PJRC library page: pjrc.com/non-blocking-ws2812-led-library/

  4. #4
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    hey defragster,

    Thanks for the suggestion I'll have a look into them. It might be a little difficult as I need to modify the libraries to get the RGBW TM1814 to work .
    I'll keep this thread updates

  5. #5
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    hey defragzter,

    I've been playing with the libraries you suggested but I can't seem to get them to work with the TM1814 and RGBW and stable.
    I still think the best method would be to use a non interrupt version of uart if possible with the Teensy3.5.
    Is it possible or will I have to find another solution?

  6. #6
    Senior Member crees's Avatar
    Join Date
    Dec 2016
    Location
    Utah
    Posts
    210
    Hi the TM1814 is an awkward chip. I am curious are you getting anything close to what your expecting like colors and intensities? Are you getting random color and flicker?

  7. #7
    Senior Member crees's Avatar
    Join Date
    Dec 2016
    Location
    Utah
    Posts
    210
    I worked on this chip once. Double check but the tm1814 logic is not the same as a neopixel. It’s almost opposite. The only way you can get this strip to work is to bitbang your own code or modify an existing library.


    Edit

    Interestingly I found your post on Arduino and that you got it to work! Awesome job! I would think that the non blocking serial would allow interrupt free operation. As odd as this chip is you may want to fire up the scope and compare with a working example and see what kind of timings you can modify in non blocking serial. Also I want to say that this chip may be more sensitive than the typical neopixel?
    Last edited by crees; 01-04-2020 at 07:57 AM.

  8. #8
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    Hey Crees,

    I've been playing around with the two libraries suggested by defragster https://github.com/Makuna/NeoPixelBus & pjrc.com/non-blocking-ws2812-led-library/. I tested them with a Ws2812 test strip of 8 pixels, the non blocking Ws2812 library on the teensy3.5 works well but when Serial is introduced and the number of LEDs is greater than 8 the system flickers presumably because of timing issues. I've run the NeoPixelBus on ESP32 with similar problems once Serial is introduced the problems start.

    Are there any other methods that might be better than Serial, would SPI and I2c have the same problems?

  9. #9
    Senior Member crees's Avatar
    Join Date
    Dec 2016
    Location
    Utah
    Posts
    210
    I currently use the DMA driven octows2811 and attempted to invert the IO logic but from the scope I did not get output timing to work yet. I put it on the back burner for now but may revisit it later.

    What I am very interested in is the 12c that yves bazin has been able to accomplish in fastled. It also uses DMA.

  10. #10
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,091
    Sorry, I know others who use these leds and the like can answer a lot better than I can.

    But wondering when you say things like > 8, how many? Also how are they being powered? i.e. are these LEDS being powered through USB? Or some external power source. If external, does it have enough power for the number of LEDs you have?

    When you say introduce Serial, what are you saying? That is @Paul's non-blocking library uses DMA to transfer the data, so each output should not be impacted by any interrupts that occur to handle the serial data...


    Also maybe I am reading this wrong, but it looks like your main loop calls read_to_receive, which looks to me like it clears out the LEDs and then pauses for 1ms and then calls off to receive data from the ESP32? And then when it gets a full frame from the ESP32, it then displays it? Then blanks it again? Again maybe I am reading that wrong...

  11. #11
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,091
    Warning: I may be completely wrong in the above post. I am just not sure how it is expected to work.

    That is your loop is:
    Code:
    void loop() {
      Read_to_Receive(); //activate transmission
      recvWithStartEndMarkers(); //read buffer
      if (newData == true) {
        parseData();
        showParsedData();
        newData = false;
      }
    }
    And each call Read_to_Recieve() does a show of the data and asks for data... Again I don't know when it asks... Is it on the
    Code:
    void Read_to_Receive() {
    
      pixelsA.fill(amp, ~amp, pixelsA.Color(0, 0, 0, 0), 0, NUM_LEDS);
      pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition, apeture / 2);
      pixelsA.fill(amp, ~amp, pixelsA.Color(rgbwArray[0], rgbwArray[1], rgbwArray[2], rgbwArray[3]), apeturePosition - (apeture / 2), apeture / 2);
      digitalWrite(RTR_PIN, LOW);
      pixelsA.show();
      digitalWrite(RTR_PIN, HIGH);
      //wait for ESP to transmit
      delay(1);
    }
    Pin going low or pin going High. If High, you wait 1ms for data before your return and then try receive the data?

    With the Data you are trying to receive, which I believe is:
    Code:
    struct Received_Data_t {
      char startMarker;
      int rgbwArrayFromESP;
      char comma;
      int rgbwFromESP;
      char endMarker;
    };
    Again I am not sure if the size of this structure will turn out to be 11 or 17 bytes and the same on both processors? (11 if packed, 17 if not).
    (Or maybe completely different if both processors don't have a common size for int. )

    But if you are trying to receive this data in one call to recvWithStartEndMarkers, it may easily not have a full packet yet.
    So it would be curious to see if you are showing multiple times per receiving?

    Again not sure, but just throwing out ideas. Does it get better if you delay 2 instead of 1?

    Or maybe your function recvWithStartEndMarkers should not exit if it has a partial packet, or maybe it does after some timeout...

    Or maybe Read_to_Receive should not do anything if a Read is currently active, or only display if it has New data...

    Again sorry for just throwing darts here!

  12. #12
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    Hey Kurt,

    To answer some of your Questions,
    But wondering when you say things like > 8, how many? Also how are they being powered? i.e. are these LEDS being powered through USB? Or some external power source. If external, does it have enough power for the number of LEDs you have?
    The total strip length of the TM1814 may vary but it will be round 50-75, They are powered off a meanwell 240W 12v LED Driver power supply which is more than enough to supply the full length.

    When you say introduce Serial, what are you saying? That is @Paul's non-blocking library uses DMA to transfer the data, so each output should not be impacted by any interrupts that occur to handle the serial data...
    Sorry I should've been a little clearer here, here I'm talking about receiving Serial data from the ESP32. That's my bad.

    Thanks for taking a look, I think what might help to answer a few of your questions and clear things up a little is to post the ESP32_Transmitter code. This code is a simplified version of what the final project will be, this way I can identify problems as they appear.

    so here it is:
    Code:
    #include <Rotary.h>
    
    #define RTS_PIN 5
    
    int previousArray;
    int previousRGBW;
    
    #define inPinA  35
    
    //rotary acceleration variables
    int rotaryTime;
    volatile int counterA;
    volatile int counterB;
    byte enableAcceleration;
    bool lockFlag = false;
    
    Rotary rotaryA = Rotary(32, 33);
    
    //teensy is expecting data <rgbwArrayToTeensy,rgbwToTeensy>
    typedef struct ESPtransmit_t {
      char startMarker;
      int rgbwArrayToTeensy;
      char comma;
      int rgbwToTeensy;
      char endMarker;
    };
    
    typedef union Channel_Packet_t {
      ESPtransmit_t rgbwLED;
      byte ChannelPacket[sizeof(ESPtransmit_t)];
    };
    
    Channel_Packet_t blueOn;
    
    void setup() {
      Serial.begin(9600);
      Serial2.begin(115200, SERIAL_8N1, 16, 17);
    
      while (!Serial);
      while (!Serial2);
    
      pinMode(RTS_PIN, INPUT);
      attachInterrupt(digitalPinToInterrupt(RTS_PIN), Transmit_Data, RISING);
      attachInterrupt(digitalPinToInterrupt(32), rotateA, CHANGE);
      attachInterrupt(digitalPinToInterrupt(33), rotateA, CHANGE);
    
    }
    
    void loop() {
      for (int x = 0; x != 125; x++) {
        blueOn.rgbwLED = {'<', 2, ',', x, '>'};
        //to simulate time between frames from DMX
        delay(21);
      }
    }
    
    
    void Transmit_Data() {
      noInterrupts();
      if (previousRGBW != blueOn.rgbwLED.rgbwToTeensy) {
        Serial2.write(blueOn.ChannelPacket, sizeof(ESPtransmit_t));
        Serial.println("send");
        previousRGBW = blueOn.rgbwLED.rgbwToTeensy;
      }
      interrupts();
    }
    
    void rotateA() {
      int speedMultiplier = 1;
      unsigned char result = rotaryA.process();
      if (lockFlag == false) {
        if (result == DIR_CW) {
          if (millis() - rotaryTime <= 10 && enableAcceleration == 0x01) {
            speedMultiplier = 7;
    
          }
          else if (digitalRead(inPinA) == HIGH) {
            speedMultiplier = 700;
          }
          counterA += speedMultiplier;
          rotaryTime = millis();
        }
        else if (result == DIR_CCW) {
          if (millis() - rotaryTime <= 10 && enableAcceleration == 0x01) {
            speedMultiplier = 7;
    
          }
          else if (digitalRead(inPinA) == HIGH) {
            speedMultiplier = 700;
          }
          counterA -= speedMultiplier;
          rotaryTime = millis();
        }
      }
    }
    The rotary encoder variable
    Code:
    counterA
    can simply replace the for loop so the user can generate a new variable.

    Warning: I may be completely wrong in the above post. I am just not sure how it is expected to work.
    You are honestly pretty close the structure size is 20bytes on the ESP32 and I can send, receive and parse the data fine when I don't call
    Code:
    pixelsA.show()
    .

  13. #13
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    To clarify a little,

    The main problem I'm facing is trying to drive the TM1814 LEDs on the Teensy 3.5. It needs to be time critical with so there can be no interference with the output method what ever it may be (DMA I2s/c, SPI, UART or Bit Banging). Then I need to receive data from the ESP32 that the user has generated. This data will usually be an individual variable, say for example the Blue in RGBW.

    What happens at the moment is something, whether it is pixelsA.show() on the Teensy or the rotary encoder interrupt on the ESP32 causes the Serial communication to mess up and receive incorrect data. What I'm looking for is a method to transmit the data from the ESP32 to the Teensy reliably while being compatible with interrupts and the tight timing code the pixels require.

    What I think needs to happen is either some kind of buffer needs to be in place where the esp32 can write to it and the teensy can poll it and read the buffer. I've been doing a bit of research and wanted to know if looking further into the FIFO buffer might work? Or perhaps some sort of shared SRAM (possible even the inbuilt spi Sram module on the ESP32 which has pins I can access directly connected to it)?

    The other option would be something similar to what I'm trying already in which the ESP32 "Calls" the Teensy to tell it there is new data. Then the Teensy "Responds" when it is able to receive. however feels like it might have more interrupts involved as well as more use of while and delays where the ESp32 would be "locked up" waiting to transmit the data leaving the user unable to interact with it again adding unwanted amounts of latency.

    I'm spit balling a little and trying to see if something sticks. It feels like I might be barreling towards a situation where I will have to chose to sacrifice something and I might be asking for too much.

    Thanks for all the suggestions and help thus far! It's all been great

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,302
    Quote Originally Posted by ConnorN View Post
    I tested them with a Ws2812 test strip of 8 pixels, the non blocking Ws2812 library on the teensy3.5 works well but when Serial is introduced and the number of LEDs is greater than 8 the system flickers presumably because of timing issues.
    Can you share this test code, and test code that does the transmitting of data, so anyone here can reproduce this problem?

    The many cases you've mentioned where blocking interrupts interferes with serial data are expected results.

    WS2812Serial should not interfere with serial data reception. I would like to look into the "presumably because of timing issues" problem you saw (only in this case - not the others where interrupts were blocked by libs like Adafruit_NeoPixel). But if you do not give us the *exact* code to reproduce the problem, how can anyone investigate?

  15. #15
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,091
    As Paul mentioned, seeing full code sets can help, especially if someone has a setup similar who can try it out.

    As I was eluding to in previous post, I am thinking you simply have a communications timing issue and nothing really nothing majorly wrong hardware wise...

    Again I think there could be simple issue of timing of how your functions in main loop are working:
    Code:
    void loop() {
      Read_to_Receive(); //activate transmission
      recvWithStartEndMarkers(); //read buffer
      if (newData == true) {
        parseData();
        showParsedData();
        newData = false;
      }
    }
    That is suppose the code was changed to only call Read_to_receive to only be called if you have new data or some time has elapsed since the last call....
    Maybe something like:
    Code:
    const uint32_t TIMEOUT_PACKET 25;  // choose some timeout value
    elapsedMillis time_since_last_packet;
    
    void loop() {
      recvWithStartEndMarkers(); //read buffer
      if (newData == true) {
        parseData();
        showParsedData();
      }
      if (newData || (time_since_last_packet > TIMEOUT_PACKET)) {
        newData = false;
        time_since_last_packet = 0;  // reset our timeout
        Read_to_Receive(); //activate transmission
      }
    }
    Warning typed on fly so could have issues. Also the elapsedMillis variable I would put up near top of file above setup and in setup I would set to 0...

    Note: If I were doing this fully for myself, I would probably change up a few more things, like: when you are receiving the data, and the data is going to exceed your array, that is signal of an error, I would probably toss all of the data I have and any else that might arrive in some time frame, and signal I want new data...

  16. #16
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    hello all,

    @paul, I took a break and revisited the non-blocking library with my test strip, long story short I accidentally didn't save my original receiving code (probably out of frustration) so I rewrote it and I am no longer having the issues.

    So here is the new receiver code:
    Code:
    #include <WS2812Serial.h>
    
    const int numled = 150;
    const int pin = 10;
    
    // Usable pins:
    //   Teensy LC:   1, 4, 5, 24
    //   Teensy 3.2:  1, 5, 8, 10, 31   (overclock to 120 MHz for pin 8)
    //   Teensy 3.5:  1, 5, 8, 10, 26, 32, 33, 48
    //   Teensy 3.6:  1, 5, 8, 10, 26, 32, 33
    //   Teensy 4.0:  1, 8, 14, 17, 20, 24, 29, 39
    
    byte drawingMemory[numled * 3];       //  3 bytes per LED
    DMAMEM byte displayMemory[numled * 12]; // 12 bytes per LED
    
    WS2812Serial leds(numled, displayMemory, drawingMemory, pin, WS2812_GRB);
    
    struct Received_Data_t {
      char startMarker;
      int rgbwArrayFromESP;
      char comma;
      int rgbwFromESP;
      char endMarker;
    };
    
    union Channel_Packet_t {
      Received_Data_t rgbwLED;
      byte ChannelPacket[sizeof(Received_Data_t)];
    };
    
    Channel_Packet_t LEDon;
    
    //RGB Sub Menu Variables
    int rgbArraySelector;
    uint8_t subRed;
    uint8_t subGreen;
    uint8_t subBlue;
    uint8_t subWhite;
    
    uint8_t rgbwArray [] = {subRed, subGreen, subBlue, subWhite};
    
    const byte numChars = sizeof(Received_Data_t);
    char receivedChars[numChars];
    
    int rgbwFromESP = 0;
    
    boolean newData = false;
    
    void setup() {
      leds.begin();
      Serial1.setRX(27);
      Serial1.setTX(26);
      Serial1.begin(115200, SERIAL_8N1);
      Serial.begin(9600);
    }
    
    void loop() {
    
      recvWithStartEndMarkers(); //read buffer
      if (newData == true) {
        parseData();
        showParsedData();
        newData = false;
      }
    
      for (int i = 0; i < leds.numPixels(); i++) {
        leds.setPixel(i, rgbwFromESP, 0, 0);
      }
      leds.show();
    }
    
    void recvWithStartEndMarkers() {
      static boolean recvInProgress = false;
      static byte ndx = 0;
      char startMarker = '<';
      char endMarker = '>';
      char rc;
      while (Serial1.available() > 0 && newData == false) {
        rc = Serial1.read();
    
        if (recvInProgress == true) {
          if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
              ndx = numChars - 1;
            }
          }
          else {
            receivedChars[ndx] = rc; // terminate the string
            recvInProgress = false;
            ndx = 0;
            newData = true;
          }
        }
    
        else if (rc == startMarker) {
          receivedChars[ndx] = rc;
          ndx++;
          recvInProgress = true;
        }
      }
    }
    
    //============
    
    void parseData() {      // split the data into its parts
      for (uint8_t k = 0; k < sizeof(Received_Data_t); k++) {
        LEDon.ChannelPacket[k] = receivedChars[k];
      }
      rgbArraySelector = LEDon.rgbwLED.rgbwArrayFromESP;
      rgbwFromESP = LEDon.rgbwLED.rgbwFromESP;
    
      rgbwArray[rgbArraySelector] = rgbwFromESP;
    }
    
    //============
    void showParsedData() {
      Serial.print("Array ");
      Serial.println(rgbArraySelector);
      Serial.print("Intensity ");
      Serial.println(rgbwFromESP);
    }
    My best guess is that I had the leds.show() inside the for loop, when I tested this it caused the program to "hang" and become unresponsive. I couldn't however replicate the flickering.

    Here is the transmitter code:
    Code:
    #include "Adafruit_LiquidCrystal.h"
    
    //teensy is expecting data <rgbwArrayToTeensy,rgbwToTeensy>
    typedef struct ESPtransmit_t {
      char startMarker;
      int rgbwArrayToTeensy;
      char comma;
      int rgbwToTeensy;
      char endMarker;
    };
    
    typedef union Channel_Packet_t {
      ESPtransmit_t rgbwLED;
      byte ChannelPacket[sizeof(ESPtransmit_t)];
    };
    
    Channel_Packet_t blueOn;
    
    Adafruit_LiquidCrystal lcd(19, 18, 5);
    
    void setup() {
      Serial.begin(9600);
      Serial2.begin(115200, SERIAL_8N1, 16, 17);
    
      while (!Serial);
      while (!Serial2);
    
      lcd.setBacklight(HIGH);
      // set up the LCD's number of rows and columns:
      lcd.begin(20, 4);
      // Print a message to the LCD.
      lcd.print("hello, world!");
    
      lcd.setCursor(0, 1);
      lcd.print("Array: ");
      lcd.print(2);
      lcd.setCursor(0, 2);
      lcd.print("Colour: ");
      lcd.setCursor(8, 2);
      lcd.print("    ");
      lcd.setCursor(8, 2);
      lcd.print(0);
    }
    
    void loop() {
      for (int x = 0; x < 125; x++) {
        blueOn.rgbwLED = {'<', 2, ',', x, '>'};
        Serial2.write(blueOn.ChannelPacket, sizeof(ESPtransmit_t));
        lcd.setCursor(8, 2);
        lcd.print("    ");
        lcd.setCursor(8, 2);
        lcd.print(x);
        //delay to simulate approx. artnet signal output rate
        delay(22);
      }
    }
    I also have code that uses a rotary encoder to add some user input, it also works well at the moment,
    Code:
    #include <Rotary.h>
    #include "Adafruit_LiquidCrystal.h"
    
    int previousArray;
    int previousRGBW;
    
    #define inPinA  35
    
    //rotary acceleration variables
    int rotaryTime;
    volatile int counterA;
    byte enableAcceleration;
    bool lockFlag = false;
    
    Rotary rotaryA = Rotary(32, 33);
    
    //teensy is expecting data <rgbwArrayToTeensy,rgbwToTeensy>
    typedef struct ESPtransmit_t {
      char startMarker;
      int rgbwArrayToTeensy;
      char comma;
      int rgbwToTeensy;
      char endMarker;
    };
    
    typedef union Channel_Packet_t {
      ESPtransmit_t rgbwLED;
      byte ChannelPacket[sizeof(ESPtransmit_t)];
    };
    
    Channel_Packet_t blueOn;
    
    Adafruit_LiquidCrystal lcd(19, 18, 5);
    
    void setup() {
      Serial.begin(9600);
      Serial2.begin(115200, SERIAL_8N1, 16, 17);
    
      while (!Serial);
      while (!Serial2);
    
      attachInterrupt(digitalPinToInterrupt(32), rotateA, CHANGE);
      attachInterrupt(digitalPinToInterrupt(33), rotateA, CHANGE);
    
      lcd.setBacklight(HIGH);
      // set up the LCD's number of rows and columns:
      lcd.begin(20, 4);
      // Print a message to the LCD.
      lcd.print("hello, world!");
    
      lcd.setCursor(0, 1);
      lcd.print("Array: ");
      lcd.print(2);
      lcd.setCursor(0, 2);
      lcd.print("Colour: ");
      lcd.setCursor(8, 2);
      lcd.print("    ");
      lcd.setCursor(8, 2);
      lcd.print(0);
    }
    
    void loop() {
      blueOn.rgbwLED = {'<', 2, ',', counterA, '>'};
      if (previousRGBW != blueOn.rgbwLED.rgbwToTeensy) {
        Serial2.write(blueOn.ChannelPacket, sizeof(ESPtransmit_t));
        lcd.setCursor(8, 2);
        lcd.print("    ");
        lcd.setCursor(8, 2);
        lcd.print(counterA);
        previousRGBW = blueOn.rgbwLED.rgbwToTeensy;
      }
    }
    
    void rotateA() {
      int speedMultiplier = 1;
      unsigned char result = rotaryA.process();
      if (lockFlag == false) {
        if (result == DIR_CW) {
          if (millis() - rotaryTime <= 10 && enableAcceleration == 0x01) {
            speedMultiplier = 7;
    
          }
          else if (digitalRead(inPinA) == HIGH) {
            speedMultiplier = 700;
          }
          counterA += speedMultiplier;
          rotaryTime = millis();
        }
        else if (result == DIR_CCW) {
          if (millis() - rotaryTime <= 10 && enableAcceleration == 0x01) {
            speedMultiplier = 7;
    
          }
          else if (digitalRead(inPinA) == HIGH) {
            speedMultiplier = 700;
          }
          counterA -= speedMultiplier;
          rotaryTime = millis();
        }
      }
    }
    Fresh eyes and a clear head prevail I guess.

  17. #17
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    21,302
    Glad it worked out well in the end.

    If you do encounter the problem again, please save a test case. I definitely want to investigate.

  18. #18
    Junior Member
    Join Date
    Dec 2019
    Posts
    8
    Now that the code is working I found an RGBW fork of the WS2812 Serial Library and I've started to modify it to work with my TM1814 LEDs.
    The last thing I need to do is adjust the timings, Crees you mentioned you were trying to adjust the timings for the 1 and 0 bit, how were you doing that?

    the TM1814 requires 360nS for 0 and 720nS for 1 and a total time on 1.25microSeconds per bit.
    What are the variables that need to be adjusted in the DMA Serial Code?
    from previous experience I think it would 0x07 or 0xE0 but I can't be sure.
    Code:
    do {
    			uint8_t x = 0x08;
    			if (config == TM1814_RGBW) {
    				if (!(n & 0x0080000000)) x |= 0x07;
    				if (!(n & 0x0040000000)) x |= 0xE0;
    			} else{
    				if (!(n & 0x00800000)) x |= 0x07;
    				if (!(n & 0x00400000)) x |= 0xE0;
    			}
    			n <<= 2;
    			*fb++ = x;
    		} while (fb < stop);
    	}
    	// wait 300us WS2812 reset time
    	uint32_t min_elapsed = (numled * 30) + 300;
    	if (min_elapsed < 2500) min_elapsed = 2500;
    	uint32_t m;
    	while (1) {
    		m = micros();
    		if ((m - prior_micros) > min_elapsed) break;
    		yield();
    I'v attached the modified header and cpp files, any ideas?
    WS2812Serial.cppWS2812Serial.h

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •