mcpwm capture module doesn't work after running for a while.

tonyjje
Posts: 1
Joined: Fri Mar 31, 2023 2:45 am

mcpwm capture module doesn't work after running for a while.

Postby tonyjje » Fri Mar 31, 2023 4:23 am

Hello everyone, I'm using a ESP32 board and developed a firmware to capture frequency input by mcpwm module from 2 sensor inputs channel.

It's usually working fine, but almost every time when I increase the input frequency from one of input channel, the mcpwm capture module just seems stopping working any more, at this moment I have to reboot to fix it.

here's the detail:

1. I use MCPWM_UNIT_0 module to capture two frequency input channel which are two GPIO pins, let's say FE1 and FE2. The initialization code looks like:

Code: Select all

mcpwm_pin_config_t FE12_config = {
        .mcpwm_cap0_in_num = FE1,
        .mcpwm_cap1_in_num = FE2,
};
mcpwm_set_pin(MCPWM_UNIT_0, &FE12_config);
mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, MCPWM_POS_EDGE, 0); // 0.5s
mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, MCPWM_POS_EDGE, 0);
MCPWM[MCPWM_UNIT_0]->int_ena.val = CAP0_INT_EN | CAP1_INT_EN;
mcpwm_isr_register(MCPWM_UNIT_0, isr_getfreq_handler, NULL, ESP_INTR_FLAG_EDGE, NULL); // Set ISR Handler
2. Inside the isr_getfreq_handler() code, I handle and measure the frequency each time it triggered.
Push the data into queue, just as:

Code: Select all

static void IRAM_ATTR isr_getfreq_handler()
{
    uint32_t mcpwm_intr_status;
    capture evt;
    mcpwm_intr_status = MCPWM[MCPWM_UNIT_0]->int_st.val; // Read interrupt status
    if (mcpwm_intr_status & CAP0_INT_EN) { // Check for interrupt on rising edge on CAP0 signal
        current_cap_value[0] = mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP0); // get capture signal counter value
        evt.capture_signal = (current_cap_value[0] - previous_cap_value[0]) * 0.0125;
        previous_cap_value[0] = current_cap_value[0];
        evt.sel_cap_signal = MCPWM_SELECT_CAP0;
        xQueueSendFromISR(capv_queue, &evt, NULL);
    }
    if (mcpwm_intr_status & CAP1_INT_EN) { // Check for interrupt on rising edge on CAP1 signal
        current_cap_value[1] = mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP1); // get capture signal counter value
        evt.capture_signal = (current_cap_value[1] - previous_cap_value[1]) * 0.0125;
        previous_cap_value[1] = current_cap_value[1];
        evt.sel_cap_signal = MCPWM_SELECT_CAP1;
        xQueueSendFromISR(capv_queue, &evt, NULL);
    }
    MCPWM[MCPWM_UNIT_0]->int_clr.val = mcpwm_intr_status;
}
3. I use another loop code to receive those data from queue in main task, just as:

Code: Select all

while (1) {
        // for test jje
        static uint32_t _count = 0;
        bool _log = false;
        if (++_count % 200 == 0) {
            _log = true;
        }
        if (_log) {
            ESP_LOGI(TAG, "[DEBUG] : GetFreq() called. wiht count cycle : %d", _count);
        }

        esp_task_wdt_reset(); // Comment this line to trigger a TWDT timeout
        // 双路测频
        if (xQueueReceive(capv_queue, &evt, 500)) {
            if (evt.sel_cap_signal == MCPWM_SELECT_CAP0) {
                ProcessValue.freq1 = 1.0 / (float)evt.capture_signal * 1000000;
                getFreq1 = 1;
                // for test jje
                if (_log) {
                    ESP_LOGI(TAG, "[DEBUG] : MCPWM_SELECT_CAP0 in GetFreq() called. wiht count cycle : %d", _count);
                }
            }
            if (evt.sel_cap_signal == MCPWM_SELECT_CAP1) {
                ProcessValue.freq2 = 1.0 / (float)evt.capture_signal * 1000000;
                getFreq2 = 1;
                // for test jje
                if (_log) {
                    ESP_LOGI(TAG, "[DEBUG] : MCPWM_SELECT_CAP1 in GetFreq() called. wiht count cycle : %d", _count);
                }
            }
        }
    }
I think above are all related codes, and I have several problems:

a. Normally, the frequency input from two GPIO input are the same, in this case, it works fine.

However, if I manually increase one of frequency making it much different than the others', let's say one input is set to 200 Hz and the other's increased to 500 - 1000 Hz, it will finally cause the isr_getfreq_handler() function does not work anymore. From that moment on, I have to reboot the device, otherwise, it will not recover even I decrease two input frequency to the same value.

The reason I think the isr_getfreq_handler() function has stopped working is that from the main while loop, it can't receive anything from queue.

b. When I try to add some log message within isr_getfreq_handler(), such as ESP_LOG() or printf(), it just cause a run-time crash which I have no idea why.

c. As you can see, in my main while loop, I use xQueueReceive(capv_queue, &evt, 500) function to get data from queue, however, I intentionally expect this function return in 500ms even there is no data from queue by passing 500 instead of max_delay. But seems that it blocks forever if the queue is empty, any idea?

Could some one kindly provide any idea or suggestion ? Thank you very much!

Who is online

Users browsing this forum: Gaston1980 and 134 guests