請問 MCPWM capture function 相關使用問題!!

YutingLin
Posts: 12
Joined: Wed Dec 12, 2018 6:14 am

請問 MCPWM capture function 相關使用問題!!

Postby YutingLin » Thu Jan 17, 2019 3:10 am

請問

使用需求是要抓 GPIO Low 訊號的時間加總,需精準到 us
我使用 mcpwm_basic_config_example.c 範例當中 MCPWM_EN_CAPTURE 功能

經實測後發現
雖然是 Enable 成 Falling edge(negative) 觸發
mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, MCPWM_NEG_EDGE, 0)

但不管設成 Falling(negative) 還是 Rising edge(positive)

當有正負緣訊號時 isr_handler 都會觸發
不知為何 LIB 會是寫成這樣的效果??

能理解 sample code 的動作方式
紀錄每次觸發的時間
然後將目前時間 - 前一次紀錄時間 = 此次訊號寬度時間(這有可能是 High 的時間,也有可能是 Low 的時間)

是我的使用方式有錯誤嗎???

Code: Select all

static void mcpwm_example_gpio_initialize()
{
    printf("initializing mcpwm gpio...\n");

    mcpwm_pin_config_t pin_config = {
        .mcpwm_cap0_in_num   = GPIO_CAP0_IN,
		.mcpwm_cap1_in_num   = GPIO_CAP1_IN,
    };
    mcpwm_set_pin(MCPWM_UNIT_0, &pin_config);

    gpio_pulldown_en(GPIO_CAP0_IN);    //Enable pull down on CAP0   signal
    gpio_pulldown_en(GPIO_CAP1_IN);    //Enable pull down on CAP1   signal
}

/**
 * @brief When interrupt occurs, we receive the counter value and display the time between two rising edge
 */
static void disp_captured_signal(void *arg)
{
    uint32_t *current_cap_value = (uint32_t *)malloc(sizeof(CAP_SIG_NUM));
    uint32_t *previous_cap_value = (uint32_t *)malloc(sizeof(CAP_SIG_NUM));
    uint32_t tempvalue;
    capture evt;

    uint8_t		pm2_5_level_flag = 1, pm10_level_flag = 1;
    uint32_t	pm2_5_low_level_time = 0, pm10_low_level_time = 0;

    while (1) {
    	xQueueReceive(cap_queue, &evt, portMAX_DELAY);
        if (evt.sel_cap_signal == MCPWM_SELECT_CAP0) {
            current_cap_value[0] = evt.capture_signal - previous_cap_value[0];
            previous_cap_value[0] = evt.capture_signal;
            current_cap_value[0] = (current_cap_value[0] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
            printf("CAP0 : %d us - %d\n", current_cap_value[0], mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP0));
            tempvalue = (evt.capture_signal / 10000) * (10000000000 / rtc_clk_apb_freq_get());
        }
        if (evt.sel_cap_signal == MCPWM_SELECT_CAP1) {
            current_cap_value[1] = evt.capture_signal - previous_cap_value[1];
            previous_cap_value[1] = evt.capture_signal;
            current_cap_value[1] = (current_cap_value[1] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
            printf("CAP1 : %d us - %d\n", current_cap_value[1], mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP1));
            tempvalue = (evt.capture_signal / 10000) * (10000000000 / rtc_clk_apb_freq_get());
		}
        if (evt.sel_cap_signal == MCPWM_SELECT_CAP2) {
            current_cap_value[2] = evt.capture_signal -  previous_cap_value[2];
            previous_cap_value[2] = evt.capture_signal;
            current_cap_value[2] = (current_cap_value[2] / 10000) * (10000000000 / rtc_clk_apb_freq_get());
            printf("CAP2 : %d us\n", current_cap_value[2]);
        }
    }
}

/**
 * @brief this is ISR handler function, here we check for interrupt that triggers rising edge on CAP0 signal and according take action
 */
static void IRAM_ATTR isr_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
    	evt.capture_signal = mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP0); //get capture signal counter value
		evt.sel_cap_signal = MCPWM_SELECT_CAP0;
		xQueueSendFromISR(cap_queue, &evt, NULL);
    }
    if (mcpwm_intr_status & CAP1_INT_EN) { //Check for interrupt on rising edge on CAP1 signal
    	evt.capture_signal = mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP1); //get capture signal counter value
		evt.sel_cap_signal = MCPWM_SELECT_CAP1;
		xQueueSendFromISR(cap_queue, &evt, NULL);
    }
    MCPWM[MCPWM_UNIT_0]->int_clr.val = mcpwm_intr_status;
}

/**
 * @brief Configure whole MCPWM module
 */
