使用需求是要抓 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 換算後來達到這樣的效果
謝謝!!