Faster way to print data over USB on Nano 33 BLE Sense

I set up a test (similar to the one from my previous question) to time how long a basic Serial.println("HELLO WORLD") takes on the Arduino Nano 33 BLE Sense; 160.2 us...

#include "mbed.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"

#define OUTPUT_PIN NRF_GPIO_PIN_MAP(1,11)

uint32_t startClock;
uint32_t stopClock;
uint32_t arithmeticMinuend = 4294967295;
uint32_t arithmeticSubtrahend = 2147483648;
uint32_t arithmeticDifference = 0;
uint32_t timeDifference1 = 0;
uint32_t timeDifference2 = 0;

void setup() {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  while (!Serial);
  delay(1000);

  nrf_gpio_cfg_output(OUTPUT_PIN);
  us_ticker_init();
  startClock = us_ticker_read();
  stopClock = us_ticker_read();
}

void loop() {
  Serial.println("Starting program:");
  timeDifference1 = microsecondsToSubtract2LongsOnce();
  timeDifference2 = microsecondsToSubtract2LongsAndPrint();
  us_ticker_free();
  Serial.print("timeDifference1 = ");
  Serial.print(timeDifference1);
  Serial.print(" us.\ntimeDifference2 = ");
  Serial.print(timeDifference2);
  Serial.println(" us.");

  us_ticker_init();
  microsecondsToSubtract2LongsOnceMeasuredWithScope();
  us_ticker_free();
  delay(10);
  us_ticker_init();
  microsecondsToSubtract2LongsTwiceMeasuredWithScope();
  us_ticker_free();
  delay(10);
  us_ticker_init();
  microsecondsToToggleOutputPinMeasuredWithScope();
  us_ticker_free();
  
  while(1) {
    
  }
}

//Prints 0-1 us:
uint32_t microsecondsToSubtract2LongsOnce() {
  startClock = us_ticker_read();
  stopClock = us_ticker_read();
  return stopClock - startClock;
}

//Prints 214-348 us:
uint32_t microsecondsToSubtract2LongsAndPrint() {
  startClock = us_ticker_read();
  Serial.println("HELLO WORLD1");
  stopClock = us_ticker_read();
  return stopClock - startClock;
}

//Measured 1.8 us on scope:
void microsecondsToSubtract2LongsOnceMeasuredWithScope() {
  nrf_gpio_pin_toggle(OUTPUT_PIN);
  startClock = us_ticker_read();
  stopClock = us_ticker_read();
  nrf_gpio_pin_toggle(OUTPUT_PIN);
}

//Measured 162 us on scope:
void microsecondsToSubtract2LongsTwiceMeasuredWithScope() {
  nrf_gpio_pin_toggle(OUTPUT_PIN);
  startClock = us_ticker_read();
  Serial.println("HELLO WORLD2");
  stopClock = us_ticker_read();
  nrf_gpio_pin_toggle(OUTPUT_PIN);
}

//Measured 500 ns on scope:
void microsecondsToToggleOutputPinMeasuredWithScope() {
  nrf_gpio_pin_toggle(OUTPUT_PIN);
  nrf_gpio_pin_toggle(OUTPUT_PIN);
}

I understand that the NRF52840 has native USB so maybe this could be exploited directly to get faster print times?

:cry: It takes 85 us just to write a single byte over USB:

#include "mbed.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"

#define OUTPUT_PIN NRF_GPIO_PIN_MAP(1,11)

const byte PRINT_BYTE = 254;

uint32_t startClock;
uint32_t stopClock;
uint32_t arithmeticMinuend = 4294967295;
uint32_t arithmeticSubtrahend = 2147483648;
uint32_t arithmeticDifference = 0;
uint32_t timeDifference1 = 0;
uint32_t timeDifference2 = 0;

void setup() {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  while (!Serial);
  delay(1000);

  nrf_gpio_cfg_output(OUTPUT_PIN);
  us_ticker_init();
  startClock = us_ticker_read();
  stopClock = us_ticker_read();
}

