Xenon - UART and Performance

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

I have not used the synchronization output as I recall the sensor’s technical support saying something about not using it.

As to the analog out, they also recommended I not use the analog output due to some problems I had (with a PC though).

I will get a Photon and test with it and report.

Thanks again.

Also, if you set the device to 200 samples/sec, each sample will be presented at 5ms intervals. At 115Kbaud, two contiguous bytes will take about 200us to transmit, leaving you with a 4800us interval between values. @bko can check me here but if you synchronized the “start of data” once, then every two bytes in the receive buffer will represent a new value. Unless you overflow the receive buffer, this will hold true forever unless the sensor is powered off or goes to a non-transmitting state. It just seems to me your approach here is incorrect as @bko pointed out.

2 Likes

OK, I have done a new test where everything is the same and EXACT code (below), breadboard and all.

With a Photon, Laser Frequency: 500 Hz.

With a Xenon, Laser Frequency: 15 Hz.

This is also confirmed by the lethargic distance change when I aim the sensor at different objects with the Xenon. With the Photon, the distance change is displayed immediately …

It is clear something is wrong. Could it be related to the Mesh?

SYSTEM_THREAD(ENABLED);

//=======================================================================================================
String verNum = "1.00";
//=======================================================================================================
#include <Adafruit_SSD1306.h>
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_RESET);

//=======================================================================================================
int strength;
int distance;
int distanceFT;

int len;
char buf[60];

int myCase = 0;

int hertz = 0;
//=======================================================================================================

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

for (int i=0; i <= 1000; i++){
      readLightware();
      delay(1);
   }
 
   end = millis();
   hertz = 1000 / ((end - start) / 1000) ;
   
   
  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() {
  readLightware();
  showResults();
  delay(1);
}


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

void showResults()
{
  display.clearDisplay();
  display.setCursor(0, 0);
  display.println("Dist ");
  display.setCursor(60, 0);
  display.println(distance);
  display.setCursor(0, 40);
  display.println("Freq ");
  display.setCursor(60, 40);
  //display.println(myLight);
  display.println(hertz);
  display.display();


  delay(1);
}

//===============================================================================================================
//Laser
//===============================================================================================================
void readLightware()
{
  //while (LightW.available() < 2);
  while (Serial1.available())
    //if (LightW.available() > 2);

    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!
  distanceFT = distance * 0.033;
  //---------------------------------------------
}

SF_Photon|375x500

Hello @bko:

I realize that code working on one micro may not work on another however I am not sure why you say above that it is not desirable? I am not a computer scientist, but it would seem to me that using a relatively accurate internal timer should work. It has worked before on an Arduino UNO, Due, Photon and Electron. If it is not working on a Xenon, it would seem to be a fault of that architecture?

Also, even if what you are saying is correct, this should give wrong distance results if the bytes are misread, but should not affect the read frequency.

I wish to thank @bko, @peekay123 and @ninjatill for taking the time to help and the advice they gave.

I had also changed the code to test @bko point about the code being inefficient, and sure enough, when the byte ordering code was taken out, it appears that the Xenon UART worked fine.

I am still not convinced that code that works on an UNO, DUE, Teensy, Photon and ESP32 would not work on a Xenon but have decided to just use another sensor.

1 Like