SOLVED: MCPWM - cap_edge in interrupt callback is sometimes WRONG

jcolebaker
Posts: 64
Joined: Thu Mar 18, 2021 12:23 am

SOLVED: MCPWM - cap_edge in interrupt callback is sometimes WRONG

Postby jcolebaker » 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:

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) );
}
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.

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;
}
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)
Input_Capture_Incorrect_Edges.png
Input_Capture_Incorrect_Edges.png (24.97 KiB) Viewed 1079 times
Input_Capture_Incorrect_Edges_Detail.png
Input_Capture_Incorrect_Edges_Detail.png (16.19 KiB) Viewed 1074 times
Last edited by jcolebaker on Thu Feb 22, 2024 11:02 pm, edited 2 times in total.

MicroController
Posts: 1696
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: MCPWM - cap_edge in interrupt callback is sometimes WRONG

Postby MicroController » Tue Feb 20, 2024 6:42 pm

I imagine the long rise/fall times (20us?) of your signal might be causing glitches.

jcolebaker
Posts: 64
Joined: Thu Mar 18, 2021 12:23 am

Re: MCPWM - cap_edge in interrupt callback is sometimes WRONG

Postby jcolebaker » Thu Feb 22, 2024 11:01 pm

Hi. Thanks for the reply. Yes, I think you are correct. I'm guessing that there is some small noise in the signal which causes the edge capture input to trigger several times when it is close to the threshold, e.g. instead of just Low -> High, it goes Low -> High -> Low -> High. Each of these capture triggers latches the counter and edge type to the latch registers. The timing of the interrupt processing must be such that it happens to sometimes read the latch registers at the time when the (temporary / incorrect) falling edge has been latched even though the original / correct trigger was a rising edge.

I guess there is some hysteresis in the input pin measurement to prevent this, but perhaps not enough for the low slew rate I have in this signal. However, I could not find any specification for hysteresis or minimum slew rates in the data sheet or reference manual.

An easy work-around is to sample the pin value from the interrupt handler. This requires a few extra clock ticks, and still relies on timing (i.e. the signal needs to have passed the stable threshold point by the time we read the value in the callback) but it worked well for my signal.

MicroController
Posts: 1696
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: SOLVED: MCPWM - cap_edge in interrupt callback is sometimes WRONG

Postby MicroController » Sun Feb 25, 2024 11:37 am

I guess there is some hysteresis in the input pin measurement to prevent this, but perhaps not enough for the low slew rate I have in this signal. However, I could not find any specification for hysteresis or minimum slew rates in the data sheet or reference manual.
AFAIK, the ESP's don't have any 'input shaping' circuitry (Schmitt triggers,...), so there is no defined hysteresis.
The newer ESP's have synchronization logic in their IO block which can be configured/used as a glitch filter though, which could help.

Who is online

Users browsing this forum: Google [Bot] and 78 guests