Particle Serial Interrupt

Has anyone deciphered a good way of reliably getting serial data into a Particle, without missing any data? I’m aware of the issues around the lack of a serial interrupt. Perhaps a register level solution or some additional hardware?

Thanks

There are a few things you can do to help:

  • Make sure you don’t have anything that blocks in loop
  • Make sure you handle all available serial data on every call to loop, not just one byte
  • On the Electron, make sure you use SYSTEM_THREAD(ENABLED) otherwise loop is only called 100 times per second vs. 1000 on the Photon or in threaded mode.
  • Don’t use the serialEvent. It’s just dispatched between calls to loop and isn’t helpful here.

However, if you can’t prevent loop from blocking, the next best thing is to use a thread. As long as you do all of the serial reads from that thread, it’s safe to do so. One of the easiest and safest things to do is allocate a much larger buffer, and use an interrupt-safe ring buffer to read from serial and write to the ring buffer from the thread, and read from the ring buffer instead of the actual port from loop. I’ve used a 2K ring buffer vs. the 64-byte hardware FIFO and it works great.

3 Likes

I published a library to do that. It’s a thread-based serial port buffer. You can choose the size of the buffer and read from it using the same methods you’d normally use for the hardware serial port.

With a 4K buffer I was able to send data to a Photon continuously at 230400 without dropping a single byte.

11 Likes

It’s been running for a while. 200 MB received so far at 230400 baud, no incorrect bytes.

0008669900 [app] INFO: numReceived=115385 maxInBuffer=24 totalReceived=199823581
0008674900 [app] INFO: numReceived=115385 maxInBuffer=31 totalReceived=199938966
0008679900 [app] INFO: numReceived=115385 maxInBuffer=29 totalReceived=200054351
0008684900 [app] INFO: numReceived=115385 maxInBuffer=27 totalReceived=200169736
0008689900 [app] INFO: numReceived=115385 maxInBuffer=24 totalReceived=200285121

Left column is the runtime in milliseconds. numReceived is the number of bytes received in a 5 second period. That’s constant so I know the sender is keeping the serial pumping at full speed. maxInBuffer is the maximum number of bytes buffered on a call to loop. In this test, the receiver is just sitting there idle (but cloud connected) so the max isn’t high. However with only a 64-byte buffer you have so little margin for error before losing data that buffering is basically a necessity at 230400.

1 Like

That’s quite impressive! Thanks for the heads up. I’ll certainly give this a go. The background is that I’m writing a SIA parser for a Texecom alarm panel (they’re very popular in the UK). I’ve had OK success in the past but it did drop the odd Serial message.

I’m sorry if this is a stupid idea, but would it not be possible to connect the rx line in parallel with another pin on the Particle, and have that serve an interrupt? It could be set to ‘on change’ so that it picks up either a high or low signal.

@joearkay, @ScruffR created the ParticleSoftSerial library that implements the serial protocol using bit-banging and interrupts. Problems is, at higher baudrates, the interrupts overwhelm the processor or are simply preempted by the DeviceOS. This limits the top baudrate to 38.4Kbaud at best. Short of modifying the DeviceOS code, Rick’s approach provides the best queuing mechanism for serial data.

4 Likes

I’ve integrated this library into a serial gateway we’re testing… so far it’s flawless. Thanks Rick for implementing this great addition for the dev community!

:thumbsup:

1 Like

Awesome - I definitely need to give this a go!

I love this library.

As a feature suggestion, what do you think of adding begin()? That way the library is a (almost) drop in replacement for existing serial port code, which means that in the future, when DMA’d serial port to a resizeable buffer is completely integrated into the OS, there will be very little code to change.

I’ve imported this library into my project but I get an error
thingsboard-aqua.cpp:7:28: SerialBufferRK.h: No such file or directory.

My dashboard shows that I’ve got this library included, and this comment was added by the IDE
#include “SerialBufferRK.h”

Any ideas anyone?