mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 09:01:40 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			255 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			9.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
 | 
						|
 *
 | 
						|
 * SPDX-License-Identifier: Apache-2.0
 | 
						|
 */
 | 
						|
#include <stdio.h>
 | 
						|
#include <inttypes.h>
 | 
						|
#include "freertos/FreeRTOS.h"
 | 
						|
#include "freertos/task.h"
 | 
						|
#include "freertos/event_groups.h"
 | 
						|
#include "unity.h"
 | 
						|
#include "soc/soc_caps.h"
 | 
						|
#include "esp_private/esp_clk.h"
 | 
						|
#include "driver/mcpwm_cap.h"
 | 
						|
#include "driver/mcpwm_sync.h"
 | 
						|
#include "driver/gpio.h"
 | 
						|
#include "test_mcpwm_utils.h"
 | 
						|
 | 
						|
TEST_CASE("mcpwm_capture_install_uninstall", "[mcpwm]")
 | 
						|
{
 | 
						|
    printf("install mcpwm capture timers\r\n");
 | 
						|
    mcpwm_capture_timer_config_t cap_timer_config = {
 | 
						|
        .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
 | 
						|
    };
 | 
						|
    int total_cap_timers = SOC_MCPWM_GROUPS * SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP;
 | 
						|
    mcpwm_cap_timer_handle_t cap_timers[total_cap_timers];
 | 
						|
    int k = 0;
 | 
						|
    for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
 | 
						|
        cap_timer_config.group_id = i;
 | 
						|
        for (int j = 0; j < SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP; j++) {
 | 
						|
            TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timers[k++]));
 | 
						|
        }
 | 
						|
        TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_capture_timer(&cap_timer_config, &cap_timers[0]));
 | 
						|
    }
 | 
						|
 | 
						|
    printf("install mcpwm capture channels\r\n");
 | 
						|
    mcpwm_capture_channel_config_t cap_chan_config = {
 | 
						|
        .gpio_num = 0,
 | 
						|
        .prescale = 2,
 | 
						|
        .flags.pos_edge = true,
 | 
						|
        .flags.pull_up = true,
 | 
						|
    };
 | 
						|
    mcpwm_cap_channel_handle_t cap_channels[total_cap_timers][SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER];
 | 
						|
    for (int i = 0; i < total_cap_timers; i++) {
 | 
						|
        for (int j = 0; j < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; j++) {
 | 
						|
            TEST_ESP_OK(mcpwm_new_capture_channel(cap_timers[i], &cap_chan_config, &cap_channels[i][j]));
 | 
						|
        }
 | 
						|
        TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_capture_channel(cap_timers[i], &cap_chan_config, &cap_channels[i][0]));
 | 
						|
    }
 | 
						|
 | 
						|
    printf("uninstall mcpwm capture channels and timers\r\n");
 | 
						|
    for (int i = 0; i < total_cap_timers; i++) {
 | 
						|
        for (int j = 0; j < SOC_MCPWM_CAPTURE_CHANNELS_PER_TIMER; j++) {
 | 
						|
            TEST_ESP_OK(mcpwm_del_capture_channel(cap_channels[i][j]));
 | 
						|
        }
 | 
						|
        TEST_ESP_OK(mcpwm_del_capture_timer(cap_timers[i]));
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
TEST_MCPWM_CALLBACK_ATTR
 | 
						|
static bool test_capture_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *edata, void *user_data)
 | 
						|
{
 | 
						|
    uint32_t *cap_value = (uint32_t *)user_data;
 | 
						|
    if (edata->cap_edge == MCPWM_CAP_EDGE_NEG) {
 | 
						|
        cap_value[1] = edata->cap_value;
 | 
						|
    } else {
 | 
						|
        cap_value[0] = edata->cap_value;
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("mcpwm_capture_ext_gpio", "[mcpwm]")
 | 
						|
{
 | 
						|
    printf("install mcpwm capture timer\r\n");
 | 
						|
    mcpwm_cap_timer_handle_t cap_timer = NULL;
 | 
						|
    mcpwm_capture_timer_config_t cap_timer_config = {
 | 
						|
        .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
 | 
						|
        .group_id = 0,
 | 
						|
    };
 | 
						|
    TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer));
 | 
						|
 | 
						|
    const int cap_gpio = 0;
 | 
						|
    // put the GPIO into a preset state
 | 
						|
    gpio_set_level(cap_gpio, 0);
 | 
						|
 | 
						|
    printf("install mcpwm capture channel\r\n");
 | 
						|
    mcpwm_cap_channel_handle_t pps_channel;
 | 
						|
    mcpwm_capture_channel_config_t cap_chan_config = {
 | 
						|
        .gpio_num = cap_gpio,
 | 
						|
        .prescale = 1,
 | 
						|
        .flags.pos_edge = true,
 | 
						|
        .flags.neg_edge = true,
 | 
						|
        .flags.io_loop_back = true, // so we can use GPIO functions to simulate the external capture signal
 | 
						|
        .flags.pull_up = true,
 | 
						|
    };
 | 
						|
    TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &pps_channel));
 | 
						|
 | 
						|
    printf("install callback for capture channel\r\n");
 | 
						|
    mcpwm_capture_event_callbacks_t cbs = {
 | 
						|
        .on_cap = test_capture_callback,
 | 
						|
    };
 | 
						|
    uint32_t cap_value[2] = {0};
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(pps_channel, &cbs, cap_value));
 | 
						|
 | 
						|
    printf("enable capture channel\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_enable(pps_channel));
 | 
						|
 | 
						|
    printf("enable and start capture timer\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
 | 
						|
 | 
						|
    printf("simulate GPIO capture signal\r\n");
 | 
						|
    gpio_set_level(cap_gpio, 1);
 | 
						|
    vTaskDelay(pdMS_TO_TICKS(100));
 | 
						|
    gpio_set_level(cap_gpio, 0);
 | 
						|
    vTaskDelay(pdMS_TO_TICKS(100));
 | 
						|
    printf("capture value: Pos=%"PRIu32", Neg=%"PRIu32"\r\n", cap_value[0], cap_value[1]);
 | 
						|
    uint32_t clk_src_res;
 | 
						|
    mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res);
 | 
						|
    TEST_ASSERT_UINT_WITHIN(100000, clk_src_res / 10, cap_value[1] - cap_value[0]);
 | 
						|
 | 
						|
    printf("uninstall capture channel and timer\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_disable(pps_channel));
 | 
						|
    TEST_ESP_OK(mcpwm_del_capture_channel(pps_channel));
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
 | 
						|
    TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
 | 
						|
}
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    uint32_t cap_data[2];
 | 
						|
    int cap_data_index;
 | 
						|
} test_soft_catch_user_data_t;
 | 
						|
 | 
						|
