mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
mcpwm: new driver implementation
This commit is contained in:
18
components/driver/test_apps/mcpwm/CMakeLists.txt
Normal file
18
components/driver/test_apps/mcpwm/CMakeLists.txt
Normal file
@@ -0,0 +1,18 @@
|
||||
# This is the project CMakeLists.txt file for the test subproject
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(mcpwm_test)
|
||||
|
||||
if(CONFIG_COMPILER_DUMP_RTL_FILES)
|
||||
add_custom_target(check_test_app_sections ALL
|
||||
COMMAND ${PYTHON} $ENV{IDF_PATH}/tools/ci/check_callgraph.py
|
||||
--rtl-dir ${CMAKE_BINARY_DIR}/esp-idf/driver/
|
||||
--elf-file ${CMAKE_BINARY_DIR}/mcpwm_test.elf
|
||||
find-refs
|
||||
--from-sections=.iram0.text
|
||||
--to-sections=.flash.text,.flash.rodata
|
||||
--exit-code
|
||||
DEPENDS ${elf}
|
||||
)
|
||||
endif()
|
2
components/driver/test_apps/mcpwm/README.md
Normal file
2
components/driver/test_apps/mcpwm/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
| Supported Targets | ESP32 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- |
|
14
components/driver/test_apps/mcpwm/main/CMakeLists.txt
Normal file
14
components/driver/test_apps/mcpwm/main/CMakeLists.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
set(srcs "test_app_main.c"
|
||||
"test_mcpwm_cap.c"
|
||||
"test_mcpwm_cmpr.c"
|
||||
"test_mcpwm_fault.c"
|
||||
"test_mcpwm_gen.c"
|
||||
"test_mcpwm_oper.c"
|
||||
"test_mcpwm_sync.c"
|
||||
"test_mcpwm_timer.c"
|
||||
"test_mcpwm_utils.c")
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
|
||||
# the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRCS ${srcs}
|
||||
WHOLE_ARCHIVE)
|
51
components/driver/test_apps/mcpwm/main/test_app_main.c
Normal file
51
components/driver/test_apps/mcpwm/main/test_app_main.c
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "unity.h"
|
||||
#include "unity_test_runner.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
// Some resources are lazy allocated in GPTimer driver, the threshold is left for that case
|
||||
#define TEST_MEMORY_LEAK_THRESHOLD (-300)
|
||||
|
||||
static size_t before_free_8bit;
|
||||
static size_t before_free_32bit;
|
||||
|
||||
static void check_leak(size_t before_free, size_t after_free, const char *type)
|
||||
{
|
||||
ssize_t delta = after_free - before_free;
|
||||
printf("MALLOC_CAP_%s: Before %u bytes free, After %u bytes free (delta %d)\n", type, before_free, after_free, delta);
|
||||
TEST_ASSERT_MESSAGE(delta >= TEST_MEMORY_LEAK_THRESHOLD, "memory leak");
|
||||
}
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
before_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
before_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
}
|
||||
|
||||
void tearDown(void)
|
||||
{
|
||||
size_t after_free_8bit = heap_caps_get_free_size(MALLOC_CAP_8BIT);
|
||||
size_t after_free_32bit = heap_caps_get_free_size(MALLOC_CAP_32BIT);
|
||||
check_leak(before_free_8bit, after_free_8bit, "8BIT");
|
||||
check_leak(before_free_32bit, after_free_32bit, "32BIT");
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
// __ __ ____ ______ ____ __ _____ _
|
||||
// | \/ |/ ___| _ \ \ / / \/ | |_ _|__ ___| |_
|
||||
// | |\/| | | | |_) \ \ /\ / /| |\/| | | |/ _ \/ __| __|
|
||||
// | | | | |___| __/ \ V V / | | | | | | __/\__ \ |_
|
||||
// |_| |_|\____|_| \_/\_/ |_| |_| |_|\___||___/\__|
|
||||
printf(" __ __ ____ ______ ____ __ _____ _\r\n");
|
||||
printf("| \\/ |/ ___| _ \\ \\ / / \\/ | |_ _|__ ___| |_\r\n");
|
||||
printf("| |\\/| | | | |_) \\ \\ /\\ / /| |\\/| | | |/ _ \\/ __| __|\r\n");
|
||||
printf("| | | | |___| __/ \\ V V / | | | | | | __/\\__ \\ |_\r\n");
|
||||
printf("|_| |_|\\____|_| \\_/\\_/ |_| |_| |_|\\___||___/\\__|\r\n");
|
||||
unity_run_menu();
|
||||
}
|
238
components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c
Normal file
238
components/driver/test_apps/mcpwm/main/test_mcpwm_cap.c
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include <stdio.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_APB,
|
||||
.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 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=%u, Neg=%u\r\n", cap_value[0], cap_value[1]);
|
||||
// Capture timer is clocked from APB by default
|
||||
uint32_t clk_src_res = esp_clk_apb_freq();
|
||||
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_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));
|
||||
|
||||
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 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);
|
||||
// Capture timer is clocked from APB by default
|
||||
uint32_t clk_src_res = esp_clk_apb_freq();
|
||||
TEST_ASSERT_UINT_WITHIN(80000, clk_src_res / 100, delta);
|
||||
|
||||
printf("uninstall capture channel and timer\r\n");
|
||||
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));
|
||||
|
||||
TEST_ESP_OK(mcpwm_capture_channel_trigger_soft_catch(cap_channel));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
printf("capture data before sync: %u\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: %u\r\n", cap_data);
|
||||
TEST_ASSERT_EQUAL(1000, cap_data);
|
||||
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));
|
||||
}
|
113
components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c
Normal file
113
components/driver/test_apps/mcpwm/main/test_mcpwm_cmpr.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/mcpwm_timer.h"
|
||||
#include "driver/mcpwm_oper.h"
|
||||
#include "driver/mcpwm_cmpr.h"
|
||||
|
||||
TEST_CASE("mcpwm_comparator_install_uninstall", "[mcpwm]")
|
||||
{
|
||||
mcpwm_timer_handle_t timer;
|
||||
mcpwm_oper_handle_t operator;
|
||||
mcpwm_cmpr_handle_t comparators[SOC_MCPWM_COMPARATORS_PER_OPERATOR];
|
||||
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.period_ticks = 10 * 1000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
printf("install timer and operator");
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
|
||||
printf("install comparator\r\n");
|
||||
mcpwm_comparator_config_t comparator_config = {};
|
||||
for (int i = 0; i < SOC_MCPWM_COMPARATORS_PER_OPERATOR; i++) {
|
||||
TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparators[i]));
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_comparator(operator, &comparator_config, &comparators[0]));
|
||||
|
||||
printf("connect MCPWM timer and operators\r\n");
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
printf("uninstall timer, operator and comparators\r\n");
|
||||
// can't delete operator if the comparators are still in working
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_del_operator(operator));
|
||||
for (int i = 0; i < SOC_MCPWM_COMPARATORS_PER_OPERATOR; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparators[i]));
|
||||
}
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
static bool test_compare_on_reach(mcpwm_cmpr_handle_t cmpr, const mcpwm_compare_event_data_t *ev_data, void *user_data)
|
||||
{
|
||||
uint32_t *counts = (uint32_t *)user_data;
|
||||
(*counts)++;
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_comparator_event_callback", "[mcpwm]")
|
||||
{
|
||||
mcpwm_timer_handle_t timer;
|
||||
mcpwm_oper_handle_t operator;
|
||||
mcpwm_cmpr_handle_t comparator;
|
||||
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.period_ticks = 10 * 1000, // 10ms
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_comparator_config_t comparator_config = {};
|
||||
printf("install timer, operator and comparator");
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator));
|
||||
|
||||
// set compare value before connecting timer and operator will fail
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_comparator_set_compare_value(comparator, 5000));
|
||||
printf("connect MCPWM timer and operators\r\n");
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
// compare ticks can't exceed the timer's period ticks
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_comparator_set_compare_value(comparator, 20 * 1000));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator, 5 * 1000));
|
||||
|
||||
printf("register compare event callback\r\n");
|
||||
uint32_t compare_counts = 0;
|
||||
mcpwm_comparator_event_callbacks_t cbs = {
|
||||
.on_reach = test_compare_on_reach,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_comparator_register_event_callbacks(comparator, &cbs, &compare_counts));
|
||||
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
printf("compare_counts=%u\r\n", compare_counts);
|
||||
// the timer period is 10ms, the expected compare_counts = 1s/10ms = 100
|
||||
TEST_ASSERT_INT_WITHIN(1, 100, compare_counts);
|
||||
|
||||
printf("uninstall timer, operator and comparator\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
93
components/driver/test_apps/mcpwm/main/test_mcpwm_fault.c
Normal file
93
components/driver/test_apps/mcpwm/main/test_mcpwm_fault.c
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "driver/mcpwm_fault.h"
|
||||
#include "driver/mcpwm_oper.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
TEST_CASE("mcpwm_fault_install_uninstall", "[mcpwm]")
|
||||
{
|
||||
printf("install and uninstall gpio faults\r\n");
|
||||
mcpwm_gpio_fault_config_t gpio_fault_config = {
|
||||
.gpio_num = 0,
|
||||
};
|
||||
int total_gpio_faults = SOC_MCPWM_GPIO_FAULTS_PER_GROUP * SOC_MCPWM_GROUPS;
|
||||
mcpwm_fault_handle_t gpio_faults[total_gpio_faults];
|
||||
int fault_itor = 0;
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
gpio_fault_config.group_id = i;
|
||||
for (int j = 0; j < SOC_MCPWM_GPIO_FAULTS_PER_GROUP; j++) {
|
||||
TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_fault_config, &gpio_faults[fault_itor++]));
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_gpio_fault(&gpio_fault_config, &gpio_faults[0]));
|
||||
}
|
||||
for (int i = 0; i < total_gpio_faults; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_fault(gpio_faults[i]));
|
||||
}
|
||||
|
||||
printf("install and uninstall software fault\r\n");
|
||||
mcpwm_soft_fault_config_t soft_fault_config = {};
|
||||
mcpwm_fault_handle_t soft_fault = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_soft_fault(&soft_fault_config, &soft_fault));
|
||||
TEST_ESP_OK(mcpwm_del_fault(soft_fault));
|
||||
}
|
||||
|
||||
static bool test_fault_enter_callback(mcpwm_fault_handle_t detector, const mcpwm_fault_event_data_t *status, void *user_data)
|
||||
{
|
||||
TaskHandle_t task_handle = (TaskHandle_t)user_data;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
esp_rom_printf("fault found\r\n");
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static bool test_fault_exit_callback(mcpwm_fault_handle_t detector, const mcpwm_fault_event_data_t *status, void *user_data)
|
||||
{
|
||||
TaskHandle_t task_handle = (TaskHandle_t)user_data;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
esp_rom_printf("fault relieved\r\n");
|
||||
vTaskNotifyGiveFromISR(task_handle, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_gpio_fault_event_callbacks", "[mcpwm]")
|
||||
{
|
||||
printf("create gpio fault\r\n");
|
||||
const int fault_gpio = 0;
|
||||
mcpwm_fault_handle_t fault = NULL;
|
||||
mcpwm_gpio_fault_config_t gpio_fault_config = {
|
||||
.group_id = 0,
|
||||
.gpio_num = fault_gpio,
|
||||
.flags.active_level = true, // active on high level
|
||||
.flags.pull_down = true,
|
||||
.flags.io_loop_back = true, // for debug, so that we can use gpio_set_level to mimic a fault source
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_fault_config, &fault));
|
||||
|
||||
// put fault GPIO into a safe state
|
||||
gpio_set_level(fault_gpio, 0);
|
||||
|
||||
printf("register callback for the gpio fault\r\n");
|
||||
mcpwm_fault_event_callbacks_t cbs = {
|
||||
.on_fault_enter = test_fault_enter_callback,
|
||||
.on_fault_exit = test_fault_exit_callback,
|
||||
};
|
||||
TaskHandle_t task_to_notify = xTaskGetCurrentTaskHandle();
|
||||
TEST_ESP_OK(mcpwm_fault_register_event_callbacks(fault, &cbs, task_to_notify));
|
||||
TEST_ASSERT_EQUAL(0, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(1000)));
|
||||
|
||||
printf("trigget a fault event\r\n");
|
||||
gpio_set_level(fault_gpio, 1);
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10)));
|
||||
|
||||
printf("remove the fault source\r\n");
|
||||
gpio_set_level(fault_gpio, 0);
|
||||
TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(10)));
|
||||
|
||||
TEST_ESP_OK(mcpwm_del_fault(fault));
|
||||
}
|
646
components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c
Normal file
646
components/driver/test_apps/mcpwm/main/test_mcpwm_gen.c
Normal file
@@ -0,0 +1,646 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/mcpwm_timer.h"
|
||||
#include "driver/mcpwm_oper.h"
|
||||
#include "driver/mcpwm_cmpr.h"
|
||||
#include "driver/mcpwm_gen.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
TEST_CASE("mcpwm_generator_install_uninstall", "[mcpwm]")
|
||||
{
|
||||
mcpwm_operator_config_t oper_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t oper = NULL;
|
||||
printf("create a MCPWM operator\r\n");
|
||||
TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper));
|
||||
|
||||
printf("create MCPWM generators from that operator\r\n");
|
||||
mcpwm_gen_handle_t gens[SOC_MCPWM_GENERATORS_PER_OPERATOR];
|
||||
mcpwm_generator_config_t gen_config = {
|
||||
.gen_gpio_num = 0,
|
||||
};
|
||||
for (int i = 0; i < SOC_MCPWM_GENERATORS_PER_OPERATOR; i++) {
|
||||
TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gens[i]));
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_generator(oper, &gen_config, &gens[0]));
|
||||
|
||||
printf("delete generators and operator\r\n");
|
||||
// can't delete operator if the generator is till in working
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_del_operator(oper));
|
||||
for (int i = 0; i < SOC_MCPWM_GENERATORS_PER_OPERATOR; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_generator(gens[i]));
|
||||
}
|
||||
TEST_ESP_OK(mcpwm_del_operator(oper));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_generator_force_level_hold_on", "[mcpwm]")
|
||||
{
|
||||
// The operator can even work without the timer
|
||||
printf("create operator and generator\r\n");
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
|
||||
mcpwm_gen_handle_t generator = NULL;
|
||||
const int gen_gpio = 0;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.gen_gpio_num = gen_gpio,
|
||||
.flags.io_loop_back = true, // loop back for test
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator));
|
||||
|
||||
printf("add force level to the generator, hold on");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 0, true));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_gpio));
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, true));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_gpio));
|
||||
}
|
||||
|
||||
printf("remove the force level\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, -1, true));
|
||||
|
||||
printf("delete generator and operator\r\n");
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_generator_force_level_recovery", "[mcpwm]")
|
||||
{
|
||||
printf("create mcpwm timer\r\n");
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
.resolution_hz = 1000000,
|
||||
.period_ticks = 50000,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
printf("create operator\r\n");
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
.flags.update_gen_action_on_tez = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
printf("create generator\r\n");
|
||||
mcpwm_gen_handle_t generator = NULL;
|
||||
const int gen_gpio = 0;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.gen_gpio_num = gen_gpio,
|
||||
.flags.io_loop_back = true, // loop back for test
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator));
|
||||
|
||||
printf("add force level to the generator, and recovery by events");
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 0, false));
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_gpio));
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, false));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_gpio));
|
||||
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 0, false));
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_gpio));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(generator,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
// generator should output high level on tez event, the previous force level should disappear
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_gpio));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
TEST_ESP_OK(mcpwm_generator_set_force_level(generator, 1, false));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_gpio));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(generator,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
// generator should output low level on tez event, the previous force level should disappear
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_gpio));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
printf("delete generator, operator and timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_generator_action_on_timer_event", "[mcpwm]")
|
||||
{
|
||||
const int generator_gpio = 0;
|
||||
printf("create timer and operator\r\n");
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1000000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
.period_ticks = 1000,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
mcpwm_operator_config_t oper_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t oper = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&oper_config, &oper));
|
||||
|
||||
printf("connect timer and operator\r\n");
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(oper, timer));
|
||||
|
||||
printf("create generator\r\n");
|
||||
mcpwm_generator_config_t gen_config = {
|
||||
.gen_gpio_num = generator_gpio,
|
||||
.flags.io_loop_back = 1, // so that we can read the GPIO value by GPIO driver
|
||||
};
|
||||
mcpwm_gen_handle_t gen = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_generator(oper, &gen_config, &gen));
|
||||
|
||||
printf("set generator to output high on timer full\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
printf("stop timer on full\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(generator_gpio));
|
||||
|
||||
printf("set generator to output low on timer full\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_KEEP),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
printf("stop timer on full\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_FULL));
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(generator_gpio));
|
||||
|
||||
printf("delete timer, operator, generator\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(gen));
|
||||
TEST_ESP_OK(mcpwm_del_operator(oper));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
typedef void (*set_gen_actions_cb_t)(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb);
|
||||
|
||||
static void mcpwm_gen_action_test_template(uint32_t timer_resolution, uint32_t period, mcpwm_timer_count_mode_t count_mode,
|
||||
uint32_t cmpa, uint32_t cmpb, int gpioa, int gpiob, set_gen_actions_cb_t set_generator_actions)
|
||||
{
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.count_mode = count_mode,
|
||||
.resolution_hz = timer_resolution,
|
||||
.period_ticks = period,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
mcpwm_cmpr_handle_t comparator_a = NULL;
|
||||
mcpwm_cmpr_handle_t comparator_b = NULL;
|
||||
mcpwm_comparator_config_t comparator_config = {
|
||||
.flags.update_cmp_on_tez = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator_a));
|
||||
TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator_b));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator_a, cmpa));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator_b, cmpb));
|
||||
|
||||
mcpwm_gen_handle_t generator_a = NULL;
|
||||
mcpwm_gen_handle_t generator_b = NULL;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.gen_gpio_num = gpioa,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator_a));
|
||||
generator_config.gen_gpio_num = gpiob;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator_b));
|
||||
|
||||
set_generator_actions(generator_a, generator_b, comparator_a, comparator_b);
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator_a));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator_b));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator_a));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator_b));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
static void single_edge_active_high(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void single_edge_active_low(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void pulse_placement(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_TOGGLE),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void dual_edge_active_low_asym(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, MCPWM_TIMER_EVENT_FULL, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void dual_edge_active_low_sym(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void dual_edge_complementary(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_DOWN, cmpb, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_generator_action_on_compare_event", "[mcpwm]")
|
||||
{
|
||||
printf("[Asymmetric, SingleEdge, ActiveHigh]\r\n");
|
||||
// PWMA: high = [1->350], low = [351->499,0]
|
||||
// PWMB: high = [1->200], low = [201->499,0]
|
||||
mcpwm_gen_action_test_template(1000000, 500, MCPWM_TIMER_COUNT_MODE_UP, 350, 200, 0, 2, single_edge_active_high);
|
||||
|
||||
printf("[Asymmetric, SingleEdge, ActiveLow]\r\n");
|
||||
// PWMA: low = [0->300], high = [301->499]
|
||||
// PWMB: low = [0->150], high = [151->499]
|
||||
mcpwm_gen_action_test_template(1000000, 500, MCPWM_TIMER_COUNT_MODE_UP, 300, 150, 0, 2, single_edge_active_low);
|
||||
|
||||
printf("[Asymmetric, PulsePlacement]\r\n");
|
||||
// PWMA: low = [0->200], high = [201->400], low = [401->599]
|
||||
// PWMB: high = [0->599], low = [0->599]
|
||||
mcpwm_gen_action_test_template(1000000, 600, MCPWM_TIMER_COUNT_MODE_UP, 200, 400, 0, 2, pulse_placement);
|
||||
|
||||
printf("[Asymmetric, DualEdge, ActiveLow]\r\n");
|
||||
// PWMA: low = [0->250], high = [251->599, 600->450], low = [451->1]
|
||||
// PWMB: low = [0->599], low = [600->1]
|
||||
mcpwm_gen_action_test_template(1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 250, 450, 0, 2, dual_edge_active_low_asym);
|
||||
|
||||
printf("[Symmetric, DualEdge, ActiveLow]\r\n");
|
||||
// PWMA: low = [0->400], high = [401->599, 600->400], low = [399->1]
|
||||
// PWMB: low = [0->500], high = [501->599, 600->500], low = [499->1]
|
||||
mcpwm_gen_action_test_template(1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 400, 500, 0, 2, dual_edge_active_low_sym);
|
||||
|
||||
printf("[Symmetric, DualEdge, Complementary]\r\n");
|
||||
// PWMA: low = [0->350], high = [351->599, 600->350], low = [349->1]
|
||||
// PWMB: low = [0->400], high = [401->599, 600->400], low = [399->1]
|
||||
mcpwm_gen_action_test_template(1000000, 1200, MCPWM_TIMER_COUNT_MODE_UP_DOWN, 350, 400, 0, 2, dual_edge_complementary);
|
||||
}
|
||||
|
||||
typedef void (*set_dead_time_cb_t)(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb);
|
||||
|
||||
static void mcpwm_deadtime_test_template(uint32_t timer_resolution, uint32_t period, uint32_t cmpa, uint32_t cmpb, int gpioa, int gpiob,
|
||||
set_gen_actions_cb_t set_generator_actions, set_dead_time_cb_t set_dead_time)
|
||||
{
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = timer_resolution,
|
||||
.period_ticks = period,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
mcpwm_cmpr_handle_t comparator_a = NULL;
|
||||
mcpwm_cmpr_handle_t comparator_b = NULL;
|
||||
mcpwm_comparator_config_t comparator_config = {
|
||||
.flags.update_cmp_on_tez = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator_a));
|
||||
TEST_ESP_OK(mcpwm_new_comparator(operator, &comparator_config, &comparator_b));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator_a, cmpa));
|
||||
TEST_ESP_OK(mcpwm_comparator_set_compare_value(comparator_b, cmpb));
|
||||
|
||||
mcpwm_gen_handle_t generator_a = NULL;
|
||||
mcpwm_gen_handle_t generator_b = NULL;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.gen_gpio_num = gpioa,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator_a));
|
||||
generator_config.gen_gpio_num = gpiob;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator_b));
|
||||
|
||||
set_generator_actions(generator_a, generator_b, comparator_a, comparator_b);
|
||||
set_dead_time(generator_a, generator_b);
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator_a));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator_b));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator_a));
|
||||
TEST_ESP_OK(mcpwm_del_comparator(comparator_b));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
static void ahc_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void ahc_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 50,
|
||||
.negedge_delay_ticks = 0
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
dead_time_config.posedge_delay_ticks = 0;
|
||||
dead_time_config.negedge_delay_ticks = 100;
|
||||
dead_time_config.flags.invert_output = true;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
|
||||
}
|
||||
|
||||
static void alc_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void alc_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 50,
|
||||
.negedge_delay_ticks = 0,
|
||||
.flags.invert_output = true
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
dead_time_config.posedge_delay_ticks = 0;
|
||||
dead_time_config.negedge_delay_ticks = 100;
|
||||
dead_time_config.flags.invert_output = false;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
|
||||
}
|
||||
|
||||
static void ah_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void ah_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 50,
|
||||
.negedge_delay_ticks = 0,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
dead_time_config.posedge_delay_ticks = 0;
|
||||
dead_time_config.negedge_delay_ticks = 100;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
|
||||
}
|
||||
|
||||
static void al_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void al_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 50,
|
||||
.negedge_delay_ticks = 0,
|
||||
.flags.invert_output = true
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
dead_time_config.posedge_delay_ticks = 0;
|
||||
dead_time_config.negedge_delay_ticks = 100;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, genb, &dead_time_config));
|
||||
}
|
||||
|
||||
static void reda_only_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void reda_only_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 50,
|
||||
.negedge_delay_ticks = 0,
|
||||
};
|
||||
// apply deadtime to generator_a
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
// bypass deadtime module for generator_b
|
||||
dead_time_config.posedge_delay_ticks = 0;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
|
||||
}
|
||||
|
||||
static void fedb_only_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void fedb_only_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 0,
|
||||
.negedge_delay_ticks = 0,
|
||||
};
|
||||
// generator_a bypass the deadtime module (no delay)
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
// apply dead time to generator_b
|
||||
dead_time_config.negedge_delay_ticks = 50;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
|
||||
|
||||
}
|
||||
|
||||
static void redfedb_only_set_generator_actions(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb, mcpwm_cmpr_handle_t cmpa, mcpwm_cmpr_handle_t cmpb)
|
||||
{
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gena,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(gena,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpa, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(genb,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_compare_event(genb,
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, cmpb, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
|
||||
}
|
||||
|
||||
static void redfedb_only_set_dead_time(mcpwm_gen_handle_t gena, mcpwm_gen_handle_t genb)
|
||||
{
|
||||
mcpwm_dead_time_config_t dead_time_config = {
|
||||
.posedge_delay_ticks = 0,
|
||||
.negedge_delay_ticks = 0,
|
||||
};
|
||||
// generator_a bypass the deadtime module (no delay)
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(gena, gena, &dead_time_config));
|
||||
// apply dead time on both edge for generator_b
|
||||
dead_time_config.negedge_delay_ticks = 50;
|
||||
dead_time_config.posedge_delay_ticks = 50;
|
||||
TEST_ESP_OK(mcpwm_generator_set_dead_time(genb, genb, &dead_time_config));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_generator_deadtime_classical_configuration", "[mcpwm]")
|
||||
{
|
||||
printf("Active High Complementary\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 600, 200, 400, 0, 2, ahc_set_generator_actions, ahc_set_dead_time);
|
||||
|
||||
printf("Active Low Complementary\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 600, 200, 400, 0, 2, alc_set_generator_actions, alc_set_dead_time);
|
||||
|
||||
printf("Active High\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 600, 200, 400, 0, 2, ah_set_generator_actions, ah_set_dead_time);
|
||||
|
||||
printf("Active Low\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 600, 200, 400, 0, 2, al_set_generator_actions, al_set_dead_time);
|
||||
|
||||
printf("RED on A, Bypass B\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 500, 350, 350, 0, 2, reda_only_set_generator_actions, reda_only_set_dead_time);
|
||||
|
||||
printf("Bypass A, FED on B\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 500, 350, 350, 0, 2, fedb_only_set_generator_actions, fedb_only_set_dead_time);
|
||||
|
||||
printf("Bypass A, RED + FED on B\r\n");
|
||||
mcpwm_deadtime_test_template(1000000, 500, 350, 350, 0, 2, redfedb_only_set_generator_actions, redfedb_only_set_dead_time);
|
||||
}
|
380
components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c
Normal file
380
components/driver/test_apps/mcpwm/main/test_mcpwm_oper.c
Normal file
@@ -0,0 +1,380 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/mcpwm_oper.h"
|
||||
#include "driver/mcpwm_timer.h"
|
||||
#include "driver/mcpwm_gen.h"
|
||||
#include "driver/mcpwm_fault.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
TEST_CASE("mcpwm_operator_install_uninstall", "[mcpwm]")
|
||||
{
|
||||
const int total_operators = SOC_MCPWM_OPERATORS_PER_GROUP * SOC_MCPWM_GROUPS;
|
||||
mcpwm_timer_handle_t timers[SOC_MCPWM_GROUPS];
|
||||
mcpwm_oper_handle_t operators[total_operators];
|
||||
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1 * 1000 * 1000,
|
||||
.period_ticks = 10 * 1000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
};
|
||||
printf("install one MCPWM timer for each group\r\n");
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
timer_config.group_id = i;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
printf("install MCPWM operators for each group\r\n");
|
||||
int k = 0;
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
operator_config.group_id = i;
|
||||
for (int j = 0; j < SOC_MCPWM_OPERATORS_PER_GROUP; j++) {
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operators[k++]));
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_operator(&operator_config, &operators[0]));
|
||||
}
|
||||
printf("connect MCPWM timer and operators\r\n");
|
||||
k = 0;
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
for (int j = 0; j < SOC_MCPWM_OPERATORS_PER_GROUP; j++) {
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operators[k++], timers[i]));
|
||||
}
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_ARG, mcpwm_operator_connect_timer(operators[0], timers[1]));
|
||||
printf("uninstall operators and timers\r\n");
|
||||
for (int i = 0; i < total_operators; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_operator(operators[i]));
|
||||
}
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_operator_carrier", "[mcpwm]")
|
||||
{
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1000000, // 1MHz, 1us per tick
|
||||
.period_ticks = 20000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.gen_gpio_num = 0,
|
||||
};
|
||||
mcpwm_gen_handle_t generator = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &generator));
|
||||
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(generator,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_TOGGLE),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
|
||||
printf("add carrier to PWM wave\r\n");
|
||||
mcpwm_carrier_config_t carrier_config = {
|
||||
.frequency_hz = 1000000, // 1MHz carrier
|
||||
.duty_cycle = 0.5,
|
||||
.first_pulse_duration_us = 10,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_operator_apply_carrier(operator, &carrier_config));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
printf("remove carrier from PWM wave\r\n");
|
||||
carrier_config.frequency_hz = 0;
|
||||
TEST_ESP_OK(mcpwm_operator_apply_carrier(operator, &carrier_config));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(200));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_generator(generator));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
static bool test_cbc_brake_on_gpio_fault_callback(mcpwm_oper_handle_t operator, const mcpwm_brake_event_data_t *edata, void *user_data)
|
||||
{
|
||||
esp_rom_printf("cbc brake\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool test_ost_brake_on_gpio_fault_callback(mcpwm_oper_handle_t operator, const mcpwm_brake_event_data_t *edata, void *user_data)
|
||||
{
|
||||
esp_rom_printf("ost brake\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_operator_brake_on_gpio_fault", "[mcpwm]")
|
||||
{
|
||||
printf("install timer\r\n");
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = 1000000, // 1MHz, 1us per tick
|
||||
.period_ticks = 20000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
printf("install operator\r\n");
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
printf("set brake event callbacks for operator\r\n");
|
||||
mcpwm_operator_event_callbacks_t cbs = {
|
||||
.on_brake_cbc = test_cbc_brake_on_gpio_fault_callback,
|
||||
.on_brake_ost = test_ost_brake_on_gpio_fault_callback,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_operator_register_event_callbacks(operator, &cbs, NULL));
|
||||
|
||||
printf("install gpio fault\r\n");
|
||||
mcpwm_gpio_fault_config_t gpio_fault_config = {
|
||||
.group_id = 0,
|
||||
.flags.active_level = 1,
|
||||
.flags.io_loop_back = true,
|
||||
.flags.pull_down = true,
|
||||
};
|
||||
mcpwm_fault_handle_t gpio_cbc_fault = NULL;
|
||||
mcpwm_fault_handle_t gpio_ost_fault = NULL;
|
||||
const int cbc_fault_gpio = 4;
|
||||
const int ost_fault_gpio = 5;
|
||||
|
||||
gpio_fault_config.gpio_num = cbc_fault_gpio;
|
||||
TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_fault_config, &gpio_cbc_fault));
|
||||
gpio_fault_config.gpio_num = ost_fault_gpio;
|
||||
TEST_ESP_OK(mcpwm_new_gpio_fault(&gpio_fault_config, &gpio_ost_fault));
|
||||
|
||||
// put fault GPIO into a safe state
|
||||
gpio_set_level(cbc_fault_gpio, 0);
|
||||
gpio_set_level(ost_fault_gpio, 0);
|
||||
|
||||
printf("set brake mode on fault\r\n");
|
||||
mcpwm_brake_config_t brake_config = {
|
||||
.fault = gpio_cbc_fault,
|
||||
.brake_mode = MCPWM_OPER_BRAKE_MODE_CBC,
|
||||
.flags.cbc_recover_on_tez = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_operator_set_brake_on_fault(operator, &brake_config));
|
||||
brake_config.fault = gpio_ost_fault;
|
||||
brake_config.brake_mode = MCPWM_OPER_BRAKE_MODE_OST;
|
||||
TEST_ESP_OK(mcpwm_operator_set_brake_on_fault(operator, &brake_config));
|
||||
|
||||
printf("create generators\r\n");
|
||||
const int gen_a_gpio = 0;
|
||||
const int gen_b_gpio = 2;
|
||||
mcpwm_gen_handle_t gen_a = NULL;
|
||||
mcpwm_gen_handle_t gen_b = NULL;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
generator_config.gen_gpio_num = gen_a_gpio;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &gen_a));
|
||||
generator_config.gen_gpio_num = gen_b_gpio;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &gen_b));
|
||||
|
||||
printf("set generator actions on timer event\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen_a,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen_b,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
|
||||
printf("set generator actions on brake event\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_brake_event(gen_a,
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_brake_event(gen_b,
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_OST, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION_END()));
|
||||
|
||||
printf("enable and start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
|
||||
printf("trigger GPIO fault signal, brake in CBC mode\r\n");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
gpio_set_level(cbc_fault_gpio, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_a_gpio));
|
||||
// remove the fault signal
|
||||
gpio_set_level(cbc_fault_gpio, 0);
|
||||
// recovery
|
||||
TEST_ESP_OK(mcpwm_operator_recover_from_fault(operator, gpio_cbc_fault));
|
||||
vTaskDelay(pdMS_TO_TICKS(40));
|
||||
// should recovery automatically
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_a_gpio));
|
||||
}
|
||||
|
||||
printf("trigger GPIO fault signal, brake in OST mode\r\n");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
gpio_set_level(ost_fault_gpio, 1);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_b_gpio));
|
||||
// can't recover because fault signal is still active
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_operator_recover_from_fault(operator, gpio_ost_fault));
|
||||
// remove the fault signal
|
||||
gpio_set_level(ost_fault_gpio, 0);
|
||||
vTaskDelay(pdMS_TO_TICKS(40));
|
||||
// for ost brake, the generator can't recover before we manually recover it
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_b_gpio));
|
||||
// now it's safe to recover the operator
|
||||
TEST_ESP_OK(mcpwm_operator_recover_from_fault(operator, gpio_ost_fault));
|
||||
vTaskDelay(pdMS_TO_TICKS(40));
|
||||
// should recovery now
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_b_gpio));
|
||||
}
|
||||
|
||||
printf("delete all mcpwm objects\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_fault(gpio_cbc_fault));
|
||||
TEST_ESP_OK(mcpwm_del_fault(gpio_ost_fault));
|
||||
TEST_ESP_OK(mcpwm_del_generator(gen_a));
|
||||
TEST_ESP_OK(mcpwm_del_generator(gen_b));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_operator_brake_on_soft_fault", "[mcpwm]")
|
||||
{
|
||||
printf("install timer\r\n");
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = 1000000, // 1MHz, 1us per tick
|
||||
.period_ticks = 20000,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
printf("install operator\r\n");
|
||||
mcpwm_operator_config_t operator_config = {
|
||||
.group_id = 0,
|
||||
};
|
||||
mcpwm_oper_handle_t operator = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_operator(&operator_config, &operator));
|
||||
TEST_ESP_OK(mcpwm_operator_connect_timer(operator, timer));
|
||||
|
||||
printf("install soft fault\r\n");
|
||||
mcpwm_soft_fault_config_t soft_fault_config = {};
|
||||
mcpwm_fault_handle_t soft_fault = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_soft_fault(&soft_fault_config, &soft_fault));
|
||||
|
||||
printf("set brake mode on fault\r\n");
|
||||
mcpwm_brake_config_t brake_config = {
|
||||
.fault = soft_fault,
|
||||
.brake_mode = MCPWM_OPER_BRAKE_MODE_CBC,
|
||||
.flags.cbc_recover_on_tez = true,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_operator_set_brake_on_fault(operator, &brake_config));
|
||||
|
||||
printf("create generators\r\n");
|
||||
const int gen_a_gpio = 0;
|
||||
const int gen_b_gpio = 2;
|
||||
mcpwm_gen_handle_t gen_a = NULL;
|
||||
mcpwm_gen_handle_t gen_b = NULL;
|
||||
mcpwm_generator_config_t generator_config = {
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
generator_config.gen_gpio_num = gen_a_gpio;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &gen_a));
|
||||
generator_config.gen_gpio_num = gen_b_gpio;
|
||||
TEST_ESP_OK(mcpwm_new_generator(operator, &generator_config, &gen_b));
|
||||
|
||||
printf("set generator actions on timer event\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen_a,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_timer_event(gen_b,
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_LOW),
|
||||
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
|
||||
|
||||
printf("set generator actions on brake event\r\n");
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_brake_event(gen_a,
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_CBC, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION_END()));
|
||||
TEST_ESP_OK(mcpwm_generator_set_actions_on_brake_event(gen_b,
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_OPER_BRAKE_MODE_OST, MCPWM_GEN_ACTION_HIGH),
|
||||
MCPWM_GEN_BRAKE_EVENT_ACTION_END()));
|
||||
|
||||
printf("enable and start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
|
||||
printf("trigger soft fault signal, brake in CBC mode\r\n");
|
||||
for (int i = 0; i < 1; i++) {
|
||||
// stop the timer, so the operator can't recover from fault automatically
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(40));
|
||||
// check initial generator output
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_a_gpio));
|
||||
TEST_ESP_OK(mcpwm_soft_fault_activate(soft_fault));
|
||||
// check generate output on fault event
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_a_gpio));
|
||||
// start the timer, so that operator can recover at a specific event (e.g. tez)
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
// recover on tez
|
||||
TEST_ESP_OK(mcpwm_operator_recover_from_fault(operator, soft_fault));
|
||||
vTaskDelay(pdMS_TO_TICKS(40));
|
||||
// the generator output should be recoverd automatically
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_a_gpio));
|
||||
}
|
||||
|
||||
printf("change the brake mode to ost\r\n");
|
||||
brake_config.brake_mode = MCPWM_OPER_BRAKE_MODE_OST;
|
||||
TEST_ESP_OK(mcpwm_operator_set_brake_on_fault(operator, &brake_config));
|
||||
|
||||
printf("trigger soft fault signal, brake in OST mode\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// check initial generator output
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_b_gpio));
|
||||
TEST_ESP_OK(mcpwm_soft_fault_activate(soft_fault));
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_b_gpio));
|
||||
vTaskDelay(pdMS_TO_TICKS(40));
|
||||
// don't recover without a manual recover
|
||||
TEST_ASSERT_EQUAL(1, gpio_get_level(gen_b_gpio));
|
||||
TEST_ESP_OK(mcpwm_operator_recover_from_fault(operator, soft_fault));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// should recovery now
|
||||
TEST_ASSERT_EQUAL(0, gpio_get_level(gen_b_gpio));
|
||||
}
|
||||
|
||||
printf("delete all mcpwm objects\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_fault(soft_fault));
|
||||
TEST_ESP_OK(mcpwm_del_generator(gen_a));
|
||||
TEST_ESP_OK(mcpwm_del_generator(gen_b));
|
||||
TEST_ESP_OK(mcpwm_del_operator(operator));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
}
|
204
components/driver/test_apps/mcpwm/main/test_mcpwm_sync.c
Normal file
204
components/driver/test_apps/mcpwm/main/test_mcpwm_sync.c
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/mcpwm_timer.h"
|
||||
#include "driver/mcpwm_sync.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_private/mcpwm.h"
|
||||
#include "test_mcpwm_utils.h"
|
||||
|
||||
TEST_CASE("mcpwm_sync_source_install_uninstall", "[mcpwm]")
|
||||
{
|
||||
printf("install timer sync_src\r\n");
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1000000, // 1MHz
|
||||
.period_ticks = 200,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
const int total_timers = SOC_MCPWM_TIMERS_PER_GROUP * SOC_MCPWM_GROUPS;
|
||||
mcpwm_timer_handle_t timers[total_timers];
|
||||
int k = 0;
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
timer_config.group_id = i;
|
||||
for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timers[k++]));
|
||||
}
|
||||
}
|
||||
mcpwm_timer_sync_src_config_t timer_sync_src_config = {
|
||||
.timer_event = MCPWM_TIMER_EVENT_EMPTY,
|
||||
};
|
||||
mcpwm_sync_handle_t timer_syncs[total_timers];
|
||||
for (int i = 0; i < total_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_new_timer_sync_src(timers[i], &timer_sync_src_config, &timer_syncs[i]));
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_new_timer_sync_src(timers[0], &timer_sync_src_config, &timer_syncs[0]));
|
||||
|
||||
printf("install gpio sync_src\r\n");
|
||||
mcpwm_gpio_sync_src_config_t gpio_sync_config = {
|
||||
.gpio_num = 0,
|
||||
};
|
||||
const int total_gpio_sync_srcs = SOC_MCPWM_GROUPS * SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP;
|
||||
mcpwm_sync_handle_t gpio_sync_srcs[total_gpio_sync_srcs];
|
||||
k = 0;
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
gpio_sync_config.group_id = i;
|
||||
for (int j = 0; j < SOC_MCPWM_GPIO_SYNCHROS_PER_GROUP; j++) {
|
||||
TEST_ESP_OK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_srcs[k++]));
|
||||
}
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_srcs[0]));
|
||||
|
||||
printf("delete synchors\r\n");
|
||||
for (int i = 0; i < total_gpio_sync_srcs; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(gpio_sync_srcs[i]));
|
||||
}
|
||||
for (int i = 0; i < total_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(timer_syncs[i]));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_soft_sync_timer_phase_lock", "[mcpwm]")
|
||||
{
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = 1000000, // 1MHz
|
||||
.period_ticks = 200,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_STOP_FULL));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
check_mcpwm_timer_phase(&timer, 1, timer_config.period_ticks / 2, MCPWM_TIMER_DIRECTION_DOWN);
|
||||
|
||||
printf("install soft sync source\r\n");
|
||||
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_timer_sync_phase_config_t sync_phase_config = {
|
||||
.count_value = 77,
|
||||
.direction = MCPWM_TIMER_DIRECTION_UP,
|
||||
.sync_src = soft_sync,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timer, &sync_phase_config));
|
||||
TEST_ESP_OK(mcpwm_soft_sync_activate(soft_sync));
|
||||
check_mcpwm_timer_phase(&timer, 1, 77, MCPWM_TIMER_DIRECTION_UP);
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(soft_sync));
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_gpio_sync_timer_phase_lock", "[mcpwm]")
|
||||
{
|
||||
// GPIO
|
||||
// |
|
||||
// v
|
||||
// timer0-->timer1-->timer2
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = 1000000, // 1MHz, 1us per tick
|
||||
.period_ticks = 500,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_timer_sync_src_config_t sync_config = {
|
||||
.flags.propagate_input_sync = 1, // reuse the input sync source as the output sync trigger
|
||||
};
|
||||
mcpwm_timer_handle_t timers[SOC_MCPWM_TIMERS_PER_GROUP];
|
||||
mcpwm_sync_handle_t sync_srcs[SOC_MCPWM_TIMERS_PER_GROUP];
|
||||
for (int i = 0; i < SOC_MCPWM_TIMERS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timers[i]));
|
||||
TEST_ESP_OK(mcpwm_new_timer_sync_src(timers[i], &sync_config, &sync_srcs[i]));
|
||||
}
|
||||
mcpwm_timer_sync_phase_config_t sync_phase_config = {
|
||||
.count_value = 100,
|
||||
.direction = MCPWM_TIMER_DIRECTION_UP,
|
||||
};
|
||||
mcpwm_sync_handle_t gpio_sync_src;
|
||||
const int gpio_num = 0;
|
||||
mcpwm_gpio_sync_src_config_t gpio_sync_config = {
|
||||
.group_id = 0,
|
||||
.gpio_num = gpio_num,
|
||||
.flags.io_loop_back = true, // so that we can use gpio driver to simulate the sync signal
|
||||
.flags.pull_down = true, // internally pull down
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_new_gpio_sync_src(&gpio_sync_config, &gpio_sync_src));
|
||||
// put the GPIO into initial state
|
||||
gpio_set_level(gpio_num, 0);
|
||||
for (int i = 1; i < SOC_MCPWM_TIMERS_PER_GROUP; i++) {
|
||||
sync_phase_config.sync_src = sync_srcs[i - 1];
|
||||
TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timers[i], &sync_phase_config));
|
||||
}
|
||||
sync_phase_config.sync_src = gpio_sync_src;
|
||||
TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timers[0], &sync_phase_config));
|
||||
|
||||
// simulate an GPIO sync singal
|
||||
gpio_set_level(gpio_num, 1);
|
||||
gpio_set_level(gpio_num, 0);
|
||||
check_mcpwm_timer_phase(timers, SOC_MCPWM_CAPTURE_TIMERS_PER_GROUP, 100, MCPWM_TIMER_DIRECTION_UP);
|
||||
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(gpio_sync_src));
|
||||
for (int i = 0; i < SOC_MCPWM_TIMERS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(sync_srcs[i]));
|
||||
TEST_ESP_OK(mcpwm_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_timer_sync_timer_phase_lock", "[mcpwm]")
|
||||
{
|
||||
// +->timer1
|
||||
// |
|
||||
// timer0---+
|
||||
// |
|
||||
// +->timer2
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.group_id = 0,
|
||||
.resolution_hz = 1000000, // 1MHz, 1us per tick
|
||||
.period_ticks = 500,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN,
|
||||
};
|
||||
mcpwm_timer_handle_t timers[SOC_MCPWM_TIMERS_PER_GROUP];
|
||||
for (int i = 0; i < SOC_MCPWM_TIMERS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timers[i]));
|
||||
}
|
||||
|
||||
mcpwm_timer_sync_src_config_t sync_config = {
|
||||
.timer_event = MCPWM_TIMER_EVENT_FULL,
|
||||
};
|
||||
mcpwm_sync_handle_t sync_src;
|
||||
TEST_ESP_OK(mcpwm_new_timer_sync_src(timers[0], &sync_config, &sync_src));
|
||||
|
||||
mcpwm_timer_sync_phase_config_t sync_phase_config = {
|
||||
.count_value = 50,
|
||||
.direction = MCPWM_TIMER_DIRECTION_DOWN,
|
||||
.sync_src = sync_src,
|
||||
};
|
||||
for (int i = 1; i < SOC_MCPWM_TIMERS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_set_phase_on_sync(timers[i], &sync_phase_config));
|
||||
}
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timers[0]));
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[0], MCPWM_TIMER_START_STOP_FULL));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
|
||||
check_mcpwm_timer_phase(&timers[1], 2, 50, MCPWM_TIMER_DIRECTION_DOWN);
|
||||
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timers[0]));
|
||||
TEST_ESP_OK(mcpwm_del_sync_src(sync_src));
|
||||
for (int i = 0; i < SOC_MCPWM_TIMERS_PER_GROUP; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_timer(timers[i]));
|
||||
}
|
||||
}
|
186
components/driver/test_apps/mcpwm/main/test_mcpwm_timer.c
Normal file
186
components/driver/test_apps/mcpwm/main/test_mcpwm_timer.c
Normal file
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "driver/mcpwm_timer.h"
|
||||
#include "esp_private/mcpwm.h"
|
||||
#include "test_mcpwm_utils.h"
|
||||
|
||||
TEST_CASE("mcpwm_timer_start_stop", "[mcpwm]")
|
||||
{
|
||||
mcpwm_timer_config_t config = {
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1000000, // 1MHz
|
||||
.period_ticks = 400,
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP_DOWN,
|
||||
};
|
||||
const int num_timers = SOC_MCPWM_TIMERS_PER_GROUP * SOC_MCPWM_GROUPS;
|
||||
|
||||
printf("create mcpwm timer instances\r\n");
|
||||
mcpwm_timer_handle_t timers[num_timers];
|
||||
for (int i = 0; i < SOC_MCPWM_GROUPS; i++) {
|
||||
for (int j = 0; j < SOC_MCPWM_TIMERS_PER_GROUP; j++) {
|
||||
config.group_id = i;
|
||||
TEST_ESP_OK(mcpwm_new_timer(&config, &timers[i * SOC_MCPWM_TIMERS_PER_GROUP + j]));
|
||||
}
|
||||
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, mcpwm_new_timer(&config, &timers[0]));
|
||||
}
|
||||
|
||||
// can't do start/stop control before enable
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_timer_start_stop(timers[0], MCPWM_TIMER_START_NO_STOP));
|
||||
|
||||
printf("enable timers\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timers[i]));
|
||||
}
|
||||
|
||||
printf("start timer and then stop when empty\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_STOP_EMPTY));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
check_mcpwm_timer_phase(timers, num_timers, 0, MCPWM_TIMER_DIRECTION_UP);
|
||||
|
||||
printf("start timer and then stop when full\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_STOP_FULL));
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
check_mcpwm_timer_phase(timers, num_timers, config.period_ticks / 2, MCPWM_TIMER_DIRECTION_DOWN);
|
||||
|
||||
printf("start freely and stop manually when full\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// stop at next counter full
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_STOP_FULL));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
check_mcpwm_timer_phase(timers, num_timers, config.period_ticks / 2, MCPWM_TIMER_DIRECTION_DOWN);
|
||||
|
||||
printf("start freely and stop manually when empty\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_START_NO_STOP));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
// stop at next counter empty
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timers[i], MCPWM_TIMER_STOP_EMPTY));
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
}
|
||||
check_mcpwm_timer_phase(timers, num_timers, 0, MCPWM_TIMER_DIRECTION_UP);
|
||||
|
||||
// can't delete timer before disable
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, mcpwm_del_timer(timers[0]));
|
||||
|
||||
printf("disable timers\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timers[i]));
|
||||
}
|
||||
|
||||
printf("delete timers\r\n");
|
||||
for (int i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_del_timer(timers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
#define TEST_MCPWM_TIMER_EVENT_BIT_FULL (1 << 0)
|
||||
#define TEST_MCPWM_TIMER_EVENT_BIT_EMPTY (1 << 1)
|
||||
#define TEST_MCPWM_TIMER_EVENT_BIT_STOP (1 << 2)
|
||||
|
||||
typedef struct {
|
||||
EventGroupHandle_t event_group;
|
||||
uint32_t expected_full_counts;
|
||||
uint32_t expected_empty_counts;
|
||||
uint32_t accumulate_full_counts;
|
||||
uint32_t accumulate_empty_counts;
|
||||
} test_mcpwm_timer_user_data_t;
|
||||
|
||||
static bool test_on_stop(mcpwm_timer_handle_t timer, const mcpwm_timer_event_data_t *edata, void *user_data)
|
||||
{
|
||||
test_mcpwm_timer_user_data_t *udata = (test_mcpwm_timer_user_data_t *)user_data;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
esp_rom_printf("timer stopped at %u\r\n", edata->count_value);
|
||||
TEST_ASSERT_EQUAL(0, edata->count_value);
|
||||
xEventGroupSetBitsFromISR(udata->event_group, TEST_MCPWM_TIMER_EVENT_BIT_STOP, &high_task_wakeup);
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static bool test_on_full(mcpwm_timer_handle_t timer, const mcpwm_timer_event_data_t *edata, void *user_data)
|
||||
{
|
||||
test_mcpwm_timer_user_data_t *udata = (test_mcpwm_timer_user_data_t *)user_data;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
udata->accumulate_full_counts++;
|
||||
if (udata->accumulate_full_counts >= udata->expected_full_counts) {
|
||||
udata->accumulate_full_counts = 0;
|
||||
xEventGroupSetBitsFromISR(udata->event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL, &high_task_wakeup);
|
||||
}
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
static bool test_on_empty(mcpwm_timer_handle_t timer, const mcpwm_timer_event_data_t *edata, void *user_data)
|
||||
{
|
||||
test_mcpwm_timer_user_data_t *udata = (test_mcpwm_timer_user_data_t *)user_data;
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
udata->accumulate_empty_counts++;
|
||||
if (udata->accumulate_empty_counts >= udata->expected_empty_counts) {
|
||||
udata->accumulate_empty_counts = 0;
|
||||
xEventGroupSetBitsFromISR(udata->event_group, TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, &high_task_wakeup);
|
||||
}
|
||||
return high_task_wakeup == pdTRUE;
|
||||
}
|
||||
|
||||
TEST_CASE("mcpwm_timer_event_callbacks", "[mcpwm]")
|
||||
{
|
||||
EventGroupHandle_t event_group = xEventGroupCreate();
|
||||
EventBits_t bits = 0;
|
||||
mcpwm_timer_config_t timer_config = {
|
||||
.group_id = 0,
|
||||
.clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
|
||||
.resolution_hz = 1 * 1000 * 1000, // 1MHz, 1us per tick
|
||||
.period_ticks = 20 * 1000, // 20ms, 50Hz
|
||||
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
|
||||
};
|
||||
mcpwm_timer_handle_t timer = NULL;
|
||||
printf("create mcpwm timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_new_timer(&timer_config, &timer));
|
||||
|
||||
printf("register event callbacks\r\n");
|
||||
mcpwm_timer_event_callbacks_t cbs = {
|
||||
.on_stop = test_on_stop,
|
||||
.on_full = test_on_full,
|
||||
.on_empty = test_on_empty,
|
||||
};
|
||||
test_mcpwm_timer_user_data_t udata = {
|
||||
.event_group = event_group,
|
||||
.expected_empty_counts = 50,
|
||||
.expected_full_counts = 50,
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_timer_register_event_callbacks(timer, &cbs, &udata));
|
||||
|
||||
printf("enable timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_enable(timer));
|
||||
|
||||
printf("start timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
|
||||
|
||||
printf("wait for full and empty events\r\n");
|
||||
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, pdTRUE, pdTRUE, pdMS_TO_TICKS(1050));
|
||||
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, bits);
|
||||
|
||||
printf("stop timer and wait for event\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
|
||||
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_STOP, pdTRUE, pdTRUE, pdMS_TO_TICKS(50));
|
||||
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_STOP, bits);
|
||||
|
||||
printf("disable timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_timer_disable(timer));
|
||||
|
||||
printf("delete timer\r\n");
|
||||
TEST_ESP_OK(mcpwm_del_timer(timer));
|
||||
vEventGroupDelete(event_group);
|
||||
}
|
20
components/driver/test_apps/mcpwm/main/test_mcpwm_utils.c
Normal file
20
components/driver/test_apps/mcpwm/main/test_mcpwm_utils.c
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "unity.h"
|
||||
#include "esp_private/mcpwm.h"
|
||||
#include "test_mcpwm_utils.h"
|
||||
|
||||
void check_mcpwm_timer_phase(mcpwm_timer_handle_t *timers, size_t num_timers,
|
||||
uint32_t expected_count, mcpwm_timer_direction_t expected_direction)
|
||||
{
|
||||
uint32_t count_value;
|
||||
mcpwm_timer_direction_t direction;
|
||||
for (size_t i = 0; i < num_timers; i++) {
|
||||
TEST_ESP_OK(mcpwm_timer_get_phase(timers[i], &count_value, &direction));
|
||||
TEST_ASSERT_INT_WITHIN(1, expected_count, count_value);
|
||||
TEST_ASSERT_EQUAL(expected_direction, direction);
|
||||
}
|
||||
}
|
17
components/driver/test_apps/mcpwm/main/test_mcpwm_utils.h
Normal file
17
components/driver/test_apps/mcpwm/main/test_mcpwm_utils.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_attr.h"
|
||||
#include "driver/mcpwm_types.h"
|
||||
|
||||
#if CONFIG_MCPWM_ISR_IRAM_SAFE
|
||||
#define TEST_MCPWM_CALLBACK_ATTR IRAM_ATTR
|
||||
#else
|
||||
#define TEST_MCPWM_CALLBACK_ATTR
|
||||
#endif // CONFIG_MCPWM_ISR_IRAM_SAFE
|
||||
|
||||
void check_mcpwm_timer_phase(mcpwm_timer_handle_t *timers, size_t num_timers,
|
||||
uint32_t expected_count, mcpwm_timer_direction_t expected_direction);
|
22
components/driver/test_apps/mcpwm/pytest_mcpwm.py
Normal file
22
components/driver/test_apps/mcpwm/pytest_mcpwm.py
Normal file
@@ -0,0 +1,22 @@
|
||||
# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
|
||||
|
||||
@pytest.mark.esp32
|
||||
@pytest.mark.esp32s3
|
||||
@pytest.mark.generic
|
||||
@pytest.mark.parametrize(
|
||||
'config',
|
||||
[
|
||||
'release',
|
||||
'iram_safe',
|
||||
],
|
||||
indirect=True,
|
||||
)
|
||||
def test_mcpwm(dut: Dut) -> None:
|
||||
dut.expect('Press ENTER to see the list of tests')
|
||||
dut.write('*')
|
||||
dut.expect_unity_test_output()
|
5
components/driver/test_apps/mcpwm/sdkconfig.ci.iram_safe
Normal file
5
components/driver/test_apps/mcpwm/sdkconfig.ci.iram_safe
Normal file
@@ -0,0 +1,5 @@
|
||||
CONFIG_COMPILER_DUMP_RTL_FILES=y
|
||||
CONFIG_MCPWM_ISR_IRAM_SAFE=y
|
||||
|
||||
# silent the error check, as the error string are stored in rodata, causing RTL check failure
|
||||
CONFIG_COMPILER_OPTIMIZATION_CHECKS_SILENT=y
|
5
components/driver/test_apps/mcpwm/sdkconfig.ci.release
Normal file
5
components/driver/test_apps/mcpwm/sdkconfig.ci.release
Normal file
@@ -0,0 +1,5 @@
|
||||
CONFIG_PM_ENABLE=y
|
||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y
|
2
components/driver/test_apps/mcpwm/sdkconfig.defaults
Normal file
2
components/driver/test_apps/mcpwm/sdkconfig.defaults
Normal file
@@ -0,0 +1,2 @@
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
CONFIG_ESP_TASK_WDT=n
|
Reference in New Issue
Block a user