ESP32S3 fast 32bit and 64bit usec counters. Set/Get
Posted: Mon May 25, 2026 9:15 pm
Hello,
I'd like to share some of my findings which may be useful for others. These are specific to ESP32-S3.
Two alternatives to `esp_timer_get_time()`, with ability to set counter value.
This code is written fro Arduino framework fro simplicity but can be easily adopted for ESP-IDF.
MMIO registers used in the sketch are not documented in TRM but it is very likely that they will remain constants in future releases of ESP32-S3
Functions of interest: micros64(), setmicros64() and micros32()
Typical output:
I'd like to share some of my findings which may be useful for others. These are specific to ESP32-S3.
Two alternatives to `esp_timer_get_time()`, with ability to set counter value.
This code is written fro Arduino framework fro simplicity but can be easily adopted for ESP-IDF.
MMIO registers used in the sketch are not documented in TRM but it is very likely that they will remain constants in future releases of ESP32-S3
Functions of interest: micros64(), setmicros64() and micros32()
Code: Select all
// ESP32-S3 Microsecond Counters: 32/64-bit, read/write
//
// Two ways to get a microsecond timestamp:
//
// 1. Very fast, but returns only the lower 32 bits
// 2. Full 64-bit timestamp, slightly slower
//
// For simplicity, this example uses the Arduino framework.
//
// Setting the microsecond counter MAY interfere with WiFi TSF logic.
// Or maybe not - I have not tested it.
//
// WiFi does not need to be initialized to use these counters.
//
// vvb333007@gmail.com
//
#include <Arduino.h>
#include <stdint.h>
// Command register:
#define WIFI_TSF_CMD_REG (volatile uint32_t *)((uintptr_t)0x6003500c)
// Commands:
#define WIFI_TSFC_LATCH 0x01 // Latch current counter#0 (STA TSF counter) value into MMIO regs 0x18 and 0x1C
#define WIFI_TSFC_SET 0x10 // Set current counter#0 value from regs 0x10 and 0x14
// Latched 64-bit counter value.
// After issuing the LATCH command, these registers contain
// a snapshot of the current microsecond counter.
//
#define WIFI_TSF_HIGH_REG (volatile uint32_t *)((uintptr_t)0x6003501c)
#define WIFI_TSF_LOW_REG (volatile uint32_t *)((uintptr_t)0x60035018)
// Setter registers.
// Values written here are used when updating
// the current microsecond counter.
//
#define WIFI_TSF_SET_HIGH_REG (volatile uint32_t *)((uintptr_t)0x60035014)
#define WIFI_TSF_SET_LOW_REG (volatile uint32_t *)((uintptr_t)0x60035010)
// Free-running 32-bit microsecond counter.
// The simplest and fastest option.
//
#define WIFI_MICROS_REG (volatile uint32_t *)((uintptr_t)0x60035000)
// Fastest possible micros() implementation
//
static inline uint32_t micros32() {
return *WIFI_MICROS_REG;
}
// Full 64-bit microsecond timestamp.
//
// Create a snapshot, read two 32-bit values,
// and combine them into a 64-bit result.
//
uint64_t micros64() {
uint32_t low, high;
// Create snapshot
*WIFI_TSF_CMD_REG |= WIFI_TSFC_LATCH;
// Read latched values
low = *WIFI_TSF_LOW_REG;
high = *WIFI_TSF_HIGH_REG;
// Release latch
*WIFI_TSF_CMD_REG &= ~WIFI_TSFC_LATCH;
// Build 64-bit result
return (((uint64_t)high) << 32) | (uint64_t)low;
}
// Set the current microsecond counter value
//
void setmicros64(uint64_t val) {
*WIFI_TSF_SET_LOW_REG = (uint32_t)(val & 0xffffffffUL);
*WIFI_TSF_SET_HIGH_REG = (uint32_t)(val >> 32);
*WIFI_TSF_CMD_REG |= WIFI_TSFC_SET;
}
// Demo
//
void setup() {
Serial.begin(115200);
Serial.printf("\r\n\r\nESP32-S3 microsecond counters demo:\r\n");
}
// 1. Display both 64-bit and 32-bit counters once per second
// for a 10-second interval
//
// 2. Reset the 64-bit counter to zero
//
// 3. Repeat
//
void loop() {
for (int i = 0; i < 10; i++) {
Serial.printf("micros64 = %llu, micros32 = %lu\r\n", micros64(), micros32());
delay(1000);
}
Serial.printf("Resetting 64-bit counter to zero, keeping 32-bit running...\r\n");
setmicros64(0);
}Code: Select all
micros64 = 51010996, micros32 = 51010997
micros64 = 52010996, micros32 = 52010997
micros64 = 53010996, micros32 = 53010997
micros64 = 54010996, micros32 = 54010997
micros64 = 55010996, micros32 = 55010997
micros64 = 56010996, micros32 = 56010997
Resetting 64-bit counter to zero, keeping 32-bit running...
micros64 = 3, micros32 = 57011019
micros64 = 999981, micros32 = 58010997
micros64 = 1999981, micros32 = 59010997
micros64 = 2999981, micros32 = 60010997