void loop() {
  Serial.println("Starting program:");
  timeDifference1 = microsecondsToSubtract2LongsOnce();
  timeDifference2 = microsecondsToSubtract2LongsAndPrint();
  us_ticker_free();
  Serial.print("timeDifference1 = ");
  Serial.print(timeDifference1);
  Serial.print(" us.\ntimeDifference2 = ");
  Serial.print(timeDifference2);
  Serial.println(" us.");

  us_ticker_init();
  microsecondsToSubtract2LongsOnceMeasuredWithScope();
  us_ticker_free();
  delay(10);
  us_ticker_init();
  microsecondsToSubtract2LongsTwiceMeasuredWithScope();
  us_ticker_free();
  delay(10);
  us_ticker_init();
  microsecondsToToggleOutputPinMeasuredWithScope();
  us_ticker_free();
  
  while(1) {
    
  }
}

//Prints 0-1 us:
uint32_t microsecondsToSubtract2LongsOnce() {
  startClock = us_ticker_read();
  stopClock = us_ticker_read();
  return stopClock - startClock;
}

//Prints 406 us:
uint32_t microsecondsToSubtract2LongsAndPrint() {
  startClock = us_ticker_read();
  Serial.write(PRINT_BYTE);
  stopClock = us_ticker_read();
  return stopClock - startClock;
}

//Measured 1.8 us on scope:
void microsecondsToSubtract2LongsOnceMeasuredWithScope() {
  nrf_gpio_pin_toggle(OUTPUT_PIN);
  startClock = us_ticker_read();
  stopClock = us_ticker_read();
  nrf_gpio_pin_toggle(OUTPUT_PIN);
}

//Measured 85 us on scope:
void microsecondsToSubtract2LongsTwiceMeasuredWithScope() {
  nrf_gpio_pin_toggle(OUTPUT_PIN);
  startClock = us_ticker_read();
  Serial.write(PRINT_BYTE);
  stopClock = us_ticker_read();
  nrf_gpio_pin_toggle(OUTPUT_PIN);
}

//Measured 500 ns on scope:
void microsecondsToToggleOutputPinMeasuredWithScope() {
  nrf_gpio_pin_toggle(OUTPUT_PIN);
  nrf_gpio_pin_toggle(OUTPUT_PIN);
}

did you try higher baud rate?

I read that baud rate setting doesn’t even do anything on the Arduino Nano 33 or Portenta H7 boards because their Arm based MCUs have native usb which is functioning as virtual com…

I can try lower baud rate setting and see if it is slower.

What I want is a more direct way to achieve the print though. Like using mbed os code or NRF SDK code.

I'll soon be trying the UART (the Serial1) on the board because of the same issue. I'd report back (hopefully). Yet, it may take 1 or 2 weeks.

@necator Ignore this post. I suspect lsi8 did not look into how USB works. Measuring how much time is needed to send one byte over USB is meaningless. USB does not send single bytes. USB is a protocol with different transfer modes and additional protocol overhead.
If you like to have an average value. Send larger amounts of data and then calculate the average bandwidth from that.

@Klaus_K Could you please refrain from telling people to ignore my posts? If someone has had a similar experience to mine and would like to help find a solution, then what's in it for you to impede them? Also, could you please explain how a 1 byte speed test is "meaningless"?

USB is polled at 1 ms intervals, and sends a buffer full of data in a burst.

So the time you might calculate from your simplistic experiments for the "transfer of 1 byte" is completely meaningless.

@Klaus_K @jremington
Okay, so is there a way to speed up the data transfer rate? I was trying to do this in this other thread a while back but eventually gave up. I found that the Portenta H7 had a faster transfer rate and so I went with that. I would like to use the Nano though if someone can suggest a way to speed things up.

Transfer large blocks of data at once, using Serial.write().

You may be limited by internal Arduino buffers.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.