Ultra slow UART?

Hello,

In a reasearch project I’m working on, I need to log a large amount of data to an SD card. To make my life simple (rather than dealing with the raw SD card myself), I went with the 4D systems uDrive (http://www.4dsystems.com.au/prod.php?id=22) which just takes UART serial data and logs it to the card. I’m using an Arduino Mega, for the extra RAM, UART ports, external interrupts, and A/D channels.

Now when I tested the uDrive with my ftdi usb to serial cable, it works perfectly (can write about 2Kbyte/sec easily).

I run into problems when I use the Arduino to drive the serial communications, however. Despite the baud rate being 115200, the maximum transfer rate I can get is 50 bytes / sec. Outputting serial data to the port that has the uDrive attached to it is extremely slow - adding an echo on Serial0 shows that the characters are sent out slow enough to watch it scroll by.

I know something isn’t wrong with the Serial port interfacing with the uDrive - this slowdown happens on whichever port the uDrive is connected to. If I connect something like an XBee or the ftdi cable to the serial port that was using the uDrive, it outputs fine at normal speed. The uDrive also works fine with the ftdi cable, so I’m confused by what’s going on.

This is how I’m outputting bytes:

for(unsigned int i = 0; i < numBytes; i++)
{
            Serial1.write(buff[i]);
            Serial.write(buff[i]);
}

(Here Serial1 is connected to the uDrive, and Serial is the straight up usb port).

Does anyone know what’s going on? Right now, I have two wires going straight between RXD and TXD on each device, and nothing else. I tried adding pullup resistors on the lines, but that just seemed to stop all communication entirely. I wouldn’t worry, since it does work (albeit, slowly), except that I need to log about 1Kbyte/sec, where I’m only getting 50byte/sec.

I have contacted 4D about this, but they don’t understand why it’s so slow either, and are looking into it further, but this is seems to be a bit more of an Arduino issue since the uDrive works with an FTDI cable.

Thanks for any help anyone can send my way, is is greatly appreciated!!

How do you initialize Serial?

Serial.begin(?); Serial1.begin(?);

Do you have the l (l as in long) suffix appended to 115200 (115200l)?

Yes, both serial ports are initialized as:

Serial.begin(115200l);
Serial1.begin(115200l);

Why not create a minimal sketch showing the issue and post the full sketch for others to see.

Then you should look at printing the baudrate divisors (in Setup after you call begin). This will be UBRRn where n is 0 through to 3 depending on the serial port you use.

Are you compiling/uploading through the Arduino IDE and using version 0018?

Thank-you!! I’ve got it fixed now, thanks to a stupid mistake that I didn’t see. Your baudrate divisors comment really helped - I realized that the serial port the uDrive was on was 3000 something vs. the usb serial port at 16.

Turns out, the InitSD function I wrote was taking the baud rate as an argument to the function as an int instead of an unsigned long!

(Yes, I’m compiling and uploading through the Arduino IDE).

I’ve attached the demo sketch with the fixed argument type for posterity’s sake:

// Serial      - USB serial
// Serial1      - uDrive serial

char buffer[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla in elit augue, vitae consectetur nisl. Praesent mattis, nisi et bibendum pretium, risus lectus eleifend augue, luctus dictum diam mauris sed mi. Sed sit amet lectus orci. Nulla molestie placerat accumsan. Aliquam erat volutpat. Integer dictum ultricies tortor vel egestas. Morbi auctor pulvinar volutpat. Mauris sodales auctor porta. Donec malesuada pulvinar nisi, sed suscipit turpis auctor vitae. Sed vel tortor at diam vulputate scelerisque sed eget risus. Nunc eu lorem id diam tincidunt ultrices. Phasellus non velit augue, nec lobortis ipsum. Suspendisse potenti. Nam non ante quis lorem pharetra vulputate nec vel neque.";

void ClearJunk()
{
      while(Serial1.available() > 0)
            char c = Serial.read();
}

boolean WaitForAck()
{
      char b = 0;
      while(b != 0x06 && b != 0x15)
      {
            if(Serial1.available() > 0)
            {
                  b = Serial1.read();
                  Serial.write(b);
            }
      }
      if(b == 0x06)
            return true;
      return false;
}

boolean InitSD(unsigned long baud, unsigned long timeout)
{
      // start the serial port
      Serial1.begin(baud);

      delay(500);
      
      // setup the uDrive's autobaud feature
      int response = 0x15;
      unsigned long st = millis();
      while(response != 0x06)
      {
            Serial1.write('U');
            
            if(Serial1.available() > 0)
                  response = Serial1.read();
                        
            if((millis() - st) > timeout)
            {
                  // timed out
                  ClearJunk();
                  return false;
            }
      }
      ClearJunk();
            
      return true;
}

boolean WriteFile(char *file, boolean overwrite, unsigned long numBytes, char *buff)
{
      ClearJunk();
      
      // command header
      Serial1.print("@t"); 
      Serial.print("@t"); 
      
      // overwrite / append mode + 50 byte handshaking
      if(overwrite)
      {
            Serial1.write(0x32);
            Serial.write(0x32);
      }
      else
      {
            Serial1.write(0x32 | 0x80);
            Serial.write(0x32 | 0x80);
      }
      
      // file name
      Serial1.print(file);
      Serial1.write((uint8_t)0x00);
      Serial.print(file);
      Serial.write((uint8_t)0x00);
      
      // file size
      Serial1.write(byte(numBytes >> 24));
      Serial1.write(byte(numBytes >> 16));
      Serial1.write(byte(numBytes >>  8));
      Serial1.write(byte(numBytes >>  0));

      Serial.write(byte(numBytes >> 24));
      Serial.write(byte(numBytes >> 16));
      Serial.write(byte(numBytes >>  8));
      Serial.write(byte(numBytes >>  0));
      
      // wait for ack
      if(!WaitForAck())
            return false;
                  
      char count = 0;
      for(unsigned int i = 0; i < numBytes; i++)
      {
            Serial1.write(buff[i]);
            Serial.write(buff[i]);
            count++;
            
            // handshake
            if(count == 50)
            {
                  if(!WaitForAck())
                        return false;
                  count = 0;
            }
      }
      
      // wait for ack
      if(!WaitForAck())
            return false;
      
      return true;
}

void setup()
{
      // start usb serial
      Serial.begin(115200l);
      
      // init the uDrive serial with 5 second timeout
      Serial.println("Initializing SD Card...");
      if(!InitSD(115200l, 5000))
      {
            Serial.println("Init failed!");
            while(1);
      }
      Serial.println("Done!");
      
      Serial.println("Baud rate divisors:");
      Serial.print("Serial:  ");
      Serial.println(UBRR0);
      Serial.print("Serial1: ");
      Serial.println(UBRR1);
      
      Serial.println("Writing file...");
      unsigned long st = micros();
      boolean r = WriteFile("lorem.txt", true, strlen(buffer), buffer);
      unsigned long et = micros();
      
      if(!r)
            Serial.println("\r\nFailed!");
      else
      {
            Serial.println("\r\nSuccess!");
            Serial.print("Took ");
            Serial.print(et - st);
            Serial.println(" uS!");
            Serial.println("To write ");
            Serial.print(strlen(buffer));
            Serial.println(" bytes!");
      }
      
      Serial.println("Done test!");
}

void loop()
{
        
}

Once again, many thanks! This is why I love Arduino - so much great community support!

This is why I love Arduino

Me to! :)