Need Working Example for MCPWM Capture (or RMT) to Measure Frequency on GPIO36 – ESP32-WROOM32 / ESP-IDF v5.2.5
Posted: Tue Jun 03, 2025 12:59 am
Hi everyone,
I’m stuck trying to measure the frequency of a digital pulse signal on GPIO36 of an ESP32-WROOM32 (ESP-IDF v5.2.5). I hoped to use the MCPWM capture mode, but after days with the official docs and scattered snippets I still don’t have a working solution—and I haven’t found any up-to-date example code.
What I need
I first tried the PCNT peripheral: every 500 ms I read the pulse count and divide by the window. That’s too coarse at low frequencies (e.g. at 10 Hz I see only ≈5 pulses in 0.5 s, giving ±10–20 % error). I need sub-1 % accuracy across the range, so I’d rather measure the period between edges in hardware—hence MCPWM capture (or RMT if that’s simpler).
What I tried (and where it fails)
1 - MCPWM capture
What I’m asking for
1 - A minimal, self-contained code snippet that
3 - If MCPWM capture simply isn’t the right tool, I’m open to an RMT-based approach—just need a working example.
Thank you in advance! Any pointers, code, or even partial examples would be greatly appreciated.
I’m stuck trying to measure the frequency of a digital pulse signal on GPIO36 of an ESP32-WROOM32 (ESP-IDF v5.2.5). I hoped to use the MCPWM capture mode, but after days with the official docs and scattered snippets I still don’t have a working solution—and I haven’t found any up-to-date example code.
What I need
- Signal: square-wave on GPIO36
- Frequency range: 10 Hz – 1 kHz
- Edge: rising edge is fine (falling or both would also work)
- Task context: runs every 500 ms (void taskCalcFlowmetterPulses(void *pvParameters))
- Output: update a global volatile float frequency with at least two decimal places of precision
- Project constraints: no other timers or peripherals compete for GPIO36; I’m free to pick MCPWM capture channel, timer, etc.
I first tried the PCNT peripheral: every 500 ms I read the pulse count and divide by the window. That’s too coarse at low frequencies (e.g. at 10 Hz I see only ≈5 pulses in 0.5 s, giving ±10–20 % error). I need sub-1 % accuracy across the range, so I’d rather measure the period between edges in hardware—hence MCPWM capture (or RMT if that’s simpler).
What I tried (and where it fails)
1 - MCPWM capture
- Routed GPIO36 to MCPWM_UNIT_0, MCPWM_CAP_0.
- Configured .cap_edge = MCPWM_POS_EDGE, .cap_prescale = 1.
- ISR collects timestamps, task averages periods.
- Result: driver throws ESP_ERR_INVALID_ARG on mcpwm_new_capture_channel() if I follow examples for older IDF versions, or the callback never fires if I adapt to new struct names. I suspect I’m still mis-configuring something.
What I’m asking for
1 - A minimal, self-contained code snippet that
- configures MCPWM (or RMT, if that’s preferred) to capture rising edges on GPIO36,
- runs inside a FreeRTOS task every 500 ms,
- updates float frequency with real-time frequency (≥2 decimals).
3 - If MCPWM capture simply isn’t the right tool, I’m open to an RMT-based approach—just need a working example.
Thank you in advance! Any pointers, code, or even partial examples would be greatly appreciated.