Serial Tutorial

ISSUE SOLVED!

TL;DR
There’s an interesting interaction between pySerial (and possibly other serial interface implementations) and the Photon’s USB serial port that means flow control is effectively always on. If your read rate is limited by the frequency of your loop() function, then it can look like a low-baud serial link when it’s actually a firmware bug.

Long Version

OK all who are interested, here’s the deal. There are a few factors at play here, which combine together to give some really strange false-positive results when testing:

  1. I don’t know about other interfaces, but when interfacing to pySerial, regardless of the flow control settings, the python code will block if the 128 byte RX buffer on the photon is full until the photon has cleared some of that data out. Occasionally the code will timeout, but I haven’t been able to find rhyme or reason on that one. Therefore at the Python end, it appears as if there’s a local TX buffer that’s being overfilled because the pipeline size isn’t sufficient for the data you’re trying to send.
  2. As mentioned by Scruff, the SerialEvent() “callback” does not behave like a traditional ISR. I was expecting it to be called repeatedly while there was serial data to be processed. Instead, it will be called only once at the end of loop() if there is serial data in the RX buffer.
  3. One wierd result of this - If your loop() function has a 10 mSec delay in it, and your SerialEvent() handler is only reading one byte at a time, you get an apparent data rate of 100 bytes/second regardless of the baud rate setting of the serial link.

It was an issue in my Photon firmware, nothing to do with the Python or Win10 issues I had been chasing for a while. Here’s the summarry:

BROKEN CODE:

void loop(void){
  // Do some assorted data processing.
  MySerialHandler.processData(); // Process any data in my buffer as appropriate
  delay(10); // I want a roughly 100 Hz core loop
}

// Because loop() is only running at 100Hz, this will get called at a _FASTEST_ speed of 100 Hz
SerialEvent(void)
{
  mySerialHandler.RXData(Serial.read());
}

WORKING CODE:

void loop(void){
  // Do some assorted data processing.
  while(Serial.available())  // Make sure I'm reading out ALL the available data
    mySerialHandler.RXData(Serial.read());
  MySerialHandler.processData(); // Process any data in my buffer as appropriate
  delay(10); // I want a roughly 100 Hz core loop
}

I now have the capability to push ~20 byte packets to the photon at about 100 Hz. Not a crazy-high-rate test, but sustained for 20 minutes seems to be stable.

Thanks as always for your help @ScruffR!

1 Like