2

I'm communicating serially with an Arduino Mega2560 from Raspberry Pi v1 model B. The Mega is connected to the Pi's USB slot.

I'm using the rxtx library on the Pi to send data at 1,000,000 baud. The Arduino requests data from the Pi by transmitting 1 byte to the Pi. The Pi receives the byte, then replies with 3072 bytes. The Arduino receives the 3072 bytes and replies with one byte... etc. This process continues forever.

In this process the Pi only sends 3072 bytes 15 times a second (that's 43,008 bytes/sec.) This surprises me because 15 times a second is only around 460,000 baud, not 1,000,0000 baud!

1,000,000 baud is 125,000 bytes/sec.

125,000 / 3072 is about 40.

So I expected to send more like 40 chunks of 3072 bytes a second.

Given the Arduino is doing NO processing here, other than receiving the data and sending 1 byte, why can't I transmit 40 times a second? My only guess is maybe USB serial communication is half duplex, and so my effective baud rate is 500,000 but that's pure speculation... any ideas?

Edit:

I'm using the Java RXTX library. I've included my FPS test code below. Also I've tried transmitting in larger chunks, without waiting for request from the Arduino just to determine what my best baud rate was. I sent the same amount of data.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

public class FPSTest {
    private static SerialPort createSerialPort(String portName, int baudRate) throws IOException {
        SerialPort serialPort = null;
        CommPortIdentifier portIdentifier = null;
        try {
            portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
        } catch (NoSuchPortException e) {
            throw new IOException("No such port " + portName, e);
        }
        if (portIdentifier.isCurrentlyOwned()) {
            throw new IOException("Error: Port is currently in use");
        }
        //
        else {
            int timeout = 2000;
            CommPort commPort;
            try {
                commPort = portIdentifier.open(FPSTest.class.getName(), timeout);
            } catch (PortInUseException e) {
                throw new IOException("Port " + portName + " is in use", e);
            }

            if (commPort instanceof SerialPort) {
                serialPort = (SerialPort) commPort;
                try {
                    serialPort.setSerialPortParams(baudRate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                            SerialPort.PARITY_NONE);
                    System.out.println("Baud raute = " + serialPort.getBaudRate());
                } catch (UnsupportedCommOperationException e) {
                    throw new IOException("Unable to set serial port parameters", e);
                }
            }
            //
            else {
                throw new IOException("Error: This device is not a serial port.");
            }
        }
        return serialPort;
    }

    public static void main(String[] args) throws IOException, UnsupportedCommOperationException {
        int baud = 1000000;
        byte[] bytes = new byte[3072];
        SerialPort port = createSerialPort("/dev/ttyUSB0", baud);
        InputStream stream = port.getInputStream();
        OutputStream output = port.getOutputStream();
        long time = 0;
        int fps = 0;
        long fpsTime = 0;
        System.out.println("begin reading...");
        while (true) {
            int result = stream.read();
            output.write(bytes);
            output.flush();

            ++fps;
            if (time != 0) {
                long elapsed = System.currentTimeMillis() - time;
                fpsTime += elapsed;
            }
            if (fpsTime >= 1000) {
                System.out.println("fps: " + fps);
                fpsTime = 0;
                fps = 0;
            }
            time = System.currentTimeMillis();
        }
    }
    }

Here's the sketch I've loaded onto my Arduino:

#include "FastLED.h"

#define NUM_LEDS 1024
#define DATA_PIN 7

CRGB leds[NUM_LEDS];

int colors[8][3]={
    {255,0,0},
    {0,255,0},
    {0,0,255},
    {255,255,0},
    {0,255,255},
    {255,0,255},
    {255,255,255},
    {0,0,0}
  };

void setup() {
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  Serial.begin(1000000);
  bootupColorSequence();
}

void bootupColorSequence(){
  for(int i=0;i<8;i++){
    fill(colors[i][0],colors[i][1],colors[i][2]);  
    FastLED.show();
    delay(100);
  }
}


int serialReadBlocking(){
  while(!Serial.available()){}
  return Serial.read();
}

int numRead = 0;
int readFromSerial2(){
  int result = 0;
  if(numRead!=NUM_LEDS*3)
    Serial.write((byte)1);
  else
    Serial.write((byte)0);
  Serial.flush();
  numRead = Serial.readBytes((char*)leds, NUM_LEDS*3);
  return result;
}

void fill(int r,int g, int b){
  for(long i=0;i<NUM_LEDS;i++)
  {
    leds[i].r = r;
    leds[i].g = g;
    leds[i].b = b;
  }
}

void loop() {
  int status = readFromSerial2();
  FastLED.show();
}

I've tried adjusting the uart baud and clock speed under /boot/config.txt to no avail. I don't recall performing further configuration.

I've tried JSSC now and had similar the exact same maximum bandwidth. This makes me think my problem native, either hardware or driver related as 2 Java implementations have had the same issue.

  • 1
    You haven't added any details (code, settings, etc.) to explain how you did this, meaning all anyone can do is go, "Oh I guess it doesn't work then, too bad for you" or if they are nice, make random guesses about what you did wrong. Hopefully mine is correct. If not, please explain yourself more completely (SSCCE, etc.). – goldilocks Feb 7 '16 at 11:39
  • Just because the USB is transmitting at 1Mbps doesn't mean you will transfer 100,000 bytes a second (serial data is usually 10 bits, start + 8 data + stop, although I don't know what USB does internally). As an experiment try sending larger packets. Do you get a higher throughput? – joan Feb 7 '16 at 12:21
  • To which "rxtx" library are you referring? Can you edit your question, to provide a link in your question? Do you mean the RXTX Java library? – Greenonline Feb 7 '16 at 14:15
  • @goldilocks I've added more detail par your request, I appreciate the assistance. – William Morrison Feb 7 '16 at 17:32
  • 1
    @Greenonline yes I'm using the java RXTX library. I've also included my FPS testing code and my Arduino sketch. – William Morrison Feb 7 '16 at 17:35
