Xenon - UART and Performance

I have an old sketch which connects to a sensor that is updating at 200Hz.

The sketch runs really fast on a Photon (150 Hz even soft serial), and blazing fast on an ESP32 but is only doing 13 Hz on a Xenon (almost 10 times slower).

I was wondering if the community had a chance to test the speed of the Xenon’s UART?

1 Like

@Jimmie, can you post your code?

1 Like

Hello @peekay123

Sure, here it is:

//=======================================================================================================
String verNum = "1.00";
//=======================================================================================================
// This #include statement was automatically added by the Particle IDE.
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);
//=======================================================================================================
int strength;
int distance;

int myCase = 0;
//=======================================================================================================

void setup() {
  //=================================================================
  Serial1.begin(115200);      //on SoftSerial - Sensor cannot support any faster than baud 38400
  delay(2000);
   //=================================================================   
long start = millis();
long end;

for (int i=0; i <= 100; i++){
      readLaser();
      delay(1);
   }
 
   end = millis();
   int hertz = 1000 / ((end - start) / 100) ;
   
   
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64)

    display.clearDisplay();   // clears the screen and buffer
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0, 0);
    display.println("Trigger");
    display.setCursor(0, 25);
    //display.println("Ver. " + verNum);
    display.println(hertz);
    display.setCursor(0, 50);
    display.println("Jimmie");
    display.display();
    delay(5000);
 }

void loop() {

//------------------------------
  readLaser();
  showResults();
  delay(10);
//------------------------------ 
}


//===============================================================================================================

void showResults()
{
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Dist");
  display.setCursor(60, 0);
  display.println(distance);
  display.setCursor(0, 40);
  display.println("Case");
  display.setCursor(60, 40);
  display.println(myCase);
  display.display();
}

//===============================================================================================================
//Laser
//===============================================================================================================
void readLaser()
{
  while (Serial1.available())

    Serial1.read();

  while (Serial1.available() == 0);
  unsigned long t0 = micros();
  while (Serial1.available() == 1);
  unsigned long t1 = micros();
  while (Serial1.available() == 2);
  unsigned long t2 = micros();

  int byte0 = Serial1.read();
  int byte1 = Serial1.read();
  int byte2 = Serial1.read();

  float distanceM = 0.0;

  if ((t1 - t0) < (t2 - t1))
  {
    distanceM = byte1 + byte0 / 256.0;
    myCase = 0;
  }
  else
  {
    distanceM = byte2 + byte1 / 256.0;
    myCase = 1;
  }
  
  //Serial1.flush();
  //---------------------------------------------
  distance = distanceM * 100;   //convert to cm
  //---------------------------------------------
}

It does not necessarily follow that serial is the problem–it could be that the i2c display is slower.

What happens if you comment out the display code and just blink the LED or something similar?

2 Likes

The display is not used to calculate the frequency in setup(). It just displays the result (hertz).

for (int i=0; i <= 100; i++){
      readLaser();
      delay(1);
   }

end = millis();
int hertz = 1000 / ((end - start) / 100) ;

OK I see what you mean now–you are measuring the speed in setup in a non-functional loop. I believe that the serial data buffer is larger on Xenon’s as compared to Photon/Electron so that could have some impact, but I’m not sure why you are getting the results you are seeing. Maybe you are processing more bytes in your readLaser while loop than you think you are. Can you count the total bytes read in both cases and report that too?

By the way, I would not do the integer divide you are doing above to get hertz–why not work in floats or doubles once you have the end-start time as you do below?

2 Likes

Hello @bko

I can do that but this is the same EXACT code I used on an ESP32. I also used that code on a Photon but that was a while ago so may be worth repeating.

Thank you on the programming advice. I was doing that to avoid formatting the result to fit the screen.

Another reason is that more powerful processors (coupled of a lack of good C knowledge) makes one complacent :-). Will follow your advice.

Nothing in your code prevents the readLaser function from reading more than one set of measurements since you have that while loop there. You could be reading two or more serial port measurements for every value returned through the global and you would never know. If you count bytes, you will know the bandwidth for sure.

2 Likes

OK, I will check again.

