Serial communication is slow

I've tried to search my problem but haven't found anything related yet so hopefully i won't get beaten for opening a new topic. :relaxed:
I've asked this question on StackOverflow also: java - Slow Arduino serial transmission - Stack Overflow

I'm testing my Arduino UNO's serial transmission speed. For my requirements i have to transfer eta. 3kB/s from the host PC to the Arduino. I've written a very simple program which replies back the result of Serial.available() then tested it in the Arduino IDE's Serial monitor. I've started sending characters till i reached the maximum which is 63 bytes. I was quiet surprised of that because i've read somewhere that the Arduino has a 128byte Serial buffer.

Anyway i've made up a very simple protocol which transmits data in 48 byte packets (actually 49 bytes because of the header character). The host sends a d character then 48 bytes of data. For testing the validity of the transmission i'm sending a simple byte sequence from 0 to 47 which gets validated on the Arduino side. If the validation fails the UNO starts to blink the onboard LED on PIN13. Once the bytes are sent the host waits for an acknowledgement which is a simple k character. The Arduino sends this once it finishes processing the actual packet.

The host program meassures the number of transmitted packets and display it after 1 second. With a baud rate of 9600 the PC successfully transmits ~16 packets/second (~800 bytes/sec) which is quiet ok. I've tried to improve this by increasing the baud rate on both sides to 57600 however the number of sent packets increase only a little. I don't know what's the problem. Maybe i've hit some kind of limit of the USB serial converter?

Here is my code.

PC (Java, i'm using jSSC Google Code Archive - Long-term storage for Google Code Project Hosting. for serial port communication)

      package hu.inagy.tapduino.server;
      
      import jssc.SerialPort;
      import jssc.SerialPortException;
      
      /**
       * Test Arduino communication.
       */
      public class App
      {
      
        private static void testComm(SerialPort port) throws SerialPortException {
          long runningSeconds = 0;
          long time = System.currentTimeMillis();
          long numberOfPackets = 0;
          boolean packetSent = false;
          while (runningSeconds < 10) {
            long currentTime = System.currentTimeMillis();
            if (currentTime - time > 1000) {
              runningSeconds++;
              time = currentTime;
              System.out.println(numberOfPackets + " packets/s");
              numberOfPackets = 0;
            }
      
            if (!packetSent) {
              packetSent = true;
              port.writeByte((byte) 'd');
              for (int i = 0; i < 48; i++) {
                port.writeByte((byte) i);
              }
            } else {
              byte[] received = port.readBytes();
              if (received != null) {
                if (received.length > 1) {
                  throw new IllegalStateException("One byte expected, instead got: " + received.length);
                }
      
                char cmd = (char) received[0];
                if ('k' != cmd) {
                  throw new IllegalStateException("Expected response 'k', instead got: " + cmd);
                }
                packetSent = false;
                numberOfPackets++;
              }
            }
      
          }
        }
      
        public static void main(String[] args)
        {
          SerialPort port = new SerialPort("COM7");
      
          try {
            if (!port.openPort()) {
              throw new IllegalStateException("Failed to open port.");
            }
            port.setParams(57600, 8, 1, 0);
          } catch (SerialPortException e) {
            throw new IllegalStateException("Exception while setting up port.", e);
          }
      
          try {
            // Wait 1.5sec for Arduino to boot successfully.
            Thread.sleep(1500);
          } catch (InterruptedException e) {
            throw new IllegalStateException("Interrupt while waiting?", e);
          }
      
          try {
            testComm(port);
          } catch (SerialPortException exc) {
            throw new IllegalStateException("Failure while testing communication.", exc);
          } finally {
            try {
              if (!port.closePort()) {
                throw new IllegalStateException("Failed to close port.");
              }
            } catch (SerialPortException e) {
              throw new IllegalStateException("Exception while closing port.", e);
            }
          }
        }
      }

Arduino

    void setup() {
       pinMode(13, OUTPUT);
       Serial.begin(57600);
    }
    
    boolean error = false;
    
    void loop() {
      if (error) {
          digitalWrite(13, HIGH);
          delay(1000);
          digitalWrite(13, LOW);
          delay(1000);
      } else {
        while (Serial.available()<49);
        char cmd = Serial.read();
        if ('d'!=cmd) {
           error=true;
           return;
        }
        
        for (int i=0; i<48; i++) {
           int r = Serial.read();
           if (r!=i) {
             error=true;
             return;
           } 
        }
        
        Serial.write('k');
      }
      
    }

If you want serial throughput just use

Serial.begin(345600); iso 57600 will be 6x as fast See also - Fast communication to PC with low Arduino footprint - #12 by robtillaart - Networking, Protocols, and Devices - Arduino Forum

Thank you robtillaart!

I've made the baud rate change as you suggested on both ends. But i still get only 19 packets/second as the maximum.
Maybe my code does something non optimally. :blush:

I've found the solution. The writeByte function of jSSC is highly inefficient in this case. If i premade the 49 byte buffer in Java then pass it at once to jSSC i get a very big speed boost.

    byte[] sendBuffer = new byte[49];
    sendBuffer[0] = 'd';

    for (byte i = 0; i < 48; i++) {
      sendBuffer[i + 1] = i;
    }
    port.writeBytes(sendBuffer);

With baud rate 345600 it gives me now ~240 packets/sec (~12KB/sec). :slight_smile:

345600 is in theory max 28-29KB/sec so 12KB is quite nice in practice.

You might even try baudrate 500000 as it is a divider of the clockspeed it is quite a stable although not common speed. should get you to 300 packets a second I expect.

What throughput do you need?

I need eta 3kB/sec. So i've already achieved what i need. :slight_smile: I guess there is still room for improvement though.

I've started sending characters till i reached the maximum which is 63 bytes. I was quiet surprised of that because i've read somewhere that the Arduino has a 128byte Serial buffer.

Prior to 1.0, the Arduino did have a 128 byte buffer. With 1.0, outgoing serial data is now buffered, too, so the buffer size was cut in half, so that the two buffers take up no more space than the one buffer did.