Arduino MKR Zero Serial baud rate mystery

I had an Arduino sketch and C++ program on PC to communicate using Serial library for Uno, it worked fine and I would have to set the baud rates on both Arduino side (e.g. SerialUSB.begin(9600)) and PC side to the same value. If I would set them to different values they would stop communicating. Also, increasing the baud rate would proportionally increase the communication speed.

I then tried Arduino Zero and it worked the same way.

I'm now using the MKR Zero and found to my surprise that the MKR Zero board communicates with the PC host always at the same actual communication speed regardless of the baud rate numbers that I set in the sketch and in PC C++ code (I ran the timing tests). Even if I set the baud rates in the sketch and C++ host code to different numbers is still communicates. It looks as if the communication channel is pre-set to a constant baud rate and totally ignores the baudrate settings in the sketch and the host C++ code.

My guess is that this is because the MKR Zero uses the native SAMD21 USB port setup as a CDC class? So basically the Serial a "fake" wrapper around a low level USB protocol and the board actually communicates using the USB CDC protocol but "pretends" to act like a serial com port?

I'm asking because I need higher speed communication to send large amount of data between Arduino and PC. I was able to reach much faster communication speed with Zero boards when I used 256000 baud rate. Is there a way to increase the serial communication speed for MKR Zero boards? (I know that switching to USB HID communication is another option but that would be lot of trouble and extra work)

Isn’t the “one speed” of the USB/CDC pretend port much faster than 256kbps? The last time I experimented with a SAMD21 native USB port, I was seeing speeds of several Mbps…

westfw:
Isn't the "one speed" of the USB/CDC pretend port much faster than 256kbps? The last time I experimented with a SAMD21 native USB port, I was seeing speeds of several Mbps...

As far as I know the max speed for CDC is 500kbsp (64 bytes max buffer size for high-speed USB mode with 1ms period). How did you get several Mbps?

But regardless of CDS, since I used Serial library on both Adruino and PC side, it's limited on the PC side at 256kbps (because it's the Win API driver limit for serial ports). But further to this, regardless of that API limit, I could not even get to 256kbps with MKR Zero because it ignores the baudrate setting altogether and seems to be hard-coded to 115kbps. With the Zero board (not MKR) I was able to get to 256kbps (but not higher on the PC side).

I posted this question in a parallel thread but if you could tell me how to get up to at least 500kbps with MKR Zero board by whichever way it works (serial, CDC, HID or whatever) I would greatly appreciate it!

As far as I know the max speed for CDC is 500kbsp (64 bytes max buffer size for high-speed USB mode with 1ms period). How did you get several Mbps?

Your logic is also what I thought happened, but when I went to try to “improve” USBSerial Performance, I wrote a little test sketch, and it shows me getting more than 6Mbps on a SAMD native USB port (to a MacOS system):

Test done.

Serial.write speed test with size 45
Sent 766305bytes of data in 1000009 Microseconds
Data Rate is 6130384.83 bps

I haven’t yet tried to figure out exactly where the “64b/ms” logic fails…

// If needed:
#define Serial SerialUSB

void setup() {
  Serial.begin(250000);
  while (!Serial)
    ;
  Serial.print(F("Enter a character to select write size"));
}
char text[] = "  0123456789... ABCDEFGHIJKLMNOPQRSTUVWXYZ \n"
              "  0123456789 .... ABCDEFGHIJKLMNOPQRSTUVWXYZ \n"
              "  0123456789 .... ABCDEFGHIJKLMNOPQRSTUVWXYZ \n";

void loop() {
  uint32_t starttime, eltime, datasent;
  int c = Serial.read();
  if (c < 0)
    return;
  if (c >= '0') {
    int len;
    len = (c - '0') * 5;
    if (len == 0) len = 1;
    Serial.print("Serial.write speed test with size ");
    Serial.println(len);
    Serial.flush();
    starttime = micros();
    datasent = 0;
    while (1) {
      if (micros() - starttime > 1000000)
        break;
      Serial.write(text, len);
      datasent += len;
    }
    Serial.flush();
    eltime = micros() - starttime;
    Serial.println();
    Serial.println(F("Test done."));
    Serial.print(F("Serial.write speed test with size "));
    Serial.println(len);
    Serial.print(F("Sent "));
    Serial.print(datasent);
    Serial.print(F("bytes of data in "));
    Serial.print(eltime);
    Serial.println(F(" Microseconds"));
    Serial.print(F("Data Rate is "));
    Serial.print((datasent * 8e6) / eltime);
    Serial.println(" bps");
    Serial.println();
    Serial.print(F("Enter a character to select write size"));
    while (Serial.read() > 0)
      ;
  }
}

Interesting. Thanks for the code! I ran the same code and got the result "Data Rate is 3606367.54 bps". And that is in spite of the fact the baudrate in the Serial Monitor was set to 115200 baud, so that one is another fake baudrate.

Google found this: "for full speed USB CDC device (using bulk transfer), 1,216,000 bytes/second is the theoretical max data throughput: up to 19 packets in 1ms frame for full speed bulk transfer in theory, max packet size for full speed USB bulk endpoint is 64 Bytes, 19packet x 64Bytes/1ms=1216B/ms or 1,216,000B/s".

So there must be something limiting the data rate in my codes, either in FW or on the PC side, I need to dive into this. One obvious thing is that I was sending data only one byte at a time with Serial.write(byte) and did not know about bulk transfer option Serial.write(text, len). That shoud speed up the data rate quite a lot.

Also on the topic: I was right that the MRK Zero boards ignore the baudrate settings and use the generic CDC USB protocol, here is how it's defined in CDC.cpp file:

void Serial_::begin(uint32_t /* baud_count */)
{
// uart config is ignored in USB-CDC
}

So Serial.begin with its baudrate setting is a dummy function that does not do anything.
Mystery solved