I just did another test (back on the ESP32). I increased the sensor frequency to 300 Hz. The ESP32 still managed to get > 200 Hz.

I hope someone can test the Xenon with a fast serial sensor to get an independent result of its UART’s performance and to rule out my specific sensor. DHT11s are not an good evaluation …

1 Like

You can use one controller to push the data with defined pace and see how long the Xenon can keep up. That’s not anything you need anybody else to test this for you.

2 Likes

@rickkas7 wrote a program to test his serial port buffer. The examples/test in the library should help you test the speed. Check this post:

@Scruffr:

Thank you for helping me multiple times in the past, but if you read what I had written carefully, you would have seen that I am not asking anyone to “…test this for me”.

Per my post, I have tested this issue with 2 different micros so I am out of options.

I am asking a rather simple question: Has Particle tested this UART with a fast serial sensor?

Thank you @ninjatill. Will try this too.

@Jimmie, I would like to emulate this sensor on a Photon and have the Xenon “read” the data. Which sensor are you using? What is the data from the sensor look like? If I understand correctly the sensor simply pushes its data at 200Hz as a steady stream. The first thing done in readLaser is to purge the receive buffer. Then the software waits for the buffer to contain 3 bytes, reads them, calculates values and returns. So the code ignores any buffering essentially. What “typical” data do byte0 to byte 2 contain? Does the sensor have a “start” byte to indicate a new value?

2 Likes

This does not validate the data, but I can receive about 11200 bytes per second at 115200 baud on the Xenon.

0000010000 [app] INFO: 109726 bytes received in 10 seconds
0000020002 [app] INFO: 115188 bytes received in 10 seconds

This is the receiver:

#include "Particle.h"

SerialLogHandler logHandler;

SYSTEM_THREAD(ENABLED);

size_t seq = 0;
unsigned long lastReport = 0;
size_t lastCount = 0;

void setup() {
	Serial1.begin(115200);
}

void loop() {
	while(true) {
		int c = Serial1.read();
		if (c < 0) {
			break;
		}
		seq++;
	}

	if (millis() - lastReport >= 10000) {

		Log.info("%lu bytes received in 10 seconds", seq - lastCount);

		lastReport = millis();
		lastCount = seq;
	}

}

This is the transmitter (a Photon):

#include "Particle.h"

SerialLogHandler logHandler;

size_t seq = 0;

void setup() {
	Serial1.begin(115200);
}

void loop() {
	while(Serial1.availableForWrite() > 10) {
		int c = rand() % 255;
		Serial1.write(c);
		seq++;
	}
}
5 Likes

Hello @peekay123,

Thank you. The reason for my puzzlement is because I am using the same sensor with a Photon. That Photon reads 150 readings from the sensor per second. The same reading routine is used but within a much larger application. I could not test the simple code with the Photon I have because they are in sealed enclosures and it would be a big hassle to get to.

The sensor is a laser distance sensor. Its frequency is configurable and can be much higher than 200 Hz but that I was I am using. The sensor is this:

https://acroname.com/products/r367-sf30-b?sku=R367-SF30-B

The distance is output as 2 bytes. You noted correctly the shortcoming of the sensor I have, namely that the stream has no start string, hence reading the byte millis() times to figure out he first byte. The sensor company has addressed this problem in their new sensors.

That is good since the absolute maximum rate at 115kbaud is 11,520 bytes/sec!

3 Likes

Hello @rickkas7. Thank you for taking the time to do the test. I am not sure what the problem is but I am considering taking one of my Photons out of its enclosure and testing it since I know that with a Photon, I do get much faster readings.

I think what the discussion here is telling you is that your code is not really doing what you expect. The fact that it works OK for you on Photon is pretty irreverent. You seem to be trying to use the microsecond timer and the number of bytes buffered to tell where you are in the stream, but I don't see that as being desirable or robust.

2 Likes

@Jimmie, it seems the sensor uses a “sychronization” output to indicate when a measurement is made and thus can be used to synchronize the serial data. Have you considered using the analog output of the sensor which could be sampled at a much higher rate than the serial can? In either case, have you considered using the synchronization output?

image

3 Likes