ESP32 interrupts can only do 200khz!

Hayden Dekker
3 min readFeb 8, 2022

--

A deep dive into the ESP32, the IDF and docs, hoping it can perform better.

Andreas Spiess made a great video on the ESP32 Interrupts but at the 8:40 marker a horrible discovery is made, the ESP32 has an interrupt latency of 2us and is even unstable at times!

Andreas is an absolute legend and his channel one of the great embedded programs going around so this article isn’t intending on proving him wrong but rather hoping that the ESP interrupt performance is better a microsecond!

TLDR; can achieve 10x better.

Methods

Andreas’s test method uses the ESP32 SDK via Arduino IDE. Using the SDK indeed does restrict the interrupt bandwidth to around 200khz. I suspect the latency comes from the SDK, in the management of interrupt handlers.

This method will utilise the ESP32 memory directly inside a high-level interrupt. Surely that will do the trick. I’ll use the same test setup as Andreas, that is, a signal generator triggers an interrupt on a GPIO, and that interrupt sets toggles the value of an output pin.

UNIT-T — UTG962E function generator setup

ESP IDF / SDK

A quick note on the SDK/IDF and how that utilises the physical processor. The IDF uses layers of code so that consistency in the programming interface can be achieved across the range of ESP32 silicon. The final layer links to a specific ESP target at compile time and it’s this layer that maps to the physical device.

For an example, let’s look at the function gpio_set_level(), here. The SDK first calls the HAL equivalent function, that hal function refers to the specific silicon implementation “hal_II”, and that implementation then writes to the memory associated with the GPIO PIN.

Note the register being written to hw->out1_w1ts/c, If we look at the technical reference manual, here, in the section on GPIO we see the following,

ESP32 Technical Reference Manual — GPIO register mapping

The address of GPIO_OUT_W1TS_REG is given and allows write only access. As a test try printing the address of the GPIO structure hw->out1_w1ts at runtime. You’ll see they correspond to the above values.

The ESP32 Technical Manual can be trusted and provides the best source of truth for the ESP32 capability. I find it useful to manually trace the IDF code to the function end to view the registers used to access the memory mapped peripherals and from there I can cross reference those against the TRM to consolidate my understanding.

Writing the Assembly IRQ

Here’s what you need to know in order to write your own low-latency high level interrupt.

You can find my test repo, here, with the full assembly IRQ.

There are two parts to this program, the c. and the .S, with the .S holding the IRQ.

ESP32 uses xtensa architecture. We need this document here to assist in writing the IRQ. The relevant section is that on instruction set and for this IRQ we only need a few easy to use instructions; MOVI, L32I, S32I, and XOR. Luckily if you’re unfamiliar the architecture reference goes into great depth on all instructions.

And the ESP reference guides document setup and use of the HLI, here.

Make sure you’ve linked correctly, as described in the above HLI link. The definitive way is to look for the symbol in the build/*.map file. Open and search for the symbol and make sure your document has been linked. If not you need to adjust your make file.

Outcome

Nice and steady

We can see that to set and clear takes only 64ns or 15MHZ, half period.

And from external interrupt to setting the output value, 325ns or 3MHZ!!

Perfect!

--

--

Hayden Dekker

Systems Engineer building a new CBTC train line for Melbourne Australia. Weekends spent head in the cloud programming or embedded in the garden. Pun intended.