Go Down

Topic: Serial.readBytes exceeds 500ms (Read 222 times) previous topic - next topic

DarkEyeDragon

Dec 14, 2018, 10:18 pm Last Edit: Dec 14, 2018, 10:22 pm by DarkEyeDragon
Hello everyone! I hope this is the right section.

So I made an app in C# which sends serial data to my arduino.
The arduino then processes the bytes to control 84 LED's

The way i currently send my data is the following: 3 bytes with values between 0-255 in a continues datastream. So after one cycle the arduino has processed 252 bytes. However it's taking over 400ms to do this. So now my question is: How do i make it not exceed 100ms?

What I tried so far: Increase the baud rate, however this didn't seem to be a bottleneck.
Decrease the timeout. This seems to improve it a bit but no noticable impact

Debugged: timed how low each step takes.

Conclusion: without serial.readBytes it can complete the cycle in 2-3ms.

Code: [Select]

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif
#define PIN 6

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
//   NEO_RGBW    Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(84, PIN, NEO_GRB + NEO_KHZ800);

byte colors[3];
unsigned long startTime;
unsigned long endTime;
String divider = "/";
void setup() {
  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
  Serial.begin(115200);
  Serial.setTimeout(500);
}
void loop() {
    if(Serial.available() >= 3){
      startTime = millis();
      for(int i=0; i < strip.numPixels(); i++) {
        //strip.setPixelColor(i, colors[0], colors[1], colors[2]);
        Serial.readBytes(colors, 3);
        strip.setPixelColor(i, colors[0], colors[1], colors[2]);
      }
      strip.show();
      endTime = millis();
      Serial.println(endTime-startTime+divider+Serial.available());
    }
}


AWOL

"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

DarkEyeDragon

What about it? I tried 200, i tried 100, i tried 20, i tried 4, nothing seems to really matter

AWOL

#3
Dec 14, 2018, 11:07 pm Last Edit: Dec 14, 2018, 11:09 pm by AWOL
Quote
So I made an app in C# which sends serial data to my arduino.
We also  seem to be missing a major part of the puzzle.

Why show for every three bytes?
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

DarkEyeDragon

#4
Dec 14, 2018, 11:17 pm Last Edit: Dec 14, 2018, 11:19 pm by DarkEyeDragon
We also  seem to be missing a major part of the puzzle.

Why show for every three bytes?
https://github.com/DarkEyeDragon/LED_Controller/tree/master/LED_Controller
this is the (crappy) source in case that helps.

I take a screenshot every ms and process pixels out of it. Pretty much like an ambient light. The sending itself doesnt seem to take long at all. It's just the reading thats very slow on the arduino.

The 3 bytes are basically just RGB, 1 byte Red, 1byte Green, 1byte Blue

AWOL

Quote
It's just the reading thats very slow on the arduino.
No, I don't think so.
252 bytes at 115200 takes a shade under 22 milliseconds by my arithmetic.
"Pete, it's a fool (who) looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.
I speak for myself, not Arduino.

Robin2

Don't use Serial.readbytes()

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

DarkEyeDragon

Seems promising. Just kind of disappointing how poorly the readBytes method was designed. And outlives its usefulness for anything more than reading a few bytes :/

cattledog

Quote
Just kind of disappointing how poorly the readBytes method was designed
Here's the source code for readBytes(). What's so poorly designed?.

Code: [Select]
size_t Stream::readBytes(char *buffer, size_t length)
{
  size_t count = 0;
  while (count < length) {
    int c = timedRead();
    if (c < 0) break;
    *buffer++ = (char)c;
    count++;
  }

  int Stream::timedRead()
{
  int c;
  _startMillis = millis();
  do {
    c = read();
    if (c >= 0) return c;
  } while(millis() - _startMillis < _timeout);
  return -1;     // -1 indicates timeout
}
  return count;
}


My guess is that the 500 ms problems are on the sending end or in the neopixel commands .


DarkEyeDragon

They're not though. As i said multiple times before, everything except the readBytes runs within a few ms, that includes setting the LED's to a color. I even tried using another lib before i realised it was the readBytes

cattledog

Quote
before i realised it was the readBytes
I can not confirm your findings. When I send 99 bytes, they are read in 8 ms. Any time the are not a multiple of 3 bytes sent, the default time out of 500 ms kicks in. Send 98 bytes reading time is 508 ms. Send 95 bytes and the reading time is 1008 ms. If three bytes are not available to read in your for() loop you run into a time out. You could be using an if() conditional instead of the for() loop.

Code: [Select]

//enter into serial monitor and send with no line ending
//123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
//99 bytes

byte colors[3];
unsigned long startTime;
unsigned long endTime;

void setup() {
  Serial.begin(115200);
  Serial.setTimeout(500);
}

void loop() {
  if (Serial.available() >= 3) {
    startTime = millis();
    for (int i = 0; i < 33; i++) {
      Serial.readBytes(colors, 3);
    }
    endTime = millis();
    Serial.println(endTime - startTime);
  }
}

Go Up