esp-idf/components/esp_driver_mcpwm/test_apps/mcpwm/main/test_mcpwm_timer.c

204 wiersze
8.1 KiB
C

/*
* SPDX-FileCopyrightText: 2022-2023 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;
IRAM_ATTR 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 %" PRIu32 "\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;
}
IRAM_ATTR 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;
}
IRAM_ATTR 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(1300));
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("update timer period\r\n");
TEST_ESP_OK(mcpwm_timer_set_period(timer, 50 * 1000)); // period: 50ms, 20Hz
udata.accumulate_empty_counts = 0;
udata.accumulate_full_counts = 0;
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(1500));
// because the timer period changed, the previous wait time is not sufficient, so timeout
TEST_ASSERT_EQUAL(0, bits);
bits = xEventGroupWaitBits(event_group, TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, pdTRUE, pdTRUE, pdMS_TO_TICKS(1500));
TEST_ASSERT_EQUAL(TEST_MCPWM_TIMER_EVENT_BIT_FULL | TEST_MCPWM_TIMER_EVENT_BIT_EMPTY, bits);
printf("stop timer\r\n");
TEST_ESP_OK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_STOP_EMPTY));
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);
}