Skip to content

Instantly share code, notes, and snippets.

@vvb333007
Created May 26, 2026 13:56
Show Gist options
  • Select an option

  • Save vvb333007/ff3ba9b73834309c67677a9f21fba129 to your computer and use it in GitHub Desktop.

Select an option

Save vvb333007/ff3ba9b73834309c67677a9f21fba129 to your computer and use it in GitHub Desktop.
Undocumented counters on ESP32-S3
// ESP32-S3 Microsecond Counters: 32/64-bit, read/write
// 4 full 64bit usec counters (read/write) and one 32 bit freerunning counter
//
// 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 counters MAY interfere with WiFi TSF logic.
// Or maybe not — I haven't 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)
# define WIFI_TSFC_LATCH 0x01 // Latch current counter value into MMIO regs 0x18 and 0x1C
# define WIFI_TSFC_SET 0x10 // Set current counter value from regs 0x10 and 0x14
// Counter Enable Registers (4 registers)
//
#define WIFI_TSF_EN_REG(_Counter) (volatile uint32_t *)((uintptr_t)(0x60035028 + _Counter * 0x0c))
# define WIFI_TSFE_ENABLE 0x98000000 // Enable flags (TODO: leave only required flags)
// 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(uint8_t counter) {
uint32_t low = 0, high = 0;
if (counter < 4) {
// Create snapshot
*WIFI_TSF_CMD_REG |= (WIFI_TSFC_LATCH << counter);
// Read latched values
low = *WIFI_TSF_LOW_REG;
high = *WIFI_TSF_HIGH_REG;
// Release latch
*WIFI_TSF_CMD_REG &= ~(WIFI_TSFC_LATCH << counter);
}
// Build 64-bit result
return (((uint64_t)high) << 32) | (uint64_t)low;
}
// Set the current microsecond counter value
//
void setmicros64(uint8_t counter, uint64_t val) {
if (counter < 4) {
*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 << counter);
}
}
// Enable/Disable counters
void micros64en(uint8_t counter, bool en) {
if (counter < 4) {
if (en) {
*WIFI_TSF_EN_REG(counter) |= WIFI_TSFE_ENABLE;
} else {
*WIFI_TSF_EN_REG(counter) &= ~WIFI_TSFE_ENABLE;
}
}
}
// Demo
//
void setup() {
Serial.begin(115200);
delay(300);
Serial.printf("\r\n\r\nESP32-S3 microsecond counters demo:\r\n");
//micros64en(0, true); // Works on its own from the start. May be it is a good idea to call enable on this one too
micros64en(1, true);
micros64en(2, true);
micros64en(3, true);
}
// 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 / %llu / %llu / %llu\r\n", micros64(0), micros64(1), micros64(2), micros64(3) );
delay(1000);
}
Serial.printf("Resetting 64-bit counters 1 and 3 to zero, keeping 32-bit running...\r\n");
setmicros64(1, 0);
setmicros64(3, 0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment