mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
unit_test: migrate to use pulse_cnt driver
This commit is contained in:
parent
04b3f8b210
commit
0d920a47f7
@ -692,13 +692,6 @@ UT_008:
|
||||
- UT_T1_GPIO
|
||||
- psram
|
||||
|
||||
UT_012:
|
||||
extends: .unit_test_esp32_template
|
||||
tags:
|
||||
- ESP32_IDF
|
||||
- UT_T1_LEDC
|
||||
- psram
|
||||
|
||||
UT_014:
|
||||
extends: .unit_test_esp32_template
|
||||
tags:
|
||||
@ -782,13 +775,6 @@ UT_036:
|
||||
- UT_T1_PSRAMV0
|
||||
- psram
|
||||
|
||||
# ToDo: re-enable this job when ESP32-S2 LEDC runner installed
|
||||
# UT_037:
|
||||
# extends: .unit_test_esp32s2_template
|
||||
# tags:
|
||||
# - ESP32S2_IDF
|
||||
# - UT_T1_LEDC
|
||||
|
||||
UT_038:
|
||||
extends: .unit_test_esp32s2_template
|
||||
parallel: 2
|
||||
|
@ -132,7 +132,9 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
|
||||
/**
|
||||
* @brief Set LEDC output gpio.
|
||||
* @deprecated This function is redundant, please use ledc_channel_config to set gpio pins.
|
||||
*
|
||||
* @note This function only routes the LEDC signal to GPIO through matrix, other LEDC resources initialization are not involved.
|
||||
* Please use `ledc_channel_config()` instead to fully configure a LEDC channel.
|
||||
*
|
||||
* @param gpio_num The LEDC output gpio
|
||||
* @param speed_mode Select the LEDC channel group with specified speed mode. Note that not all targets support high speed mode.
|
||||
@ -142,8 +144,8 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel);
|
||||
* - ESP_OK Success
|
||||
* - ESP_ERR_INVALID_ARG Parameter error
|
||||
*/
|
||||
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel)
|
||||
__attribute__((deprecated("use ledc_channel_config instead")));
|
||||
esp_err_t ledc_set_pin(int gpio_num, ledc_mode_t speed_mode, ledc_channel_t ledc_channel);
|
||||
|
||||
/**
|
||||
* @brief LEDC stop.
|
||||
* Disable LEDC output, and set idle level
|
||||
|
@ -6,10 +6,6 @@
|
||||
/* LEDC tested by PCNT in some case
|
||||
* PCNT can get the LEDC waveform frequency
|
||||
*
|
||||
* test environment of UT_T1_LEDC:
|
||||
* 1. connect GPIO18 with GPIO4
|
||||
* 2. connect GPIO5 to 3.3v (in case of it is pulled down by default)
|
||||
*
|
||||
* some calculation related with duty:
|
||||
* real duty = duty/2^duty_resolution
|
||||
*/
|
||||
@ -24,15 +20,13 @@
|
||||
#include "freertos/queue.h"
|
||||
#include "unity.h"
|
||||
#include "soc/ledc_periph.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_system.h"
|
||||
#include "driver/ledc.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#define PULSE_IO 18
|
||||
#define PCNT_INPUT_IO 4
|
||||
#define PCNT_CTRL_FLOATING_IO 5
|
||||
#define HIGHEST_LIMIT 10000
|
||||
#define LOWEST_LIMIT -10000
|
||||
#define PULSE_IO 18
|
||||
|
||||
#define TEST_PWM_FREQ 2000
|
||||
|
||||
@ -116,81 +110,6 @@ static void timer_duty_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit,
|
||||
timer_duty_set_get(ledc_ch_config.speed_mode, ledc_ch_config.channel, (1 << 13) - 2);
|
||||
}
|
||||
|
||||
#if SOC_PCNT_SUPPORTED
|
||||
#include "driver/pcnt.h" // TODO: C3 doesn't have PCNT peripheral
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3)
|
||||
//no runners
|
||||
|
||||
// use PCNT to test the waveform of LEDC
|
||||
static int16_t wave_count(int last_time)
|
||||
{
|
||||
int16_t test_counter;
|
||||
pcnt_config_t pcnt_config = {
|
||||
.pulse_gpio_num = PCNT_INPUT_IO,
|
||||
.ctrl_gpio_num = PCNT_CTRL_FLOATING_IO,
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.unit = PCNT_UNIT_0,
|
||||
.pos_mode = PCNT_COUNT_INC,
|
||||
.neg_mode = PCNT_COUNT_DIS,
|
||||
.lctrl_mode = PCNT_MODE_REVERSE,
|
||||
.hctrl_mode = PCNT_MODE_KEEP,
|
||||
.counter_h_lim = HIGHEST_LIMIT,
|
||||
.counter_l_lim = LOWEST_LIMIT,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||
|
||||
// initialize first
|
||||
TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
|
||||
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
|
||||
|
||||
vTaskDelay(last_time / portTICK_PERIOD_MS);
|
||||
TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
|
||||
return test_counter;
|
||||
}
|
||||
|
||||
// the PCNT will count the frequency of it
|
||||
static void frequency_set_get(ledc_mode_t speed_mode, ledc_timer_t timer, uint32_t freq_hz, int16_t real_freq, int16_t error)
|
||||
{
|
||||
int16_t count;
|
||||
TEST_ESP_OK(ledc_set_freq(speed_mode, timer, freq_hz));
|
||||
count = wave_count(1000);
|
||||
TEST_ASSERT_INT16_WITHIN(error, count, real_freq);
|
||||
TEST_ASSERT_EQUAL_INT32(ledc_get_freq(speed_mode, timer), real_freq);
|
||||
}
|
||||
|
||||
static void timer_frequency_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit, ledc_timer_t timer, ledc_mode_t speed_mode)
|
||||
{
|
||||
ledc_channel_config_t ledc_ch_config = {
|
||||
.gpio_num = PULSE_IO,
|
||||
.speed_mode = speed_mode,
|
||||
.channel = channel,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.timer_sel = timer,
|
||||
.duty = 4000,
|
||||
.hpoint = 0,
|
||||
};
|
||||
ledc_timer_config_t ledc_time_config = {
|
||||
.speed_mode = speed_mode,
|
||||
.duty_resolution = timer_bit,
|
||||
.timer_num = timer,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_USE_APB_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
frequency_set_get(ledc_ch_config.speed_mode, ledc_ch_config.timer_sel, 100, 100, 2);
|
||||
frequency_set_get(ledc_ch_config.speed_mode, ledc_ch_config.timer_sel, 5000, 5000, 5);
|
||||
frequency_set_get(ledc_ch_config.speed_mode, ledc_ch_config.timer_sel, 9000, 8993, 5);
|
||||
}
|
||||
|
||||
#endif // !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3)
|
||||
|
||||
#endif // SOC_PCNT_SUPPORTED
|
||||
|
||||
TEST_CASE("LEDC channel config wrong gpio", "[ledc]")
|
||||
{
|
||||
ledc_channel_config_t ledc_ch_config = initialize_channel_config();
|
||||
@ -324,8 +243,8 @@ TEST_CASE("LEDC set and get duty", "[ledc]")
|
||||
{
|
||||
ledc_timer_t timer_list[4] = {LEDC_TIMER_0, LEDC_TIMER_1, LEDC_TIMER_2, LEDC_TIMER_3};
|
||||
ledc_mode_t speed_mode_list[LEDC_SPEED_MODE_MAX] = SPEED_MODE_LIST;
|
||||
for(int i=0; i<LEDC_TIMER_MAX-1; i++) {
|
||||
for(int j=0; j<LEDC_SPEED_MODE_MAX; j++) {
|
||||
for (int i = 0; i < LEDC_TIMER_MAX - 1; i++) {
|
||||
for (int j = 0; j < LEDC_SPEED_MODE_MAX; j++) {
|
||||
timer_duty_test(LEDC_CHANNEL_0, LEDC_TIMER_13_BIT, timer_list[i], speed_mode_list[j]);
|
||||
}
|
||||
}
|
||||
@ -473,10 +392,88 @@ TEST_CASE("LEDC fade stop test", "[ledc]")
|
||||
|
||||
#if SOC_PCNT_SUPPORTED
|
||||
|
||||
#if !TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3)
|
||||
#include "driver/pulse_cnt.h"
|
||||
|
||||
TEST_CASE("LEDC set and get frequency", "[ledc][test_env=UT_T1_LEDC][timeout=60][ignore]")
|
||||
#define HIGHEST_LIMIT 10000
|
||||
#define LOWEST_LIMIT -10000
|
||||
|
||||
static pcnt_unit_handle_t pcnt_unit;
|
||||
static pcnt_channel_handle_t pcnt_chan;
|
||||
|
||||
static void setup_testbench(void)
|
||||
{
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.high_limit = HIGHEST_LIMIT,
|
||||
.low_limit = LOWEST_LIMIT,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &pcnt_unit));
|
||||
pcnt_chan_config_t chan_config = {
|
||||
.edge_gpio_num = PULSE_IO,
|
||||
.level_gpio_num = -1,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit, &chan_config, &pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
}
|
||||
|
||||
static void tear_testbench(void)
|
||||
{
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_del_unit(pcnt_unit));
|
||||
}
|
||||
|
||||
// use PCNT to test the waveform of LEDC
|
||||
static int wave_count(int last_time)
|
||||
{
|
||||
// The input ability of PULSE_IO is disabled after ledc driver install, so we need to reenable it again
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[PULSE_IO]);
|
||||
int test_counter = 0;
|
||||
TEST_ESP_OK(pcnt_unit_clear_count(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_start(pcnt_unit));
|
||||
vTaskDelay(pdMS_TO_TICKS(last_time));
|
||||
TEST_ESP_OK(pcnt_unit_stop(pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_get_count(pcnt_unit, &test_counter));
|
||||
return test_counter;
|
||||
}
|
||||
|
||||
// the PCNT will count the frequency of it
|
||||
static void frequency_set_get(ledc_mode_t speed_mode, ledc_timer_t timer, uint32_t freq_hz, int16_t real_freq, int16_t error)
|
||||
{
|
||||
int count;
|
||||
TEST_ESP_OK(ledc_set_freq(speed_mode, timer, freq_hz));
|
||||
count = wave_count(1000);
|
||||
TEST_ASSERT_INT16_WITHIN(error, count, real_freq);
|
||||
TEST_ASSERT_EQUAL_INT32(real_freq, ledc_get_freq(speed_mode, timer));
|
||||
}
|
||||
|
||||
static void timer_frequency_test(ledc_channel_t channel, ledc_timer_bit_t timer_bit, ledc_timer_t timer, ledc_mode_t speed_mode)
|
||||
{
|
||||
ledc_channel_config_t ledc_ch_config = {
|
||||
.gpio_num = PULSE_IO,
|
||||
.speed_mode = speed_mode,
|
||||
.channel = channel,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.timer_sel = timer,
|
||||
.duty = 4000,
|
||||
.hpoint = 0,
|
||||
};
|
||||
ledc_timer_config_t ledc_time_config = {
|
||||
.speed_mode = speed_mode,
|
||||
.duty_resolution = timer_bit,
|
||||
.timer_num = timer,
|
||||
.freq_hz = 5000,
|
||||
.clk_cfg = LEDC_USE_APB_CLK,
|
||||
};
|
||||
TEST_ESP_OK(ledc_channel_config(&ledc_ch_config));
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
frequency_set_get(ledc_ch_config.speed_mode, ledc_ch_config.timer_sel, 100, 100, 20);
|
||||
frequency_set_get(ledc_ch_config.speed_mode, ledc_ch_config.timer_sel, 5000, 5000, 50);
|
||||
frequency_set_get(ledc_ch_config.speed_mode, ledc_ch_config.timer_sel, 9000, 8992, 50);
|
||||
}
|
||||
|
||||
TEST_CASE("LEDC set and get frequency", "[ledc][timeout=60][ignore]")
|
||||
{
|
||||
setup_testbench();
|
||||
#if SOC_LEDC_SUPPORT_HS_MODE
|
||||
timer_frequency_test(LEDC_CHANNEL_0, LEDC_TIMER_13_BIT, LEDC_TIMER_0, LEDC_HIGH_SPEED_MODE);
|
||||
timer_frequency_test(LEDC_CHANNEL_0, LEDC_TIMER_13_BIT, LEDC_TIMER_1, LEDC_HIGH_SPEED_MODE);
|
||||
@ -487,10 +484,12 @@ TEST_CASE("LEDC set and get frequency", "[ledc][test_env=UT_T1_LEDC][timeout=60]
|
||||
timer_frequency_test(LEDC_CHANNEL_0, LEDC_TIMER_13_BIT, LEDC_TIMER_1, LEDC_LOW_SPEED_MODE);
|
||||
timer_frequency_test(LEDC_CHANNEL_0, LEDC_TIMER_13_BIT, LEDC_TIMER_2, LEDC_LOW_SPEED_MODE);
|
||||
timer_frequency_test(LEDC_CHANNEL_0, LEDC_TIMER_13_BIT, LEDC_TIMER_3, LEDC_LOW_SPEED_MODE);
|
||||
tear_testbench();
|
||||
}
|
||||
|
||||
TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]")
|
||||
TEST_CASE("LEDC timer set", "[ledc]")
|
||||
{
|
||||
setup_testbench();
|
||||
const ledc_mode_t test_speed_mode = TEST_SPEED_MODE;
|
||||
ledc_channel_config_t ledc_ch_config = {
|
||||
.gpio_num = PULSE_IO,
|
||||
@ -513,7 +512,8 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]")
|
||||
TEST_ESP_OK(ledc_timer_config(&ledc_time_config));
|
||||
|
||||
uint32_t freq_get;
|
||||
uint32_t count;
|
||||
int count;
|
||||
#if SOC_LEDC_SUPPORT_REF_TICK
|
||||
//set timer 0 as 250Hz, use REF_TICK
|
||||
TEST_ESP_OK(ledc_timer_set(test_speed_mode, LEDC_TIMER_0, 1000, 10, LEDC_REF_TICK));
|
||||
TEST_ESP_OK(ledc_timer_rst(test_speed_mode, LEDC_TIMER_0));
|
||||
@ -521,6 +521,7 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]")
|
||||
freq_get = ledc_get_freq(test_speed_mode, LEDC_TIMER_0);
|
||||
count = wave_count(1000);
|
||||
TEST_ASSERT_UINT32_WITHIN(10, count, freq_get);
|
||||
#endif
|
||||
|
||||
//set timer 0 as 500Hz, use APB_CLK
|
||||
TEST_ESP_OK(ledc_timer_set(test_speed_mode, LEDC_TIMER_0, 5000, 13, LEDC_APB_CLK));
|
||||
@ -539,12 +540,14 @@ TEST_CASE("LEDC timer set", "[ledc][test_env=UT_T1_LEDC]")
|
||||
TEST_ESP_OK(ledc_stop(test_speed_mode, LEDC_CHANNEL_0, !current_level));
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT_EQUAL_INT32( LEDC.channel_group[test_speed_mode].channel[LEDC_CHANNEL_0].conf0.idle_lv, !current_level);
|
||||
tear_testbench();
|
||||
}
|
||||
|
||||
TEST_CASE("LEDC timer pause and resume", "[ledc][test_env=UT_T1_LEDC]")
|
||||
TEST_CASE("LEDC timer pause and resume", "[ledc]")
|
||||
{
|
||||
setup_testbench();
|
||||
const ledc_mode_t test_speed_mode = TEST_SPEED_MODE;
|
||||
int16_t count;
|
||||
int count;
|
||||
ledc_channel_config_t ledc_ch_config = {
|
||||
.gpio_num = PULSE_IO,
|
||||
.speed_mode = test_speed_mode,
|
||||
@ -588,6 +591,7 @@ TEST_CASE("LEDC timer pause and resume", "[ledc][test_env=UT_T1_LEDC]")
|
||||
TEST_ESP_OK(ledc_timer_rst(test_speed_mode, LEDC_TIMER_0));
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
TEST_ASSERT_UINT32_WITHIN(5, count, 5000);
|
||||
tear_testbench();
|
||||
}
|
||||
|
||||
static void ledc_cpu_reset_test_first_stage(void)
|
||||
@ -603,17 +607,18 @@ static void ledc_cpu_reset_test_first_stage(void)
|
||||
|
||||
static void ledc_cpu_reset_test_second_stage(void)
|
||||
{
|
||||
int count;
|
||||
TEST_ASSERT_EQUAL(ESP_RST_SW, esp_reset_reason());
|
||||
int16_t count;
|
||||
setup_testbench();
|
||||
// reconfigure the GPIO again, as the GPIO output ability has been disabled during initialize pcnt peripheral
|
||||
ledc_set_pin(PULSE_IO, TEST_SPEED_MODE, LEDC_CHANNEL_0);
|
||||
count = wave_count(1000);
|
||||
TEST_ASSERT_UINT32_WITHIN(5, count, TEST_PWM_FREQ);
|
||||
TEST_ASSERT_UINT32_WITHIN(5, TEST_PWM_FREQ, count);
|
||||
tear_testbench();
|
||||
}
|
||||
|
||||
TEST_CASE_MULTIPLE_STAGES("LEDC software reset test",
|
||||
"[ledc][test_env=UT_T1_LEDC]",
|
||||
TEST_CASE_MULTIPLE_STAGES("LEDC continue work after software reset", "[ledc]",
|
||||
ledc_cpu_reset_test_first_stage,
|
||||
ledc_cpu_reset_test_second_stage);
|
||||
|
||||
#endif //!TEMPORARY_DISABLED_FOR_TARGETS(ESP32S2, ESP32S3)
|
||||
|
||||
#endif // SOC_PCNT_SUPPORTED
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@ -15,12 +15,10 @@
|
||||
#include "soc/rtc.h"
|
||||
#if SOC_MCPWM_SUPPORTED
|
||||
#include "soc/mcpwm_periph.h"
|
||||
#include "driver/pcnt.h"
|
||||
#include "driver/pulse_cnt.h"
|
||||
#include "driver/mcpwm.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#define TEST_PWMA_PCNT_UNIT (0)
|
||||
#define TEST_PWMB_PCNT_UNIT (1)
|
||||
#define TEST_PWMA_GPIO (2)
|
||||
#define TEST_PWMB_GPIO (4)
|
||||
#define TEST_FAULT_GPIO (21)
|
||||
@ -41,6 +39,11 @@ const static mcpwm_io_signals_t sync_io_sig_array[] = {MCPWM_SYNC_0, MCPWM_SYNC_
|
||||
const static mcpwm_capture_signal_t cap_sig_array[] = {MCPWM_SELECT_CAP0, MCPWM_SELECT_CAP1, MCPWM_SELECT_CAP2};
|
||||
const static mcpwm_io_signals_t cap_io_sig_array[] = {MCPWM_CAP_0, MCPWM_CAP_1, MCPWM_CAP_2};
|
||||
|
||||
static pcnt_unit_handle_t pcnt_unit_a;
|
||||
static pcnt_channel_handle_t pcnt_chan_a;
|
||||
static pcnt_unit_handle_t pcnt_unit_b;
|
||||
static pcnt_channel_handle_t pcnt_chan_b;
|
||||
|
||||
// This GPIO init function is almost the same to public API `mcpwm_gpio_init()`, except that
|
||||
// this function will configure all MCPWM GPIOs into output and input capable
|
||||
// which is useful to simulate a trigger source
|
||||
@ -75,26 +78,9 @@ static esp_err_t test_mcpwm_gpio_init(mcpwm_unit_t mcpwm_num, mcpwm_io_signals_t
|
||||
static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint32_t pwm_freq, float pwm_duty,
|
||||
unsigned long int group_resolution, unsigned long int timer_resolution)
|
||||
{
|
||||
// PWMA <--> PCNT UNIT0
|
||||
pcnt_config_t pcnt_config = {
|
||||
.pulse_gpio_num = TEST_PWMA_GPIO,
|
||||
.ctrl_gpio_num = -1, // don't care level signal
|
||||
.channel = PCNT_CHANNEL_0,
|
||||
.unit = TEST_PWMA_PCNT_UNIT,
|
||||
.pos_mode = PCNT_COUNT_INC,
|
||||
.neg_mode = PCNT_COUNT_DIS,
|
||||
.lctrl_mode = PCNT_MODE_KEEP,
|
||||
.hctrl_mode = PCNT_MODE_KEEP,
|
||||
.counter_h_lim = 10000,
|
||||
.counter_l_lim = -10000,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||
mcpwm_io_signals_t mcpwm_a = pwma[timer];
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(group, mcpwm_a, TEST_PWMA_GPIO));
|
||||
// PWMB <--> PCNT UNIT1
|
||||
pcnt_config.pulse_gpio_num = TEST_PWMB_GPIO;
|
||||
pcnt_config.unit = TEST_PWMB_PCNT_UNIT;
|
||||
TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
|
||||
|
||||
mcpwm_io_signals_t mcpwm_b = pwmb[timer];
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(group, mcpwm_b, TEST_PWMB_GPIO));
|
||||
|
||||
@ -111,14 +97,53 @@ static void mcpwm_setup_testbench(mcpwm_unit_t group, mcpwm_timer_t timer, uint3
|
||||
TEST_ESP_OK(mcpwm_init(group, timer, &pwm_config));
|
||||
}
|
||||
|
||||
static uint32_t mcpwm_pcnt_get_pulse_number(pcnt_unit_t pwm_pcnt_unit, int capture_window_ms)
|
||||
static void pcnt_setup_testbench(void)
|
||||
{
|
||||
int16_t count_value = 0;
|
||||
TEST_ESP_OK(pcnt_counter_pause(pwm_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_counter_clear(pwm_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_counter_resume(pwm_pcnt_unit));
|
||||
// PWMA <--> PCNT UNIT0
|
||||
pcnt_unit_config_t unit_a_config = {
|
||||
.high_limit = 10000,
|
||||
.low_limit = -10000,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_a_config, &pcnt_unit_a));
|
||||
pcnt_chan_config_t chan_a_config = {
|
||||
.edge_gpio_num = TEST_PWMA_GPIO,
|
||||
.level_gpio_num = -1, // don't care level signal
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit_a, &chan_a_config, &pcnt_chan_a));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan_a, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan_a, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
|
||||
// PWMB <--> PCNT UNIT1
|
||||
pcnt_unit_config_t unit_b_config = {
|
||||
.high_limit = 10000,
|
||||
.low_limit = -10000,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_b_config, &pcnt_unit_b));
|
||||
pcnt_chan_config_t chan_b_config = {
|
||||
.edge_gpio_num = TEST_PWMB_GPIO,
|
||||
.level_gpio_num = -1, // don't care level signal
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_channel(pcnt_unit_b, &chan_b_config, &pcnt_chan_b));
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(pcnt_chan_b, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_HOLD));
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(pcnt_chan_b, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
}
|
||||
|
||||
static void pcnt_tear_testbench(void)
|
||||
{
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan_a));
|
||||
TEST_ESP_OK(pcnt_del_channel(pcnt_chan_b));
|
||||
TEST_ESP_OK(pcnt_del_unit(pcnt_unit_a));
|
||||
TEST_ESP_OK(pcnt_del_unit(pcnt_unit_b));
|
||||
}
|
||||
|
||||
static uint32_t pcnt_get_pulse_number(pcnt_unit_handle_t pwm_pcnt_unit, int capture_window_ms)
|
||||
{
|
||||
int count_value = 0;
|
||||
TEST_ESP_OK(pcnt_unit_clear_count(pwm_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_start(pwm_pcnt_unit));
|
||||
usleep(capture_window_ms * 1000);
|
||||
TEST_ESP_OK(pcnt_get_counter_value(pwm_pcnt_unit, &count_value));
|
||||
TEST_ESP_OK(pcnt_unit_stop(pwm_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_get_count(pwm_pcnt_unit, &count_value));
|
||||
printf("count value: %d\r\n", count_value);
|
||||
return (uint32_t)count_value;
|
||||
}
|
||||
@ -163,24 +188,26 @@ static void mcpwm_start_stop_test(mcpwm_unit_t unit, mcpwm_timer_t timer)
|
||||
{
|
||||
uint32_t pulse_number = 0;
|
||||
|
||||
pcnt_setup_testbench();
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ); // Period: 1000us, 1ms
|
||||
// count the pulse number within 100ms
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 100);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_a, 100);
|
||||
TEST_ASSERT_INT_WITHIN(2, 100, pulse_number);
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 100);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_b, 100);
|
||||
TEST_ASSERT_INT_WITHIN(2, 100, pulse_number);
|
||||
|
||||
TEST_ESP_OK(mcpwm_set_frequency(unit, timer, 100));
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 100);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_b, 100);
|
||||
TEST_ASSERT_INT_WITHIN(2, 10, pulse_number);
|
||||
|
||||
// stop timer, then no pwm pulse should be generating
|
||||
TEST_ESP_OK(mcpwm_stop(unit, timer));
|
||||
usleep(10000); // wait until timer stopped
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 100);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_a, 100);
|
||||
TEST_ASSERT_INT_WITHIN(2, 0, pulse_number);
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 100);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_b, 100);
|
||||
TEST_ASSERT_INT_WITHIN(2, 0, pulse_number);
|
||||
pcnt_tear_testbench();
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM start and stop test", "[mcpwm]")
|
||||
@ -229,6 +256,7 @@ static void mcpwm_carrier_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_car
|
||||
{
|
||||
uint32_t pulse_number = 0;
|
||||
|
||||
pcnt_setup_testbench();
|
||||
mcpwm_setup_testbench(unit, timer, 1000, 50.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
mcpwm_set_signal_high(unit, timer, MCPWM_GEN_A);
|
||||
mcpwm_set_signal_high(unit, timer, MCPWM_GEN_B);
|
||||
@ -239,14 +267,15 @@ static void mcpwm_carrier_test(mcpwm_unit_t unit, mcpwm_timer_t timer, mcpwm_car
|
||||
TEST_ESP_OK(mcpwm_carrier_oneshot_mode_enable(unit, timer, os_width));
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMA_PCNT_UNIT, 10);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_a, 10);
|
||||
TEST_ASSERT_INT_WITHIN(50, 2500, pulse_number);
|
||||
usleep(10000);
|
||||
pulse_number = mcpwm_pcnt_get_pulse_number(TEST_PWMB_PCNT_UNIT, 10);
|
||||
pulse_number = pcnt_get_pulse_number(pcnt_unit_b, 10);
|
||||
TEST_ASSERT_INT_WITHIN(50, 2500, pulse_number);
|
||||
|
||||
TEST_ESP_OK(mcpwm_carrier_disable(unit, timer));
|
||||
TEST_ESP_OK(mcpwm_stop(unit, timer));
|
||||
pcnt_tear_testbench();
|
||||
}
|
||||
|
||||
TEST_CASE("MCPWM carrier test", "[mcpwm]")
|
||||
@ -382,33 +411,37 @@ TEST_CASE("MCPWM timer GPIO sync test", "[mcpwm]")
|
||||
}
|
||||
}
|
||||
|
||||
static void mcpwm_swsync_test(mcpwm_unit_t unit) {
|
||||
// used only in this area but need to be reset every time. mutex is not needed
|
||||
// store timestamps captured from ISR callback
|
||||
static uint64_t cap_timestamp[3];
|
||||
// control the start of capture to avoid unstable data
|
||||
static volatile bool log_cap;
|
||||
|
||||
// cb function, to update capture value
|
||||
// only log when channel1 comes at first, then channel2, and do not log further more.
|
||||
static bool test_mcpwm_capture_callback(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata,
|
||||
void *user_data)
|
||||
{
|
||||
if (log_cap && (cap_timestamp[1] == 0 || cap_timestamp[2] == 0)) {
|
||||
if (cap_channel == MCPWM_SELECT_CAP1 && cap_timestamp[1] == 0) {
|
||||
cap_timestamp[1] = edata->cap_value;
|
||||
}
|
||||
if (cap_channel == MCPWM_SELECT_CAP2 && cap_timestamp[1] != 0) {
|
||||
cap_timestamp[2] = edata->cap_value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void mcpwm_swsync_test(mcpwm_unit_t unit)
|
||||
{
|
||||
const uint32_t test_sync_phase = 20;
|
||||
// used only in this area but need to be reset every time. mutex is not needed
|
||||
// store timestamps captured from ISR callback
|
||||
static uint64_t cap_timestamp[3];
|
||||
|
||||
cap_timestamp[0] = 0;
|
||||
cap_timestamp[1] = 0;
|
||||
cap_timestamp[2] = 0;
|
||||
// control the start of capture to avoid unstable data
|
||||
static volatile bool log_cap;
|
||||
log_cap = false;
|
||||
|
||||
// cb function, to update capture value
|
||||
// only log when channel1 comes at first, then channel2, and do not log further more.
|
||||
bool capture_callback(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_channel, const cap_event_data_t *edata,
|
||||
void *user_data) {
|
||||
if (log_cap && (cap_timestamp[1] == 0 || cap_timestamp[2] == 0)) {
|
||||
if (cap_channel == MCPWM_SELECT_CAP1 && cap_timestamp[1] == 0) {
|
||||
cap_timestamp[1] = edata->cap_value;
|
||||
}
|
||||
if (cap_channel == MCPWM_SELECT_CAP2 && cap_timestamp[1] != 0) {
|
||||
cap_timestamp[2] = edata->cap_value;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// configure all timer output 10% PWM
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
mcpwm_setup_testbench(unit, i, 1000, 10.0, MCPWM_TEST_GROUP_CLK_HZ, MCPWM_TEST_TIMER_CLK_HZ);
|
||||
@ -420,7 +453,7 @@ static void mcpwm_swsync_test(mcpwm_unit_t unit) {
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_POS_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = capture_callback,
|
||||
.capture_cb = test_mcpwm_capture_callback,
|
||||
.user_data = NULL,
|
||||
};
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(unit, MCPWM_CAP_0, TEST_SYNC_GPIO_0));
|
||||
@ -477,7 +510,8 @@ typedef struct {
|
||||
TaskHandle_t task_hdl;
|
||||
} test_capture_callback_data_t;
|
||||
|
||||
static bool test_mcpwm_intr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata, void *arg) {
|
||||
static bool test_mcpwm_intr_handler(mcpwm_unit_t mcpwm, mcpwm_capture_channel_id_t cap_sig, const cap_event_data_t *edata, void *arg)
|
||||
{
|
||||
BaseType_t high_task_wakeup = pdFALSE;
|
||||
test_capture_callback_data_t *cb_data = (test_capture_callback_data_t *)arg;
|
||||
vTaskNotifyGiveFromISR(cb_data->task_hdl, &high_task_wakeup);
|
||||
@ -497,10 +531,10 @@ static void mcpwm_capture_test(mcpwm_unit_t unit, mcpwm_capture_signal_t cap_cha
|
||||
|
||||
TEST_ESP_OK(test_mcpwm_gpio_init(unit, cap_io, TEST_CAP_GPIO));
|
||||
mcpwm_capture_config_t conf = {
|
||||
.cap_edge = MCPWM_POS_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = test_mcpwm_intr_handler,
|
||||
.user_data = &callback_data
|
||||
.cap_edge = MCPWM_POS_EDGE,
|
||||
.cap_prescale = 1,
|
||||
.capture_cb = test_mcpwm_intr_handler,
|
||||
.user_data = &callback_data
|
||||
};
|
||||
TEST_ESP_OK(mcpwm_capture_enable_channel(unit, cap_channel, &conf));
|
||||
// generate an posage
|
||||
|
@ -4,6 +4,11 @@ set(srcs "ccomp_timer.c"
|
||||
"test_utils.c")
|
||||
|
||||
if(CONFIG_IDF_TARGET_ESP32)
|
||||
# ESP32's timer group doesn't have XTAL clock source,
|
||||
# so we can't implement a timekeeping that can work during DFS
|
||||
# but we can work around that by combining RMT and PCNT
|
||||
# where PCNT can count the pulses generated by RMT, and RMT is clocked from REF_TICK
|
||||
# REF_TICK won't be affected by DFS
|
||||
list(APPEND srcs "ref_clock_impl_rmt_pcnt.c")
|
||||
else()
|
||||
list(APPEND srcs "ref_clock_impl_timergroup.c")
|
||||
|
@ -20,41 +20,65 @@
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "driver/rmt.h"
|
||||
#include "driver/pulse_cnt.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include "hal/rmt_types.h"
|
||||
#include "hal/rmt_hal.h"
|
||||
#include "hal/rmt_ll.h"
|
||||
#include "hal/pcnt_hal.h"
|
||||
#include "hal/pcnt_ll.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#include "esp_rom_sys.h"
|
||||
|
||||
#define REF_CLOCK_RMT_CHANNEL 0 // RMT channel 0
|
||||
#define REF_CLOCK_PCNT_UNIT 0 // PCNT unit 0
|
||||
#define REF_CLOCK_PCNT_CHANNEL 0// PCNT channel 0
|
||||
#define REF_CLOCK_GPIO 21 // GPIO used to combine RMT out signal with PCNT input signal
|
||||
|
||||
#define REF_CLOCK_RMT_CHANNEL 0 // RMT channel 0
|
||||
#define REF_CLOCK_GPIO 21 // GPIO used to combine RMT out signal with PCNT input signal
|
||||
#define REF_CLOCK_PRESCALER_MS 30 // PCNT high threshold interrupt fired every 30ms
|
||||
|
||||
static void IRAM_ATTR pcnt_isr(void *arg);
|
||||
|
||||
static intr_handle_t s_intr_handle;
|
||||
static portMUX_TYPE s_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
static volatile uint32_t s_milliseconds;
|
||||
|
||||
static rmt_hal_context_t s_rmt_hal;
|
||||
static pcnt_hal_context_t s_pcnt_hal;
|
||||
static pcnt_unit_handle_t s_pcnt_unit;
|
||||
static pcnt_channel_handle_t s_pcnt_chan;
|
||||
static volatile uint32_t s_milliseconds;
|
||||
|
||||
static bool on_reach_watch_point(pcnt_unit_handle_t unit, pcnt_watch_event_data_t *edata, void *user_ctx)
|
||||
{
|
||||
s_milliseconds += REF_CLOCK_PRESCALER_MS;
|
||||
return false;
|
||||
}
|
||||
|
||||
void ref_clock_init(void)
|
||||
{
|
||||
assert(s_intr_handle == NULL && "ref clock already initialized");
|
||||
// Initialize PCNT
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.high_limit = REF_CLOCK_PRESCALER_MS * 1000,
|
||||
.low_limit = -100, // any minus value is OK, in this case, we don't count down
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &s_pcnt_unit));
|
||||
pcnt_chan_config_t chan_config = {
|
||||
.edge_gpio_num = REF_CLOCK_GPIO,
|
||||
.level_gpio_num = -1,
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_new_channel(s_pcnt_unit, &chan_config, &s_pcnt_chan));
|
||||
// increase count on both edges
|
||||
TEST_ESP_OK(pcnt_channel_set_edge_action(s_pcnt_chan, PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_INCREASE));
|
||||
// don't care level change
|
||||
TEST_ESP_OK(pcnt_channel_set_level_action(s_pcnt_chan, PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP));
|
||||
// add watch point
|
||||
TEST_ESP_OK(pcnt_unit_add_watch_point(s_pcnt_unit, REF_CLOCK_PRESCALER_MS * 1000));
|
||||
// register watch event
|
||||
pcnt_event_callbacks_t cbs = {
|
||||
.on_reach = on_reach_watch_point,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_register_event_callbacks(s_pcnt_unit, &cbs, NULL));
|
||||
// start pcnt
|
||||
TEST_ESP_OK(pcnt_unit_start(s_pcnt_unit));
|
||||
|
||||
// Route RMT output to GPIO matrix
|
||||
esp_rom_gpio_connect_out_signal(REF_CLOCK_GPIO, RMT_SIG_OUT0_IDX, false, false);
|
||||
@ -71,18 +95,11 @@ void ref_clock_init(void)
|
||||
};
|
||||
|
||||
rmt_ll_enable_drive_clock(s_rmt_hal.regs, true);
|
||||
#if SOC_RMT_SUPPORT_XTAL
|
||||
rmt_ll_set_group_clock_src(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, RMT_BASECLK_XTAL, 39, 0, 0); // XTAL(40MHz), rmt_sclk => 1MHz (40/(1+39))
|
||||
#elif SOC_RMT_SUPPORT_REF_TICK
|
||||
rmt_ll_set_group_clock_src(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, RMT_BASECLK_REF, 0, 0, 0); // select REF_TICK (1MHz)
|
||||
#endif
|
||||
rmt_hal_tx_set_channel_clock(&s_rmt_hal, REF_CLOCK_RMT_CHANNEL, 1000000, 1000000); // counter clock: 1MHz
|
||||
rmt_ll_tx_enable_idle(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, true); // enable idle output
|
||||
rmt_ll_tx_set_idle_level(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1); // idle level: 1
|
||||
rmt_ll_tx_enable_carrier_modulation(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, true);
|
||||
#if !CONFIG_IDF_TARGET_ESP32
|
||||
rmt_ll_tx_set_carrier_always_on(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, true);
|
||||
#endif
|
||||
rmt_hal_set_carrier_clock(&s_rmt_hal, REF_CLOCK_RMT_CHANNEL, 1000000, 500000, 0.5); // set carrier to 500KHz
|
||||
rmt_ll_tx_set_carrier_level(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, 1);
|
||||
rmt_ll_enable_mem_access(s_rmt_hal.regs, true);
|
||||
@ -92,77 +109,25 @@ void ref_clock_init(void)
|
||||
rmt_ll_tx_enable_loop(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, false);
|
||||
rmt_ll_tx_start(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL);
|
||||
|
||||
// Route signal to PCNT
|
||||
esp_rom_gpio_connect_in_signal(REF_CLOCK_GPIO, PCNT_SIG_CH0_IN0_IDX, false);
|
||||
if (REF_CLOCK_GPIO != 20) {
|
||||
PIN_INPUT_ENABLE(GPIO_PIN_MUX_REG[REF_CLOCK_GPIO]);
|
||||
} else {
|
||||
PIN_INPUT_ENABLE(PERIPHS_IO_MUX_GPIO20_U);
|
||||
}
|
||||
|
||||
// Initialize PCNT
|
||||
periph_module_enable(PERIPH_PCNT_MODULE);
|
||||
pcnt_hal_init(&s_pcnt_hal, REF_CLOCK_PCNT_UNIT);
|
||||
|
||||
pcnt_ll_set_edge_action(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT, REF_CLOCK_PCNT_CHANNEL,
|
||||
PCNT_CHANNEL_EDGE_ACTION_INCREASE, PCNT_CHANNEL_EDGE_ACTION_INCREASE);
|
||||
pcnt_ll_set_level_action(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT, REF_CLOCK_PCNT_CHANNEL,
|
||||
PCNT_CHANNEL_LEVEL_ACTION_KEEP, PCNT_CHANNEL_LEVEL_ACTION_KEEP);
|
||||
pcnt_ll_disable_all_events(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT);
|
||||
pcnt_ll_set_high_limit_value(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT, REF_CLOCK_PRESCALER_MS * 1000);
|
||||
pcnt_ll_enable_high_limit_event(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT, true);
|
||||
|
||||
// Enable PCNT and wait for it to start counting
|
||||
pcnt_ll_start_count(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT);
|
||||
pcnt_ll_clear_count(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT);
|
||||
|
||||
esp_rom_delay_us(10000);
|
||||
|
||||
// Enable interrupt
|
||||
s_milliseconds = 0;
|
||||
ESP_ERROR_CHECK(esp_intr_alloc(ETS_PCNT_INTR_SOURCE, ESP_INTR_FLAG_IRAM, pcnt_isr, NULL, &s_intr_handle));
|
||||
pcnt_ll_clear_intr_status(s_pcnt_hal.dev, BIT(REF_CLOCK_PCNT_UNIT));
|
||||
pcnt_ll_enable_intr(s_pcnt_hal.dev, 1 << REF_CLOCK_PCNT_UNIT, true);
|
||||
}
|
||||
|
||||
static void IRAM_ATTR pcnt_isr(void *arg)
|
||||
void ref_clock_deinit(void)
|
||||
{
|
||||
portENTER_CRITICAL_ISR(&s_lock);
|
||||
pcnt_ll_clear_intr_status(s_pcnt_hal.dev, BIT(REF_CLOCK_PCNT_UNIT));
|
||||
s_milliseconds += REF_CLOCK_PRESCALER_MS;
|
||||
portEXIT_CRITICAL_ISR(&s_lock);
|
||||
}
|
||||
// Deinitialize PCNT
|
||||
TEST_ESP_OK(pcnt_unit_stop(s_pcnt_unit));
|
||||
TEST_ESP_OK(pcnt_unit_remove_watch_point(s_pcnt_unit, REF_CLOCK_PRESCALER_MS * 1000));
|
||||
TEST_ESP_OK(pcnt_del_channel(s_pcnt_chan));
|
||||
TEST_ESP_OK(pcnt_del_unit(s_pcnt_unit));
|
||||
|
||||
void ref_clock_deinit()
|
||||
{
|
||||
assert(s_intr_handle && "ref clock deinit called without init");
|
||||
|
||||
// Disable interrupt
|
||||
pcnt_ll_enable_intr(s_pcnt_hal.dev, 1 << REF_CLOCK_PCNT_UNIT, false);
|
||||
esp_intr_free(s_intr_handle);
|
||||
s_intr_handle = NULL;
|
||||
|
||||
// Disable RMT
|
||||
// Deinitialize RMT
|
||||
rmt_ll_tx_enable_carrier_modulation(s_rmt_hal.regs, REF_CLOCK_RMT_CHANNEL, false);
|
||||
periph_module_disable(PERIPH_RMT_MODULE);
|
||||
|
||||
// Disable PCNT
|
||||
pcnt_ll_stop_count(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT);
|
||||
periph_module_disable(PERIPH_PCNT_MODULE);
|
||||
}
|
||||
|
||||
uint64_t ref_clock_get()
|
||||
uint64_t ref_clock_get(void)
|
||||
{
|
||||
portENTER_CRITICAL(&s_lock);
|
||||
int microseconds = 0;
|
||||
microseconds = pcnt_ll_get_count(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT);
|
||||
uint32_t milliseconds = s_milliseconds;
|
||||
uint32_t intr_status = pcnt_ll_get_intr_status(s_pcnt_hal.dev);
|
||||
if (intr_status & BIT(REF_CLOCK_PCNT_UNIT)) {
|
||||
// refresh counter value, in case the overflow has happened after reading cnt_val
|
||||
microseconds = pcnt_ll_get_count(s_pcnt_hal.dev, REF_CLOCK_PCNT_UNIT);
|
||||
milliseconds += REF_CLOCK_PRESCALER_MS;
|
||||
}
|
||||
portEXIT_CRITICAL(&s_lock);
|
||||
return 1000 * (uint64_t)milliseconds + (uint64_t)microseconds;
|
||||
TEST_ESP_OK(pcnt_unit_get_count(s_pcnt_unit, µseconds));
|
||||
return 1000 * (uint64_t)s_milliseconds + (uint64_t)microseconds;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user