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