Reproducible Freeze: WS2812Serial freezes teensy 4 when printing serial

Status
Not open for further replies.

fruitman

Member
I'm running into a problem with my Teensy 4.0. Attached is the code. It looks like it has to do with WS2812Serial specifically when it prints something to another serial port right before changing color. The print right before the color change doesn't work, but more importantly, some time later in the code, the teensy freezes in the middle of printing a line of serial.

My output:
Debug Serial Started
State: First recov finish
Starting char block
Timeout: bloc
[Above is not a mistake, it cuts off there and freezes]

Expected output:
Debug Serial Started
State: First recov finish
Starting char block
Timeout: block_until_char_timeout
State: End fail

Setup:
Teensy 4
Serial Keyboard Mouse Joystick 600Mhz Faster USenglish
Neopixels connected to pin 1
Serial monitor connected to pin 8 (Serial2) and common ground (no serial2 rx connected)

Code (do CTRL-F and look for PJRC for my comments about this):
Code:
#include <Arduino.h>
#include <WS2812Serial.h>

//START CONFIGS

// START User defined variables
#define NUM_LEDS 7
#define LED_DATA_PIN 1
#define LOGGING_ON true
#define DEBUGSERIAL Serial2
// END User defined variables

// START LED CONFIG
const int numled = NUM_LEDS;
const int pin = LED_DATA_PIN; // Usable pins: 1, 5, 10, 31
byte drawingMemory[numled*3]; 
DMAMEM byte displayMemory[numled*12]; 
WS2812Serial leds(numled, displayMemory, drawingMemory, pin, WS2812_GRB);
#define RED    0x160000
#define GREEN  0x001600
#define BLUE   0x000016
#define WHITE  0x101010
// END LED CONFIGS

// START OTHER CONFIGS
#define FIRST_RECOV_FINISH 2
#define END_FAIL 8
uint8_t MAIN_STATE = FIRST_RECOV_FINISH;
// END OTHER CONFIGS

// END CONFIGS
// START FUNCTIONS

// Log to the non-usb serial port
void logg(String text)
{
  if(LOGGING_ON)
    DEBUGSERIAL.println(text);
}

// Color some number of LEDS on edge, or middle only
void color_specific(int color, int howmany)
{
  if(howmany == 0) // if we want to light the middle
  {
    logg("Setting LED center to " + color);
    leds.setPixel(0, color);
  }
  for (int i=0; i < howmany && i < numled-1; i++) // if we want to light the edge
  {
    logg("Setting LED edge to " + color);
    leds.setPixel(i+1, color);
  }
  delay(20);
  leds.show();
}

// Block until serial receives a char and then return it, or timeout and return -
char block_until_char(unsigned long secs)
{
  logg("Starting char block");
  elapsedMillis waiting;
  bool forever = false;
  if(secs == 0) // no timeout
    forever = true;
  while (forever || waiting < secs * (unsigned long)1000)
  {
    if (Serial.available())
    {
      delay(50); // wait for rest of serial data to come in
      char got = Serial.peek();
      while (Serial.read() >= 0) // throw away the rest
        ;
      logg("returned char is " + String(got));
      return got;
    }
  }
  logg("Timeout: block_until_char_timeout"); // PJRC TEENSY CRASHES HERE
  return '-';
}

// Setup the LED library and light up one pixel
void setup_lights()
{
  leds.begin();
  leds.clear();
  leds.setPixel(0, BLUE);
  leds.show();
}


// END FUNCTIONS
// START MAIN

void setup() 
{
  Serial.begin(115200);
  if(LOGGING_ON)
  {
    DEBUGSERIAL.begin(9600);
    DEBUGSERIAL.println("Debug Serial Started");
  }
  setup_lights();
}

void loop() 
{
  switch (MAIN_STATE)
  {

  case FIRST_RECOV_FINISH:
  {
    logg("State: First recov finish");
    char c = block_until_char(3);
    MAIN_STATE = END_FAIL;
  }
    break;

  case END_FAIL: // PJRC because of the bug, it never comes here
  {
    logg("State: End fail");
    color_specific(RED, numled);
    color_specific(RED, 0);
    delay(5 * 1000);
  }
    break;

  default:
  {
    logg("State: Unknown State");
    delay(5 * 1000);
  }
    break;
  }
}

// END MAIN
 
I'm running into a problem with my Teensy 4.0. Attached is the code. It looks like it has to do with WS2812Serial specifically when it prints something to another serial port right before changing color. The print right before the color change doesn't work, but more importantly, some time later in the code, the teensy freezes in the middle of printing a line of serial.

I've seen a similar case before when I was testing the T4 WS2812Serial library when it was first implemented for the T4. In my case, I was being lazy and using a 16 LED ring (from Adafruit) and powering it with 3.3v. When it got to displaying white, it would hang. Ultimately, I concluded that it was just drawing to much power. When I wired the WS2812 leds correctly (i.e. using VIN instead of 3.3v, and using a 74AHCT125 level shifter to convert the data signal from 3.3v to 5v), it worked fine.

The output is interrupted because the Teensy puts the characters to be output in a temporary buffer, and sends the next character after the previous character had been written out (i.e. doing a println does not wait for the characters to be output before returning), and if the voltage regulator suddenly shuts down, you won't see the final characters (unless you use a delay or do a busy loop while polling to see if the characters are still in the buffer).
 
I've seen a similar case before when I was testing the T4 WS2812Serial library when it was first implemented for the T4. In my case, I was being lazy and using a 16 LED ring (from Adafruit) and powering it with 3.3v. When it got to displaying white, it would hang. Ultimately, I concluded that it was just drawing to much power. When I wired the WS2812 leds correctly (i.e. using VIN instead of 3.3v, and using a 74AHCT125 level shifter to convert the data signal from 3.3v to 5v), it worked fine.

The output is interrupted because the Teensy puts the characters to be output in a temporary buffer, and sends the next character after the previous character had been written out (i.e. doing a println does not wait for the characters to be output before returning), and if the voltage regulator suddenly shuts down, you won't see the final characters (unless you use a delay or do a busy loop while polling to see if the characters are still in the buffer).

Hmm but I thought separate serial ports shouldn't share the same buffer. I don't think it's about too much power because I'm only lighting one LED. Anyway, I wonder if someone can test with a level shifter because I don't have one.
 
Hmm but I thought separate serial ports shouldn't share the same buffer. I don't think it's about too much power because I'm only lighting one LED. Anyway, I wonder if someone can test with a level shifter because I don't have one.

What I meant is as I understand it, when you do a Serial<x>.print or Serial<x>.println, it copies all of the bytes to an internal buffer (each Serial UART + Serial USB has its own buffer). The first character is then started to print (sending the bits down the UART or USB line one bit at a time), when a character is finished, the interrupt handler then sends the next character to be printed. Thus if you immediately call the show function, and it causes the machine to halt because it ran out of power, there might be characters in the internal buffer that haven't printed yet. If you do a largish delay before calling show and after calling println, it is likely all characters will be printed.

And your script has 7 LEDs in it, not one. When you turn on white, it turns on all 3 LEDs. Now, in theory the Teensy should be able to handle 21 LEDS (NUM_LEDS * 3) all set to 0x10.
 
Status
Not open for further replies.
Back
Top