static void mcpwm_example_config(void *arg)
{
    //1. mcpwm gpio initialization
    mcpwm_example_gpio_initialize();

    //7. Capture configuration
    //comment if you don't want to use capture submodule, also u can comment the capture gpio signals
    //configure CAP0, CAP1 and CAP2 signal to start capture counter on rising edge
    //we generate a gpio_test_signal of 20ms on GPIO 12 and connect it to one of the capture signal, the disp_captured_function displays the time between rising edge
    //In general practice you can connect Capture  to external signal, measure time between rising edge or falling edge and take action accordingly
    mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP0, MCPWM_NEG_EDGE, 0);  //capture signal on rising edge, prescale = 0 i.e. 800,000,000 counts is equal to one second
    mcpwm_capture_enable(MCPWM_UNIT_0, MCPWM_SELECT_CAP1, MCPWM_NEG_EDGE, 0);  //capture signal on rising edge, prescale = 0 i.e. 800,000,000 counts is equal to one second

    //enable interrupt, so each this a rising edge occurs interrupt is triggered
    MCPWM[MCPWM_UNIT_0]->int_ena.val = CAP0_INT_EN | CAP1_INT_EN;  //Enable interrupt on  CAP0, CAP1 and CAP2 signal
    mcpwm_isr_register(MCPWM_UNIT_0, isr_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);  //Set ISR Handler

    vTaskDelete(NULL);
}


void pwm_app_main()
{
    printf("Testing MCPWM...\n");
    cap_queue = xQueueCreate(1, sizeof(capture)); //comment if you don't want to use capture module
    xTaskCreate(disp_captured_signal, "mcpwm_config", 4096, NULL, 5, NULL);  //comment if you don't want to use capture module
    xTaskCreate(mcpwm_example_config, "mcpwm_example_config", 4096, NULL, 5, NULL);
}
這樣的狀況我完全無法使用
放棄想自己 polling 偵測 GPIO High Low 的方式處理

但又遇到一個問題
我要如何去取得系統時間 1us 的 count 計數??
網路上找了一兩天也沒啥頭緒

以範例中的計算公式來看
(current_cap_value[1] / 10000) * (10000000000 / rtc_clk_apb_freq_get());

current_cap_value[1] 是由 isr_handler() 觸發之後 mcpwm_capture_signal_get_value(MCPWM_UNIT_0, MCPWM_SELECT_CAP0); 所取得的一個不知道是啥,可能是一個系統時間的 count 值
rtc_clk_apb_freq_get() 我確認過是 80M
為什麼要除 10000 又要再乘 (10000000000 / rtc_clk_apb_freq_get()) 完全無法理解

想請問我要如何取得 1us 的 system count 數
或是說如何自己寫個 function 在不使用 Timer 用一些系統 counter 換算後來達到這樣的效果

謝謝!!

YutingLin
Posts: 12
Joined: Wed Dec 12, 2018 6:14 am

Re: 請問 MCPWM capture function 相關使用問題!!

Postby YutingLin » Thu Jan 17, 2019 9:14 am

無意間在搜尋 LIB 相關內容的時候
發現了一個 system 1us count 的 function
目前使用 B 方案,create 一個 Task Polling 判斷 GPIO 的 High Low 狀態
來達到我想要的需求
提供給大家參考

#include "esp_clk.h"

uint64_t get_rtc_time_us()
{
const uint64_t ticks = rtc_time_get();
const uint32_t cal = esp_clk_slowclk_cal_get();
/* RTC counter result is up to 2^48, calibration factor is up to 2^24,
* for a 32kHz clock. We need to calculate (assuming no overflow):
* (ticks * cal) >> RTC_CLK_CAL_FRACT
*
* An overflow in the (ticks * cal) multiplication would cause time to
* wrap around after approximately 13 days, which is probably not enough
* for some applications.
* Therefore multiplication is split into two terms, for the lower 32-bit
* and the upper 16-bit parts of "ticks", i.e.:
* ((ticks_low + 2^32 * ticks_high) * cal) >> RTC_CLK_CAL_FRACT
*/
const uint64_t ticks_low = ticks & UINT32_MAX;
const uint64_t ticks_high = ticks >> 32;
return ((ticks_low * cal) >> RTC_CLK_CAL_FRACT) +
((ticks_high * cal) << (32 - RTC_CLK_CAL_FRACT));
}

此 function 雖在 LIB timer.c 裏
但無法直接呼叫使用
我是 copy 到我的專案黨內使用
並且要 include esp_clk.h

建議 A 方案
使用 MCPWM capture function 的方式改良一下
(也或許是我對於此 sample code 的使用理解錯誤)

謝謝!!

ESP_houwenxiang
Posts: 118
Joined: Tue Jun 26, 2018 3:09 am

Re: 請問 MCPWM capture function 相關使用問題!!

Postby ESP_houwenxiang » Wed Feb 13, 2019 6:42 am

Hi,
目前 IDF 中 MCPWM 只能是上升沿或下降沿会触发一次测量. 你遇到的问题是 两个边沿都会产生中断吗?这种现象是不正常的,请检查信号是否有干扰. 另一个问题是你需要测量输入信号低电平持续的时间吗?

thanks !!
wookooho

Who is online

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