Nano 33 IoT millis() rate varies with USB power source

Hi,

I'm having a strange behavior several Nano 33 IoT's and their millis() counters. To try to create a very simple test case, I wait for 500 millis() then toggle and pin low or high and then repeat --> I should have a 1 Hz, 50% duty cycle square wave. I hooked the pin up to a logic analyzer sampling at 500MSa/s and observed the frequency.

When I have the Nano powered by a USB bus connected to a computer or powered hub connected to a computer, I get 1Hz. When I just take a micro USB cable and connect to any charger, I get 0.980Hz. It's very consistent.

The is the code that has different behavior depending on how the USB port of the Nano is connected. It's been distilled down from something more complex that first had the issue, but even with this code, the strange behavior is present

#include <Arduino.h>

void setup() {
  pinMode(2, OUTPUT);
}

void loop() {
  static unsigned long last_interval_ms = 0;
  if (millis() >= last_interval_ms + 500) {
    last_interval_ms = millis();
    digitalWrite(2, !digitalRead(2)); 
  }
}

What am I doing wrong? Two different Nano's do the same thing and it tracks the type of USB connection exactly. Millis() work as expected when on a USB from a computer or even a Raspberry Pi. When on a power only bus, Millis() seems to run a little slow. I haven't tried a stand alone power supply.

Could there be something being clocked differently internally when there's a USB host connection?

I found a reference to ticks being 1ms on the Nano 33 vs 1.024ms on AVR-based Arduinos. Could this be related? Why would things change based the USB connection?

How would I go about getting accurate time without a full USB host connected?

Thank you very much for all thoughts


Jay

Hi Jay (@ajaxous)

You're not doing anything wrong.

The Nano 33 IoT board is crystalless. This means that microcontroller's clock source is provided by its on-chip, 32.768kHz internal oscillator (OSC32K), which is less accurate than an external 32.768kHz crystal (XOSC32K) found on the Arduino Zero and MKR boards.

This internal oscillator can then used as the clock source for the on-chip Digital Frequency Locked Loop that multiplies it up (by 1465 times), to generate the CPU's 48MHz main clock (DFLL48M).

However, the SAMD21 microcontroller offers the alternative possibility of USB clock recovery from the USB's SOF (Start Of Frame) signal at 1kHz. This can also be employed as a clock source for the Digital Frequency Locked Loop (DFLL48M) instead, but only when the Nano 33 IoT board is connected a host computer with a data connection.

The 1kHz SOF signal is capable of providing a more accurate clock source for the Digital Frequency Locked Loop, hence the timing discrepancy you're observing.

1 Like

Hi,

Thank you for that quick reply -- I had a suspicion that something like that was happening but I wasn't positive.

Looking at the SAM D21 datasheet, I had seen the SOF 1kHz clock in the USB Block Diagram and was suspicious that was related to what was going on. Now, looking at the "17.6.7.2.2 USB Clock Recovery Mode" section, it states "USB Clock Recovery mode can be used to create the 48MHz USB clock from the USB Start Of Frame (SOF)". It does make sense now.

I had been using MQTT to publish the Nano's sensor data once a second, with an ISO 8601 timestamp (I used NTP to set the time, but was only refreshing once an hour). I had several other down stream steps that were collecting all the data and that's where I saw the time drifting (the delta from the ISO time stamp and the different brokers time stamps should be fairly uniform but it wasn't). When I would try to debug things, I'd bring the Nano back to my computer and then it seemed okay. I'd move it away to the non-data USB connection and then time would drift again. It finally seemed to be that duration of a millis() count was not same in the two different configurations. The logic analyzer and really short code segment helped verify that.

I had been curious why the default NTP server polling frequency had been 1 minute in NTPClient and NTPClient_Generic. It definitely works better to poll the NTP server more often in this situation.

Thank you again for helping me understand what was going on.


Jay

I have the same issue as Jay.
In my project, the 33iot connects internet via wifi.
Then get NTP time(stamp) once at the beginning.
Use the system time(millis()) to reupdate the current time.

In Jay's suggest, he sync the time from NTP every several time to fix the problem. But in my project sync to NTP take to much time.

Is there have other hardware or software solution? let millis() more stable without PC usb power.

Thank you very much for all thoughts

Lien

Same problem here. I collect logged data over Wifi and the timestamps drift by about 2 seconds per minute! That's almost an hour a day. Not good enough to take accurate measurements.

I cannot access the NTP servers (I think its some problem with my WiFi router), so the devices cannot periodically sync to real time. My solution is going to be to push time sync events (using UDP) back at each IOT device about once every 10 minutes from a central device which is connected to USB and has a reliable time. My devices listen for incoming UDP messages anyway, so its easy to push a 32-bit UTC value and reset the time on the device.

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