1

[This probably only applies to the GPIO UART pins but it may be worth trying.]

My only guess is maybe USB serial communication is half duplex, and so my effective baud rate is 500,000 but that's pure speculation

Nope, it will run at 1+ Mbaud both ways (I've tried 2 but not enough to say how reliable it is). However, the default clock is 3 Mhz, which is probably not enough to drive anything much over ~190 Kbaud (assuming the transmission rate is 1/16 the clock).

Try adding:

init_uart_baud 1000000
init_uart_clock 16000000

To /boot/config.txt and reboot.

  • I've tried this and had no luck. Assuming 10 bits per byte my rate is actually around 460Kbaud. I'd hope I'd have nearer than 50% my requested rate! – William Morrison Feb 7 '16 at 17:34
  • You could have a look in minicom -s and see what rates are available, but 1000000 is probably one of them. If you are really desperate you could also try doing it wire to wire with the arduino, I'd presume there's some UART code available for that. I use the pins to an FPGA that absolutely cannot deviate rate once configured, and 500K and 1M work there. – goldilocks Feb 7 '16 at 17:59
  • I've checked minicom and yes, 1Mbaud is available. (Higher rates too.) I've. Bought a logic level converter for the UART approach. I'll try and remember to update here with results once I've them. – William Morrison Feb 8 '16 at 4:04
  • Ok I've got everything wired up with my logic level converter. However when I send 3072 bytes from the pi, I only receive 1333 bytes on the Arduino side. If I only flush about 100 bytes at a time I lose much less data but I still lose some. Any idea why this would be? – William Morrison Feb 13 '16 at 23:15
0

After upgrading to a raspberry pi 3 model B I can finally transmit at 1,000,000 baud using the same test case I've posted above. Because of this I suspect the limitation I had was hardware induced (probably CPU bound.)

To anyone experiencing slow baud rates I recommend upgrading. If upgrading isn't an option, consider using a lower level language to remove any latency caused by Java interoping via JNI to native layers, or the JRE itself.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.