Page 1 of 1

Millis() and esp_timer_get_time() non-monotonic

Posted: Fri Jul 24, 2026 4:19 pm
by Downsider
In the loop () of my application, I print the loop iteration time to check for stalls etc.

Very infrequently I appear to see the Millis() and esp_timer_get_time() go backwards, by up to 3~4s. I have no sleep modes enabled, only interesting thing running is nimBLE with a single idle connection to a central.

Once the issue sets in - it can take an arbitrary time to start from less than a minute, or in this case 3 hrs, then it continues to happen more frequently until the code crashes for various reasons (most likely caused by no functions expecting the clock to go backwards, so watchdog times bite, etc.)

Is it bad silicon (date code 492025)? is it fake silicon (unlikely I think). Any ideas on how to resolve this?

In this debug log, the console is timestamping the serial.print messages:

10887.9906 long loop millis -1
10887.9913 long loop micros -229

10887.9932 INT free 243192
10887.9950 INT largest 200692
10887.9969 DMA free 235432
10887.9986 DMA largest 200692
10888.0004 PSRAM free 101552
10889.6560 long loop millis -1880
10889.6566 long loop micros -1879488

10889.6585 INT free 243192
10889.6602 INT largest 200692
10889.6620 DMA free 235432
10889.6637 DMA largest 200692
10889.6654 PSRAM free 101552
10899.2712 T: 35000
10920.1166 long loop millis -1
10920.1171 long loop micros -114

10920.1190 INT free 243192
10920.1208 INT largest 200692
10920.1224 DMA free 235432
10920.1242 DMA largest 200692
10920.1260 PSRAM free 101552
10924.2925 long loop millis -1
10924.2930 long loop micros -237

10924.2948 INT free 243192
10924.2966 INT largest 200692
10924.2987 DMA free 235432
10924.3004 DMA largest 200692
10924.3022 PSRAM free 101552
10929.2716 T: 65000
10959.2714 T: 95000
10989.2716 T: 125000
11016.3048 long loop millis -33
11016.3054 long loop micros -32755
11016.3076 INT free 243192
11016.3096 INT largest 200692
11016.3118 DMA free 235432
11016.3134 DMA largest 200692
11016.3154 PSRAM free 101552
11019.3043 T: 155000
11049.3042 T: 185000
11067.6464 long loop millis -1797
11067.6491 long loop micros -1796726

void loop() {

uint32_t now = millis();
uint32_t nowAgain = millis();
int64_t nowMicros = esp_timer_get_time();

if (nowAgain < now) {
Serial.printf("RAW GLITCH: %lu then %lu (diff=%ld)\n", now, nowAgain, (int32_t)(nowAgain - now));
}

static uint32_t loopMillis = millis();
static int64_t loopMicros = esp_timer_get_time();

if ( now - loopMillis > 1000) {
Serial.printf("long loop millis %ld\n", (now - loopMillis) );
Serial.printf("long loop micros %ld\n", (int32_t)(nowMicros - loopMicros) );

Serial.printf("INT free %u\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL));
Serial.printf("INT largest %u\n", heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL));
Serial.printf("DMA free %u\n", heap_caps_get_free_size(MALLOC_CAP_DMA));
Serial.printf("DMA largest %u\n", heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
Serial.printf("PSRAM free %u\n", heap_caps_get_free_size(MALLOC_CAP_SPIRAM));
}

loopMillis = now;
loopMicros = nowMicros;