TEST_MCPWM_CALLBACK_ATTR
 | 
						|
static bool soft_cap_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *data, void *user_data)
 | 
						|
{
 | 
						|
    test_soft_catch_user_data_t *cbdata = (test_soft_catch_user_data_t *)user_data;
 | 
						|
    cbdata->cap_data[cbdata->cap_data_index++] = data->cap_value;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("mcpwm_capture_software_catch", "[mcpwm]")
 | 
						|
{
 | 
						|
    printf("install mcpwm capture timer\r\n");
 | 
						|
    mcpwm_cap_timer_handle_t cap_timer = NULL;
 | 
						|
    mcpwm_capture_timer_config_t cap_timer_config = {
 | 
						|
        .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
 | 
						|
        .group_id = 0,
 | 
						|
    };
 | 
						|
    TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer));
 | 
						|
 | 
						|
    printf("install mcpwm capture channel\r\n");
 | 
						|
    mcpwm_cap_channel_handle_t cap_channel = NULL;
 | 
						|
    mcpwm_capture_channel_config_t cap_chan_config = {
 | 
						|
        .gpio_num = -1, // don't need any GPIO, we use software to trigger a catch
 | 
						|
        .prescale = 2,
 | 
						|
    };
 | 
						|
    test_soft_catch_user_data_t test_callback_data = {};
 | 
						|
    TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel));
 | 
						|
 | 
						|
    TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_capture_channel_trigger_soft_catch(cap_channel));
 | 
						|
 | 
						|
    printf("register event callback for capture channel\r\n");
 | 
						|
    mcpwm_capture_event_callbacks_t cbs = {
 | 
						|
        .on_cap = soft_cap_callback,
 | 
						|
    };
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &test_callback_data));
 | 
						|
 | 
						|
    printf("enable capture channel\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel));
 | 
						|
 | 
						|
    printf("enable and start capture timer\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_enable(cap_timer));
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_start(cap_timer));
 | 
						|
 | 
						|
    printf("trigger software catch\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
 | 
						|
    vTaskDelay(pdMS_TO_TICKS(10));
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
 | 
						|
    vTaskDelay(pdMS_TO_TICKS(10));
 | 
						|
 | 
						|
    // check user data
 | 
						|
    TEST_ASSERT_EQUAL(2, test_callback_data.cap_data_index);
 | 
						|
    uint32_t delta = test_callback_data.cap_data[1] - test_callback_data.cap_data[0];
 | 
						|
    esp_rom_printf("duration=%u ticks\r\n", delta);
 | 
						|
    uint32_t clk_src_res;
 | 
						|
    mcpwm_capture_timer_get_resolution(cap_timer, &clk_src_res);
 | 
						|
    TEST_ASSERT_UINT_WITHIN(80000, clk_src_res / 100, delta);
 | 
						|
 | 
						|
    printf("uninstall capture channel and timer\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel));
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_disable(cap_timer));
 | 
						|
    TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
 | 
						|
    TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
 | 
						|
}
 | 
						|
 | 
						|
TEST_MCPWM_CALLBACK_ATTR
 | 
						|
static bool test_capture_after_sync_callback(mcpwm_cap_channel_handle_t cap_channel, const mcpwm_capture_event_data_t *data, void *user_data)
 | 
						|
{
 | 
						|
    uint32_t *cap_data = (uint32_t *)user_data;
 | 
						|
    *cap_data = data->cap_value;
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("mcpwm_capture_timer_sync_phase_lock", "[mcpwm]")
 | 
						|
{
 | 
						|
    mcpwm_capture_timer_config_t cap_timer_config = {
 | 
						|
        .group_id = 0,
 | 
						|
        .clk_src = MCPWM_CAPTURE_CLK_SRC_DEFAULT,
 | 
						|
    };
 | 
						|
    mcpwm_cap_timer_handle_t cap_timer = NULL;
 | 
						|
    TEST_ESP_OK(mcpwm_new_capture_timer(&cap_timer_config, &cap_timer));
 | 
						|
 | 
						|
    mcpwm_sync_handle_t soft_sync = NULL;
 | 
						|
    mcpwm_soft_sync_config_t soft_sync_config = {};
 | 
						|
    TEST_ESP_OK(mcpwm_new_soft_sync_src(&soft_sync_config, &soft_sync));
 | 
						|
 | 
						|
    mcpwm_capture_timer_sync_phase_config_t sync_config = {
 | 
						|
        .count_value = 1000,
 | 
						|
        .direction = MCPWM_TIMER_DIRECTION_UP,
 | 
						|
        .sync_src = soft_sync,
 | 
						|
    };
 | 
						|
    TEST_ESP_OK(mcpwm_capture_timer_set_phase_on_sync(cap_timer, &sync_config));
 | 
						|
 | 
						|
    mcpwm_cap_channel_handle_t cap_channel = NULL;
 | 
						|
    mcpwm_capture_channel_config_t cap_chan_config = {
 | 
						|
        .gpio_num = -1, // don't need any GPIO, we use software to trigger a catch
 | 
						|
        .prescale = 1,
 | 
						|
    };
 | 
						|
    TEST_ESP_OK(mcpwm_new_capture_channel(cap_timer, &cap_chan_config, &cap_channel));
 | 
						|
 | 
						|
    mcpwm_capture_event_callbacks_t cbs = {
 | 
						|
        .on_cap = test_capture_after_sync_callback,
 | 
						|
    };
 | 
						|
    uint32_t cap_data;
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_register_event_callbacks(cap_channel, &cbs, &cap_data));
 | 
						|
 | 
						|
    printf("enable capture channel\r\n");
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_enable(cap_channel));
 | 
						|
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
 | 
						|
    vTaskDelay(pdMS_TO_TICKS(10));
 | 
						|
    printf("capture data before sync: %"PRIu32"\r\n", cap_data);
 | 
						|
 | 
						|
    TEST_ESP_OK(mcpwm_soft_sync_activate(soft_sync));
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
 | 
						|
    vTaskDelay(pdMS_TO_TICKS(10));
 | 
						|
    printf("capture data after sync: %"PRIu32"\r\n", cap_data);
 | 
						|
    TEST_ASSERT_EQUAL(1000, cap_data);
 | 
						|
    TEST_ESP_OK(mcpwm_capture_channel_disable(cap_channel));
 | 
						|
    TEST_ESP_OK(mcpwm_del_capture_channel(cap_channel));
 | 
						|
    TEST_ESP_OK(mcpwm_del_capture_timer(cap_timer));
 | 
						|
    TEST_ESP_OK(mcpwm_del_sync_src(soft_sync));
 | 
						|
}
 |