# TraxProbe Xtensa Port (Espressif ESP32 / ESP32-S2 / ESP32-S3)

Hardware abstraction for Espressif Xtensa LX6/LX7 SoCs running under
**ESP-IDF** (FreeRTOS). Selected with `TRAX_CFG_HW_PORT = TRAX_HW_PORT_XTENSA`
in `trax_config.h`.

## Files

```
hw_port/Xtensa/
├── include/
│   └── trax_hw_port.h    # critical section, core id, timestamp macros
├── src/
│   └── trax_hw_port.c    # the single shared SMP spinlock object
└── README.md
```

> Unlike the header-only ARM/Zynq ports, this port has a `.c` file. It must be
> added to the build (it is listed in the ESP-IDF component `CMakeLists.txt`).
> The `.c` exists solely to define one process-wide spinlock; a header-local
> `static` would give every translation unit its own lock and break SMP mutual
> exclusion.

## What it provides

| Concern | Implementation | Why |
|---------|----------------|-----|
| Critical section | `portENTER_CRITICAL_SAFE` / `portEXIT_CRITICAL_SAFE` on a shared `portMUX_TYPE` | SMP-safe: masks local IRQs **and** takes a spinlock so the other core can't race the ringbuffer. Works from task or ISR context. |
| Core id | `xPortGetCoreID()` | Tags frames with the originating core (0/1) so the host lands them on the correct swimlane. Pair with `TRAX_CFG_CORE_COUNT = 2`. |
| Timestamp | FREERUN over `esp_timer_get_time()` (SYSTIMER) | SYSTIMER is system-wide and coherent across both cores. The per-core CCOUNT cycle counter is intentionally avoided — it is not synchronized between cores. |

## Required `trax_config.h` settings

```c
#define TRAX_CFG_HW_PORT              TRAX_HW_PORT_XTENSA
#define TRAX_CFG_CORE_COUNT           2U              /* ESP32-S3 dual-core */
#define TRAX_CFG_TIMESTAMP_MODE       TRAX_TIMESTAMP_FREERUN
#define TRAX_CFG_TIMESTAMP_TIMER_DIR  TRAX_TIMER_DIR_UP
#define TRAX_CFG_TIMER_FREQ_HZ        1000000U        /* esp_timer is 1 MHz */
/* TICK_BITS defaults to 8 → [tick:8][fine:24]; do NOT set TICK_COUNTER_PERIOD */
```

Call `trax_timestamp_poll()` from the main loop (or a periodic task) so the
32-bit counter-wrap tracking stays current.

## Resolution note

`esp_timer_get_time()` gives 1 µs resolution — ample for logs/vars and for
bring-up. For sub-microsecond ISR timing, replace `TRAX_HW_PORT_FREERUN_COUNTER`
with a direct 16 MHz SYSTIMER unit read and set `TRAX_CFG_TIMER_FREQ_HZ` to
`16000000U`.
