DUE native port and serial port maximum baud rate.

Hi, friends.

i want to send a bunch of data out to PC.

i want to know how fast i can send out the out at what maximum baud rate in both serial port and native port.

i tried SerialUSB.begin(1000000) for native port. and tried Serial.begin(250000) for serial port.

at native port i am getting the same speed on any bauad rate , i do not know what i am missing.

here is my code.

int drm[20000];
int drn;
void setup() {
SerialUSB.begin(1000000);
while (!SerialUSB) {
};
pinMode(3,INPUT);
pinMode(4,INPUT);
pinMode(5,INPUT);
pinMode(6,INPUT);
pinMode(7,INPUT);
for(int i=0;i<=20000;i++)
{
drm*= digitalRead(3);*
_ drm*= digitalRead(4);_
_ drm= digitalRead(5);
drm= digitalRead(6);
drm= digitalRead(7);
}
for(int i=0;i<=20000;i++)
{*_

SerialUSB.println(drm*);*
delay(1);
* }*
}
void loop() {

}

SerialUSB allows you to set a baud rate but it is completely ignored. USB doesn't really have any concept of a baud rate. So, the answer is a little bit more complicated there. USB itself has a basic speed that the bus runs at. On a reasonably modern machine and with the native port that is likely to be 480mps. The various devices on the bus get slots in this bandwidth. Each connected device is polled by the PC at a specific agreed upon interval. At this interval the PC side asks the client (Due) side if it has any data to send. The buffer will only be so big so if you try to send too much data it'll get broken into multiple time slots. So, somewhat the maximum transfer rate is contingent on how many devices are on the bus and how often you send things to the USB buffer. That is, doing SerialUSB.print("A"); is likely to have worse performance than buffering a bunch of data up and doing SerialUSB.write(buffer, 2048); but there comes a point where too large a RAM buffer will just cause it to have to sit around waiting to write more when the buffer empties. Sending in larger chunks can give better total transfer rate than sending in smaller batches but it also increases total latency. You kind of have to tune things a bit to get the best performance.

I think the Due is capable of pushing to upwards of 20 megabits per second if you play your cards right.

Thanks AdderD, i am totally new to this USB coding and in fact DUE board.

can you say something about how to write workable code as per my need. i have already wrote my code above. i need to send 20K buffer data each has 32 bit length. i want to send to PC.

if possible then give me some sample code.

Thanks

Well, your sketch was a bit far off from doing what you said it was that you were trying to do. Something like the below is more accurate to what you said you were trying for:

int drm[20000][5];

void setup() {
  SerialUSB.begin();
  while (!SerialUSB);

  pinMode(3,INPUT);
  pinMode(4,INPUT);
  pinMode(5,INPUT);
  pinMode(6,INPUT);
  pinMode(7,INPUT);

  for(int i=0;i<=20000;i++)
  {
     drm[i][0]= digitalRead(3);
     drm[i][1]= digitalRead(4);
     drm[i][2]= digitalRead(5);
     drm[i][3]= digitalRead(6);
     drm[i][4]= digitalRead(7);
  }

  for(int i=0;i<=20000;i++)
  {
      SerialUSB.println(drm[i][0]);
      SerialUSB.println(drm[i][1]);
      SerialUSB.println(drm[i][2]);
      SerialUSB.println(drm[i][3]);
      SerialUSB.println(drm[i][4]);
      SerialUSB.println();
  }
}

void loop() {
  
}

That would capture 20k iterations of the pin state and then dump them all out the USB port as quickly as possible. It doesn't use buffering but should still be fairly fast. How fast do you really need to send things out of the USB port? In your sketch you had a delay(1) after each write which would have DRASTICALLY slowed down the sending. If you did nothing but take out the delay(1) you'd speed things up very much. But, still your sketch would not have really worked properly at all.

Thanks adderD, i tried this code. but it take 30 seconds to transfer the data.

my requirement is to finish the transfer withing 5 seconds.

can we change USB speed ? or any other way to send data at higher speed other than this we are getting through this code.?

SerialUSB.write can send data super fast, AFAIK up to 850 Kbyte/s.

uint8_t buf[4096];

void setup() {
  SerialUSB.begin(9600);
  while(!SerialUSB);
  for(int i = 0; i < 4096; i++)
    buf[i] = (uint8_t)i;
    
}

void loop() {
  SerialUSB.write((uint8_t*)buf, 4096);
  delay(200);
}

But this is not readable like a SerialUSB.print.

To receive then parse data in the PC side, see:

https://playground.arduino.cc/Interfacing/CPPWindows

void dumpData() {
   int totLen=0;
   char buffer[2000];  // long-ish buffer
   for (int i=0; i < 20000; i++) {
     totLen += sprintf(&buffer[totLen], "%d %d %d %d %d\n", drm[i][0], drm[i][1], drm[i][2], drm[i][3], drm[i][4]);
     if (totLen > (sizeof(buffer) - 100)) { // if buffer is close to full
       SerialUSB.write(buffer, totLen);  // write the buffer to USB
       totLen = 0;  // reset to beginning of buffer
      }
    } // end for loop
    SerialUSB.write(buffer, totLen);  // write last buffer
}

my buffer length is 20000, i do not understand why you(westfw) used char buffer[2000]; and you (ard_newib) used 4096 size.?

i want to send data in less than 5 seconds. it is taking 40 seconds at present. how do i increase the speed of Serial or USB? it says minimum speed of UsB is 1.5Mbps.

You just can't write any buffer length in SerialUSB.write without issues.

Here is a workaround for a super fast data logging, you will need to parse your data in the PC side this way:

/************* Comment this line if you want to use SerialUSB   **********/
#define SerialUSB Serial
/************************************************************************/

const uint32_t Size = 20000;

uint8_t Mylog;

void setup() {
  SerialUSB.begin(250000);
  while (!SerialUSB);

  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);

}

void loop() {
 
  SerialUSB.println(" Start of transmission");
  for (uint32_t i = 0; i < Size; i++) {

    // Pin 3 = PC28,
    // Pin 4 = PC26,
    // Pin 5 = PC25,
    // Pin 6 = PC24,
    // Pin 7 = PC23
    //The level on each I/O line can be read through PIO_PDSR (Pin Data Status Register). 
    //This register indicates the level of the I/O lines regardless of their configuration
    Mylog = (uint8_t)(PIOC->PIO_PDSR >> 23);

    SerialUSB.write((uint8_t*)Mylog, 1);
    // Parsing is made in PC side
  }
  SerialUSB.println(" End of transmission");
  while (true); // Stop here ?

}

You just can't write any buffer length in SerialUSB.write without issues.

You should be able to. But indeed, I am having problems getting anything more than about 250 bytes to work.

The THEORY is that a usb data exchange takes some fixed time Tt, plus some time based on the amount of data in the exchange Td - usually the Tt is much larger than Td, so it's to your advantage to use a large chunk of data (ie a large buffer) in each exchange. At least, up to the point where the buffer becomes larger than the amount you're allowed to send in each exchange.

In PRACTICE, there are a lot of factors involved in the overall throughput. There is the USB driver in the Due, the way that the Arduino serial code interacts with it, the USB driver in the host, the Serial port driver in the host, and the way that the host application interacts with all that. I'm getting about 800ms to upload 10000*6 values (code attached), regardless of whether I use "println" for every line, or a more complicated buffering scheme :frowning:

Your code has other problems...

int drm[20000][5];

An Arduino Due does not have that much RAM memory. (400kBytes!)

int drm[20000];

A due doesn't even have THAT much contiguous RAM memory (80k bytes. Due has a 64k chunk and a 32k chunk.)

i don't see how you get your code to even compile...

for(int i=0;i<=20000;i++)

the "<=" should just be a "<"; otherwise you access the 20001st element of your array. (this will compile, but writing beyond the end of the array can cause .... indeterminate behavior.)

My test code:

#include <stdio.h>
#define DRMLEN 10000
#define BUFSIZE 300
#define USE_WRITE 1
#define USE_SMALL_PRINT 0

uint8_t drm[DRMLEN][5];

void setup() {
  // put your setup code here, to run once:
  SerialUSB.begin(9600);
  while (!SerialUSB)
    ;
  SerialUSB.print("Program starting");
  SerialUSB.println();
  delay(5000);
  SerialUSB.println("Here we go!");
}

uint32_t totdata;

void loop() {
  // put your main code here, to run repeatedly:
  uint32_t starttime, elapsedtime;

  for (int i = 0; i < DRMLEN; i++)
  {
    drm[i][0] = digitalRead(3);
    drm[i][1] = digitalRead(4);
    drm[i][2] = digitalRead(5);
    drm[i][3] = digitalRead(6);
    drm[i][4] = digitalRead(7);
  }
#if USE_WRITE
  SerialUSB.println("Dumping output using write");
#else
  SerialUSB.println("Dumping output using print");
#endif

  starttime = millis();
  totdata = 0;
  dumpData();
  elapsedtime = millis() - starttime;
  SerialUSB.print("Elapsed Time is ");
  SerialUSB.print(elapsedtime);
  SerialUSB.print(" ms");
  SerialUSB.print(" Total data bytes: ");
  SerialUSB.print(totdata);
  SerialUSB.print(" (");
  SerialUSB.print(((float)totdata) / (elapsedtime) * 1000.0);
  SerialUSB.print(" bytes/s)");
  SerialUSB.println();
  while (SerialUSB.read() == -1) {
    delay(1000);
  }
}

void dumpData() {
  int totLen = 0;
  int len;


  char buffer[BUFSIZE];  // long-ish buffer
  for (int i = 0; i < DRMLEN; i++) {
#if USE_SMALL_PRINT
    SerialUSB.print(i); SerialUSB.print(": ");
    SerialUSB.print(drm[i][0]); SerialUSB.print(" ");
    SerialUSB.print(drm[i][1]); SerialUSB.print(" ");
    SerialUSB.print(drm[i][2]); SerialUSB.print(" ");
    SerialUSB.print(drm[i][3]); SerialUSB.print(" ");
    SerialUSB.print(drm[i][4]); SerialUSB.print("\r\n");
#else
    len = sprintf(&buffer[totLen], "%d: %d %d %d %d %d\r\n", i, drm[i][0], drm[i][1], drm[i][2], drm[i][3], drm[i][4]);
    totLen += len;
    totdata += len;
#if USE_WRITE
    if (totLen > (sizeof(buffer) - 50)) { // if buffer is close to full
      SerialUSB.write(buffer, totLen);  // write the buffer to USB
      totLen = 0;  // reset to beginning of buffer
    }
#else
    SerialUSB.print(buffer);  // use print
    totLen = 0;   // immediately reset buffer
#endif
#endif  // USE_SMALL_PRINT
  } // end for loop
  SerialUSB.write(buffer, totLen);  // write last buffer
}

A DUE has 64K + 32K contiguous SRAM (= 96K) plus 4K non contiguous.

uint32_t Buffer[20000] is OK, provided your other variables plus the stack will not need more than
(96 * 1024) - 80000 bytes (usually this condition is easy to achieve).

As stated by westfw, native USB speed dépends on many factors (including the PC side). One of them is the endpoints size and a Transmit transaction can use several endpoints. I have read somewhere that 4096 bytes is the maximum load which can be sent in one shot without a split of the transmit buffer.

To fully understand the native USB behaviour probably requires extensive knowledge of USB 2.0 protocol.

if USB speed is depends on many factor then can i use Serial with higher baud rate? i tried baud rate 450000 anything more than that is giving garbage value. another question is if i took port read directly without using digital read for each pin. then on computer side i will extract the exact bit . then how squeeze this code? in that case we will not use 2 D array like [20000][5].

