SOLVED: MCPWM - cap_edge in interrupt callback is sometimes WRONG
Posted: Tue Feb 20, 2024 3:15 am
Hi, I've set up my ESP32 (WROVER board) to capture the rising and falling edges from a signal which is varying between 2 KHz and 4 KHz. I want to capture edge times and also whether the edge was rising or falling.
I have the code working, but the edge value (event_data->cap_edge) in the interrupt callback does not always seem to be correct!
Here's the code which sets up the MCPWM:
Here's the interrupt callback function (made really simple for testing). I have also set up the two GPIO pins as outputs so I can debug the input capture on a scope. As you can see, I set one debug pin to the "edge" value from cap_edge, and toggle the other debug pin to show that the interrupt handler was called.
The attached image shows a capture from a USB scope with this code running.
- Yellow trace is the input signal.
- White trace is GPIO_DEBUG_1 (supposed to be capture edge).
- Brown trace is GPIO_DEBUG_2 (toggled when the capture interrupt occurs).
The plot shows that the capture interrupt is occurring for each edge (brown trace toggles as expected), but sometimes the "edge" value doesn't change (i.e. it doesn't match the captured edge??) (White trace). Note that the shortest pulses are about 100 uS, and I have captured pulses down to about 2-3 uS in the past, so I don't think it's an interrupt latency problem.
The second plot shows another capture with more detail, so you can see the edge capture interrupt is being reliably called on rising and falling edges, but sometimes the "edge" value is wrong. The time between the cursors in the second plot is 92 uS.
What is going on here?
(ESP-IDF 5.1.2)
I have the code working, but the edge value (event_data->cap_edge) in the interrupt callback does not always seem to be correct!
Here's the code which sets up the MCPWM:
Code: Select all
void MCPWMInit(void)
{
mcpwm_capture_timer_config_t cap_conf =
{
.clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
.group_id = 0,
};
ESP_ERROR_CHECK( mcpwm_new_capture_timer(&cap_conf, &l_mcpwm_cap_timer) );
mcpwm_cap_channel_handle_t cap_chan = NULL;
mcpwm_capture_channel_config_t cap_ch_conf =
{
.gpio_num = GPIO_SIGNAL,
.intr_priority = 3, // 0 = Auto (low); Other options 1 - 3 (3 = highest).
.prescale = 1,
.flags.pos_edge = true,
.flags.neg_edge = true,
.flags.pull_up = false,
.flags.pull_down = true,
};
ESP_ERROR_CHECK( mcpwm_new_capture_channel(l_mcpwm_cap_timer, &cap_ch_conf, &cap_chan) );
TaskHandle_t cur_task = xTaskGetCurrentTaskHandle();
mcpwm_capture_event_callbacks_t cbs =
{
.on_cap = CaptureInterruptHandler,
};
ESP_ERROR_CHECK( mcpwm_capture_channel_register_event_callbacks(cap_chan, &cbs, cur_task) );
ESP_ERROR_CHECK( mcpwm_capture_channel_enable(cap_chan) );
}
Code: Select all
static bool IRAM_ATTR CaptureInterruptHandler(
mcpwm_cap_channel_handle_t cap_channel,
const mcpwm_capture_event_data_t *event_data,
void *user_ctx
)
{
UNUSED(cap_channel);
UNUSED(user_ctx);
gpio_set_level(GPIO_DEBUG_1, event_data->cap_edge);
static uint8_t dbg_toggle = 0;
gpio_set_level(GPIO_DEBUG_2, dbg_toggle);
dbg_toggle ^= 1;
return false;
}
- Yellow trace is the input signal.
- White trace is GPIO_DEBUG_1 (supposed to be capture edge).
- Brown trace is GPIO_DEBUG_2 (toggled when the capture interrupt occurs).
The plot shows that the capture interrupt is occurring for each edge (brown trace toggles as expected), but sometimes the "edge" value doesn't change (i.e. it doesn't match the captured edge??) (White trace). Note that the shortest pulses are about 100 uS, and I have captured pulses down to about 2-3 uS in the past, so I don't think it's an interrupt latency problem.
The second plot shows another capture with more detail, so you can see the edge capture interrupt is being reliably called on rising and falling edges, but sometimes the "edge" value is wrong. The time between the cursors in the second plot is 92 uS.
What is going on here?
(ESP-IDF 5.1.2)