Serial print seems to block

Hi I’m using an AVR4809 to run a stepper motor using the accelstepper library. The AVR receives instructions from a C# driver I’ve written, which sits between client software and the 4809. The comms protocol between the driver and the 4809 is well established and all works fine. Serial and Serial2 Comms are via USB through 2 x FTDI devices.

So my problem is that whilst Serial comms work fine with no delay (i.e. non blocking), Serial2 seems to block, and that causes my stepper motor to pause. I’ve stripped the code down and experimented to try to isolate the problem. Here’s the (pretty simple) code that causes the problem:

if (Monitor.available() > 0)
  {
    String monitorReceipt = Monitor.readStringUntil('#');

    if (monitorReceipt.indexOf("dataRequest", 0) > -1)   // request for data packet from the C# driver
    {
      dataPacket= String(syncCount) + '#';
      Monitor.print(dataPacket);                  // this seems to take about 2 seconds to execute
      ledToggle();
     
    }

Note that there’s a compiler directive which assigns Monitor as Serial2.
syncCount is defined as int and is incremented elsewhere in the code.
dataPacket is defined as String and is normally assigned elsewhere in the code, I put it where it is currently shown just to make a simple example of the problem.

I introduced the ledToggle so I could get a visual on the delay and it’s about 2 seconds.

Normally in the C# code a 3 second timer event transmits the text ‘dataRequest’ and the AVR4809 responds with the data packet (this normally consists of six data items concatenated with ‘#’ delimiters). The code works as expected, apart from the delay which causes the stepper motor to pause.

Any suggestions as to the cause, or anything to look for would be greatly appreciated.

Did you measure this by taking a micros or millis timestamp before and after and printing the difference? That’s a sure way of knowing how much execution time it needed.

unsigned long tStart = micros();
Monitor.print(dataPacket);                  // this seems to take about 2 seconds to execute
// if buffering is involved: add 
// Monitor.flush(); 
//to make sure this only returns when all data was sent
unsigned long tEnd = micros();
Serial.println("Printing took " + String(tEnd - tStart) + " microseconds");

It should also be noted that if you try and print something that is beyond the UART TX buffer size, it will hardblock.

For a ATMega4809 with ~6K of RAM, it should have a TX buffer size of 64 bytes.

You can affect this by defining the overriding macro in build_flags, such as

build_flags =
   -DSERIAL_TX_BUFFER_SIZE=256

However, 2 seconds seems to be very extreme, it would have to be massive amounts of data and a low baud rate.

Thus I think it’s rather something on the C# / computer side, specifically stream flushing. If you’re using the wrong programming constructs or settings, it might only trigger a “flush” of the received UART data to your C# program if it receives a line ending (such as \n) or after a long timeout.

By measuring the transmission time on the Arduino side as shown in the code above, you should be able to deduce which case you’re in.

Thanks Max, that’s all very helpful, I’ll explore some of this. Thanks for comprehensive reply, much appreciated.

You were right, further investigation showed a missing data terminator at the C# end. Instead of sending ‘dataRequest#’ the code was sending ‘dataRequest’.

That was causing the process delay in the 4809 code. Now that the ‘#’ has been included, the code runs fine with no pause, stepper motor runs as expected. :slight_smile:

Thanks again for great help, as always.

1 Like