Serial Baud rate is defined with UART_BRGR (i.e. UART_BRGR = 84000000/250000/16 will give you an expected baud rate of 250000 with a 0% error because this is an integer.

My reply #8 to this thread gives you the code to read directly the port (PIO_PDSR).

I guess that to really speed up the transmission, one might do this with UART:

  • clock the uc to 96 MHz
  • select a baud rate of 6 million : 96000000/6000000/16= 1
  • Code your UART with a PDC DMA (a DMA transaction is handled off core)

From the PC side, I don't know what should be done in processing sketch to give you the possibility to select this baud rate. Maybe you could use PUTTY and select 6 million bauds.

i do not know how to write code to change clock speed? if i do not want 6 million baud then can i reduce clock less than 84 MHz nearly to close integer?

EJLED:
i do not know how to write code to change clock speed? if i do not want 6 million baud then can i reduce clock less than 84 MHz nearly to close integer?

Yes you can. Google to find information on how you can adjust clock speed, several threads deal with that.

A DUE has 64K + 32K contiguous SRAM (= 96K) plus 4K non contiguous.

Rats. I looked it up and the 64k and 32k region didn't LOOK contiguous. But the datasheet DOES say:

SRAM0 is accessible over the system Cortex-M3 bus at address 0x2000 0000 and SRAM1 at address 0x2008 0000. The user can see the SRAM as contiguous thanks to mirror effect, giving 0x2007 0000 - 0x2008 7FFF for SAM3X/A8...

(now, does the compiler/linker set it up that way?)

if USB speed is depends on many factor then can i use Serial with higher baud rate?

Doesn't your serial port end up going over USB as well (which then gets you the same USB problems, only differently)? Few actual HW serial ports are likely to achieve 1Mbps+

If you really need hi-speed data transfer over USB, you could look into non-serial protocols (like the ones used for USB ethernet adaptors.) But that's likely to be somewhat difficult and I don't know whether there is any existing support for such things.

The SRAMs are aliased within their blocks; SRAM0 is aliased and will repeat every 64K, ie bits 16-18 of the address are ignored. So the byte that is accessed at address 0x20000000 can also be found at 0x20010000,
0x20020000, 0x20030000, etc, up to 0x20070000.

SRAM1 is similarly aliased and will repeat every 32K, ie bits 15-18 of the address are ignored. So the byte that is accessed at address 0x20080000, can also be found at 0x20088000, 0x20090000, 0x20098000, etc, up to 0x200F8000.

So to make the SRAM appear as one contiguous block it is accessed via the upper alias of SRAM0 (0x20070000) and the lower alias of SRAM1 (0x20080000).

And yes the native USB achieves at least a 849 Kbytes/s.

how do u co-relate drm[20000] with this SRAM0 and SRAM1 . i am not able to understand it properly. 20000 means 0x20000 or something else?

and drm[20000] means howmuch space among 64 K and 32 K it occupies ?for 64 K can we go upto drm[64000] ?

I am currently running a sketch where I am dumping 3 axis accelerometer data (3 floats truncated to 3 decimal places, 2 TAB separators, and CR/LF) at a rate of 1600 Hz out the usb programming port. All I had to do is start the sketch with Serial.begin(921600). I did not have to change with the buffer size of 128 in Ringbuffer.h although I did try to see if it would help any. I am reading the data cleanly using Teraterm set at the programming port/921600/7-N-1/Xon-Xoff. This setup has been spitting out data for the past 24 hour continuously.

For giggles and grins, I changed my data output to 5 truncated floats, 4 TAB separators, and the CR/LF. In order to get it running stably (I am scoping entry/exit flags for the ISR), I had to set Serial.begin rate to 1843200. My problem is at that COM rate Teraterm saturates a cpu core on my workstation (Dual-core 1.83) so I cannot verify with certainty that the datastream is clean, but there is a chance.

Now, I realize that setting a specific rate in serial.begin for USB SHOULDN'T matter, but it does. On my second run, the DUE runs stable set at 1843200, but not if I choose 1600000 (It will go through the ISR a few times and shut down.