Serial overruns with ChipworkX

I get a System.ArgumentException when I try this on the G400 board installed in the same custom board as the ChipworkX module was used in.

@ Dave McLaughlin -

Hi Dave, I can contribute with our experiences on this topic:

We had the same issue with ChipworkX communicating with a GSM module over COM3 (which in the documentation of ChipworkX should have the vital handshake required for all GSM modems I know of). But unfortunately we found out that handshake was not implemented for COM3 - so the two CTS and RTS pins are there hardware wise, they are just not working.

If you try and run the following code on ChipworkX, you will see they are not implemented:

HardwareProvider hwProvider = HardwareProvider.HwProvider;
Cpu.Pin rxPin = Cpu.Pin.GPIO_NONE;
Cpu.Pin txPin = Cpu.Pin.GPIO_NONE;
Cpu.Pin CTSPin = Cpu.Pin.GPIO_NONE;
Cpu.Pin RTSPin = Cpu.Pin.GPIO_NONE;
hwProvider.GetSerialPins("COM3", out rxPin, out txPin, out CTSPin, out RTSPin);

Anyways, using AT-commands at baud 19200 on the serial connection works for us most of the time (making small webservice calls, sms, etc). However, if we needed to download a file larger than 5KB, the problem of having no handshake occured (overrun resulting in missing bytes).

Our solution was to alter the implementation of the webservice on our server that hosts the files to support grabbing files in chunks of 5KB. A tedious implementation, but our solution worked and now works well in production as well. It uses a bit more bandwidth because it makes a webservice call for each 5KB chunk, but at least it works.

Thanks MD. I am sure the serial port issue is related to the driver within the ChipworkX firmware as I have a G120 based design talking to a SIM900 modem at 115200 bps, with no handshaking and there is absolutely no overruns on that. I have 2 other serial ports also running along with about 5 other threads.

Even if I cutdown the ChipworkX code and only have the modem I still get serial overruns on it. These are not due to a buffer overrun as the buffer is big enough and I empty it long before it gets filled up. The overruns are when the UART receive register is not read fast enough before the next byte arrives. This is part of the native UART handling, I am almost positive on this.

I too hope the G400 fixes these issue but I am unable to currently test this because I canā€™t run it with PPP so therefore I have no fast data to test with. Normal AT commands seem to be fine.

Yes that sounds very plausible indeed (especially since you have it working on G120 with no handshake as well). But yes, lets cross fingers that G400 doesnā€™t have the same issue - we havenā€™t gotten around to test the SIM900 modem on G400 yet.

I have now had the chance to test a SIM900 modem running at 19200 with the G400 (at the moment on COM2) and unfortunately it seems to also suffer from the serial overrun that the ChipworkX do (same code works fine when using the Spider).

So the errors I am seeing is for example periodic missing characters when reading a reply from the modem using the serial connection (after sending normal AT commands). This could be:

STATE: IP STRT instead of STATE: IP START

or just K instead of OK

So Dave, it doesnā€™t look like we are that lucky that the issue is fixed on the G400.

We will look into G400

@ Gus. That would be good. I have been tied up with another project and not had time to look at the G400 again. I am still waiting for a more stable firmware for it anyway. There are still issues listed.

By the way, the overruns, as I have said many time before are not BUFFER overruns, but overruns to the receive register. For some reason the ChipworkX and now the G400 is not processing the interrupt handler from the serial ports fast enough before the next character arrives. This I think is where you need to look at the issue. :slight_smile:

We looked into the issue and there is no hardware FIFO buffer. There is a single register that we read the character from. As you said, @ Dave, the ISR isnā€™t finishing quick enough so itā€™s getting overrun. There is DMA functionality, but it is a major change that will not make it into the next SDK. It will be added in the future.

My serial code was missing chunks of data and I traced it back to a bug in the 4.2 StringBuilder.ToString(int,int). The gadgeteer LineReceived Event Handler uses Stringbuilder to store lines from the serial port. In certain cases StringBuilder returns a truncated string.
Iā€™m not sure if this is your problem. I wrote a slightly more efficient, bug-free version of LineReceived and my cobra II is much happier.

Would be nice if you can share it on the codeshare.

This seems very unusual John as I have used much slower processors without a FIFO and been able to run at 115200 without any issues. I did this on a Netburner module with 3 serial ports and not lost characters.

I can only assume that the interrupt handler for the USARTS is not fast enough.

I just updated ā€œSerialBridge - TCP to RS232 bridgeā€ with the new code https://www.ghielectronics.com/community/codeshare/entry/748

The improved LineReceived code is the serialPort_ReadLineThread Method in SugaredSerial.cs. Just start up the thread:

serialPort_readLineThread = new Thread(() => serialPort_ReadLineThread(serialPort));
serialPort_readLineThread.Start();

and define a method to process the lines:

private void serialPort_LineReceived(Serial sender, string line)
1 Like

Excellent! :clap: Thank you!

@ eolson - unfortunately this is not the case for me. Iā€™m reading the bytes from the serial port myself and converting them to a string myself also. So just by doing something simple like the following, can result in missing characters in my project (missing characters in string s):

if (_serialPort.BytesToRead > 0)
{
      byte[] buf = new byte[_serialPort.BytesToRead];
      int res = _serialPort.Read(buf, 0, buf.Length);
      
      if (res <= 0)
           return;

      string s = new string(buf.Bytes2Chars());
      Debug.Print(s);
}

Where Bytes2Chars is an extension method defined as:

public static char[] Bytes2Chars(this byte[] Input)
{
      char[] output = new char[Input.Length];
      for (int i = 0; i < Input.Length; ++i)
          output[i] = (char)Input[i];
      return output;
 }

And it of course doesnā€™t matter if I use Bytes2Chars or Encoding.UTF8.GetChars, same result. :-/

Hi MD,

Can you set the serial port error event handler and print to debug if you detect an overrun error? It would be nice to know if this is your reason for the lost character and I suspect it is.

@ Dave McLaughlin - Hi Dave, I hooked up to the serialPort.ErrorReceived event and added a Debug.Print to the handler, but the event is not firing when or after a missing byte/character occurs (or ever actually).

What bit rate are you using?

Can you try higher rates, like 38400, 57600 or 115200?

@ Dave McLaughlin - Iā€™m using 19200, but yes, Iā€™ll try higher rates on monday (unfortunately Iā€™m not at the office before then).

[quote=ā€œMDā€]
@ eolson - unfortunately this is not the case for me.
[/quote] After more testing this week, it is not the case for me either. It made a significant difference, but Iā€™m still loosing bytes randomly on the input. Maybe 1 byte out of every 20 x 40 byte messages? (RS232 port of a Pioneer receiver sending Pandora metadata at 9600 baud) Reasonably reproducible in my environment. I think the error rate goes down a little when I swap RS232 ports (with another higher speed RS232 device that is no longer having errors). [Cobra II] (fortunately I can move the Pioneer to a tcp port if necessary)
FYI
Typical data resembles: GEH04022"" or GEH05020"Aqualung"
Bad data examples: GGEH04022"", EH05032"", G, GEH0026"", GEGEH07000""

I tried higher rates now, and it doesnā€™t seem to make any difference. The missing bytes still occur and the SerialPort.ErrorReceived event never fires.
Another thing I have also been experiencing during my testing and debugging is that SerialPort.Read can fail with an ArgumentException if to much data accumulates on the serial port before it is read (3KB accumulated data for example). After the exception is thrown, the SerialPort is not usable/readable before resetting the serial port by for example rebooting the G400 (if you try to read the port, more argument exceptions are thrown).