mirror of
https://github.com/espressif/esp-idf.git
synced 2025-09-30 19:19:21 +00:00
Merge branch 'fix/pcnt_zero_input_init' into 'master'
feat(PCNT): Add new api of clear signal See merge request espressif/esp-idf!25372
This commit is contained in:
@@ -63,15 +63,8 @@ typedef struct {
|
||||
int high_limit; /*!< High limitation of the count unit, should be higher than 0 */
|
||||
int intr_priority; /*!< PCNT interrupt priority,
|
||||
if set to 0, the driver will try to allocate an interrupt with a relative low priority (1,2,3) */
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
int zero_input_gpio_num; /*!< GPIO number used by the clear signal, the default active level is high, input mode with pull down enabled. Set to -1 if unused */
|
||||
#endif
|
||||
struct {
|
||||
uint32_t accum_count: 1; /*!< Whether to accumulate the count value when overflows at the high/low limit */
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
uint32_t invert_zero_input: 1; /*!< Invert the zero input signal and set input mode with pull up.*/
|
||||
uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */
|
||||
#endif
|
||||
} flags; /*!< Extra flags */
|
||||
} pcnt_unit_config_t;
|
||||
|
||||
@@ -146,6 +139,34 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit);
|
||||
*/
|
||||
esp_err_t pcnt_unit_set_glitch_filter(pcnt_unit_handle_t unit, const pcnt_glitch_filter_config_t *config);
|
||||
|
||||
#if SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
/**
|
||||
* @brief PCNT clear signal configuration
|
||||
*/
|
||||
typedef struct {
|
||||
int clear_signal_gpio_num; /*!< GPIO number used by the clear signal, the default active level is high, input mode with pull down enabled */
|
||||
struct {
|
||||
uint32_t invert_clear_signal: 1; /*!< Invert the clear input signal and set input mode with pull up */
|
||||
uint32_t io_loop_back: 1; /*!< For debug/test, the signal output from the GPIO will be fed to the input path as well */
|
||||
} flags; /*!< clear signal config flags */
|
||||
} pcnt_clear_signal_config_t;
|
||||
|
||||
/**
|
||||
* @brief Set clear signal for PCNT unit
|
||||
*
|
||||
* @note The function of clear signal is the same as `pcnt_unit_clear_count()`. High-level Active
|
||||
*
|
||||
* @param[in] unit PCNT unit handle created by `pcnt_new_unit()`
|
||||
* @param[in] config PCNT clear signal configuration, set config to NULL means disabling the clear signal
|
||||
* @return
|
||||
* - ESP_OK: Set clear signal successfully
|
||||
* - ESP_ERR_INVALID_ARG: Set clear signal failed because of invalid argument
|
||||
* - ESP_ERR_INVALID_STATE: Set clear signal failed because set clear signal repeatly or disable clear signal before set it
|
||||
* - ESP_FAIL: Set clear signal failed because of other error
|
||||
*/
|
||||
esp_err_t pcnt_unit_set_clear_signal(pcnt_unit_handle_t unit, const pcnt_clear_signal_config_t *config);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable the PCNT unit
|
||||
*
|
||||
|
@@ -87,7 +87,7 @@ struct pcnt_unit_t {
|
||||
int unit_id; // allocated unit numerical ID
|
||||
int low_limit; // low limit value
|
||||
int high_limit; // high limit value
|
||||
int zero_input_gpio_num; // which gpio clear signal input
|
||||
int clear_signal_gpio_num; // which gpio clear signal input
|
||||
int accum_value; // accumulated count value
|
||||
pcnt_chan_t *channels[SOC_PCNT_CHANNELS_PER_UNIT]; // array of PCNT channels
|
||||
pcnt_watch_point_t watchers[PCNT_LL_WATCH_EVENT_MAX]; // array of PCNT watchers
|
||||
@@ -235,6 +235,7 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
|
||||
unit->high_limit = config->high_limit;
|
||||
unit->low_limit = config->low_limit;
|
||||
unit->accum_value = 0;
|
||||
unit->clear_signal_gpio_num = -1;
|
||||
unit->flags.accum_count = config->flags.accum_count;
|
||||
|
||||
// clear/pause register is shared by all units, so using group's spinlock
|
||||
@@ -253,29 +254,6 @@ esp_err_t pcnt_new_unit(const pcnt_unit_config_t *config, pcnt_unit_handle_t *re
|
||||
unit->watchers[i].event_id = PCNT_LL_WATCH_EVENT_INVALID; // invalid all watch point
|
||||
}
|
||||
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
// GPIO configuration
|
||||
gpio_config_t gpio_conf = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_INPUT | (config->flags.io_loop_back ? GPIO_MODE_OUTPUT : 0), // also enable the output path if `io_loop_back` is enabled
|
||||
.pull_down_en = true,
|
||||
.pull_up_en = false,
|
||||
};
|
||||
|
||||
if (config->zero_input_gpio_num >= 0) {
|
||||
if (config->flags.invert_zero_input) {
|
||||
gpio_conf.pull_down_en = false;
|
||||
gpio_conf.pull_up_en = true;
|
||||
}
|
||||
gpio_conf.pin_bit_mask = 1ULL << config->zero_input_gpio_num;
|
||||
ESP_GOTO_ON_ERROR(gpio_config(&gpio_conf), err, TAG, "config zero GPIO failed");
|
||||
esp_rom_gpio_connect_in_signal(config->zero_input_gpio_num,
|
||||
pcnt_periph_signals.groups[group_id].units[unit_id].clear_sig,
|
||||
config->flags.invert_zero_input);
|
||||
}
|
||||
unit->zero_input_gpio_num = config->zero_input_gpio_num;
|
||||
#endif // SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
|
||||
ESP_LOGD(TAG, "new pcnt unit (%d,%d) at %p, count range:[%d,%d]", group_id, unit_id, unit, unit->low_limit, unit->high_limit);
|
||||
*ret_unit = unit;
|
||||
return ESP_OK;
|
||||
@@ -299,11 +277,11 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit)
|
||||
ESP_RETURN_ON_FALSE(!unit->channels[i], ESP_ERR_INVALID_STATE, TAG, "channel %d still in working", i);
|
||||
}
|
||||
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
if (unit->zero_input_gpio_num >= 0) {
|
||||
gpio_reset_pin(unit->zero_input_gpio_num);
|
||||
#if SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
if (unit->clear_signal_gpio_num >= 0) {
|
||||
gpio_reset_pin(unit->clear_signal_gpio_num);
|
||||
}
|
||||
#endif // SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
#endif // SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
|
||||
ESP_LOGD(TAG, "del unit (%d,%d)", group_id, unit_id);
|
||||
// recycle memory resource
|
||||
@@ -311,6 +289,40 @@ esp_err_t pcnt_del_unit(pcnt_unit_handle_t unit)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
esp_err_t pcnt_unit_set_clear_signal(pcnt_unit_handle_t unit, const pcnt_clear_signal_config_t *config)
|
||||
{
|
||||
ESP_RETURN_ON_FALSE(unit, ESP_ERR_INVALID_ARG, TAG, "invalid argument");
|
||||
pcnt_group_t *group = unit->group;
|
||||
int group_id = group->group_id;
|
||||
int unit_id = unit->unit_id;
|
||||
|
||||
if (config) {
|
||||
gpio_config_t gpio_conf = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_INPUT | (config->flags.io_loop_back ? GPIO_MODE_OUTPUT : 0), // also enable the output path if `io_loop_back` is enabled
|
||||
.pull_down_en = true,
|
||||
.pull_up_en = false,
|
||||
};
|
||||
if (config->flags.invert_clear_signal) {
|
||||
gpio_conf.pull_down_en = false;
|
||||
gpio_conf.pull_up_en = true;
|
||||
}
|
||||
gpio_conf.pin_bit_mask = 1ULL << config->clear_signal_gpio_num;
|
||||
ESP_RETURN_ON_ERROR(gpio_config(&gpio_conf), TAG, "config zero signal GPIO failed");
|
||||
esp_rom_gpio_connect_in_signal(config->clear_signal_gpio_num,
|
||||
pcnt_periph_signals.groups[group_id].units[unit_id].clear_sig,
|
||||
config->flags.invert_clear_signal);
|
||||
unit->clear_signal_gpio_num = config->clear_signal_gpio_num;
|
||||
} else {
|
||||
ESP_RETURN_ON_FALSE(unit->clear_signal_gpio_num >= 0, ESP_ERR_INVALID_STATE, TAG, "zero signal not set yet");
|
||||
gpio_reset_pin(unit->clear_signal_gpio_num);
|
||||
unit->clear_signal_gpio_num = -1;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
|
||||
esp_err_t pcnt_unit_set_glitch_filter(pcnt_unit_handle_t unit, const pcnt_glitch_filter_config_t *config)
|
||||
{
|
||||
pcnt_group_t *group = NULL;
|
||||
|
@@ -21,9 +21,6 @@ TEST_CASE("pcnt_unit_install_uninstall", "[pcnt]")
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
.intr_priority = 0,
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
.zero_input_gpio_num = -1,
|
||||
#endif
|
||||
};
|
||||
pcnt_unit_handle_t units[SOC_PCNT_UNITS_PER_GROUP];
|
||||
int count_value = 0;
|
||||
@@ -91,9 +88,6 @@ TEST_CASE("pcnt_channel_install_uninstall", "[pcnt]")
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
.zero_input_gpio_num = -1,
|
||||
#endif
|
||||
};
|
||||
pcnt_chan_config_t chan_config = {
|
||||
.edge_gpio_num = TEST_PCNT_GPIO_A, // only detect edge signal in this case
|
||||
@@ -182,9 +176,6 @@ TEST_CASE("pcnt_multiple_units_pulse_count", "[pcnt]")
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
.zero_input_gpio_num = -1,
|
||||
#endif
|
||||
};
|
||||
pcnt_unit_handle_t units[2];
|
||||
for (int i = 0; i < 2; i++) {
|
||||
@@ -250,9 +241,6 @@ TEST_CASE("pcnt_quadrature_decode_event", "[pcnt]")
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
.zero_input_gpio_num = -1,
|
||||
#endif
|
||||
};
|
||||
|
||||
printf("install pcnt unit\r\n");
|
||||
@@ -376,9 +364,6 @@ TEST_CASE("pcnt_zero_cross_mode", "[pcnt]")
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
.zero_input_gpio_num = -1,
|
||||
#endif
|
||||
};
|
||||
|
||||
printf("install pcnt unit\r\n");
|
||||
@@ -471,9 +456,6 @@ TEST_CASE("pcnt_virtual_io", "[pcnt]")
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -100,
|
||||
.high_limit = 100,
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
.zero_input_gpio_num = -1,
|
||||
#endif
|
||||
};
|
||||
pcnt_chan_config_t chan_config = {
|
||||
.edge_gpio_num = TEST_PCNT_GPIO_A, // only detect edge signal in this case
|
||||
@@ -520,23 +502,24 @@ TEST_CASE("pcnt_virtual_io", "[pcnt]")
|
||||
TEST_ESP_OK(pcnt_del_unit(unit));
|
||||
}
|
||||
|
||||
#if SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
#if SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
TEST_CASE("pcnt_zero_input_signal", "[pcnt]")
|
||||
{
|
||||
pcnt_unit_config_t unit_config = {
|
||||
.low_limit = -1000,
|
||||
.high_limit = 1000,
|
||||
.zero_input_gpio_num = TEST_PCNT_GPIO_Z,
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
|
||||
printf("install pcnt unit\r\n");
|
||||
pcnt_unit_handle_t unit = NULL;
|
||||
TEST_ESP_OK(pcnt_new_unit(&unit_config, &unit));
|
||||
pcnt_glitch_filter_config_t filter_config = {
|
||||
.max_glitch_ns = 1000,
|
||||
|
||||
pcnt_clear_signal_config_t clear_signal_config = {
|
||||
.clear_signal_gpio_num = TEST_PCNT_GPIO_Z,
|
||||
.flags.io_loop_back = true,
|
||||
};
|
||||
TEST_ESP_OK(pcnt_unit_set_glitch_filter(unit, &filter_config));
|
||||
|
||||
TEST_ESP_OK(pcnt_unit_set_clear_signal(unit, &clear_signal_config));
|
||||
|
||||
printf("install pcnt channels\r\n");
|
||||
pcnt_chan_config_t chan_config = {
|
||||
@@ -571,11 +554,30 @@ TEST_CASE("pcnt_zero_input_signal", "[pcnt]")
|
||||
|
||||
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
|
||||
printf("count_value=%d\r\n", count_value);
|
||||
TEST_ASSERT_EQUAL(0, count_value); // 0 after rst_sig
|
||||
TEST_ASSERT_EQUAL(0, count_value); // 0 after zero signal
|
||||
|
||||
printf("remove zero signal\r\n");
|
||||
TEST_ESP_OK(pcnt_unit_set_clear_signal(unit, NULL));
|
||||
TEST_ESP_ERR(ESP_ERR_INVALID_STATE, pcnt_unit_set_clear_signal(unit, NULL));
|
||||
|
||||
// trigger 10 rising edge on GPIO
|
||||
test_gpio_simulate_rising_edge(TEST_PCNT_GPIO_A, 10);
|
||||
|
||||
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
|
||||
printf("count_value=%d\r\n", count_value);
|
||||
TEST_ASSERT_EQUAL(10, count_value);
|
||||
|
||||
printf("simulating zero input signal\r\n");
|
||||
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_Z, 1));
|
||||
TEST_ESP_OK(gpio_set_level(TEST_PCNT_GPIO_Z, 0));
|
||||
|
||||
TEST_ESP_OK(pcnt_unit_get_count(unit, &count_value));
|
||||
printf("count_value=%d\r\n", count_value);
|
||||
TEST_ASSERT_EQUAL(10, count_value); // 10 with no zero signal
|
||||
|
||||
TEST_ESP_OK(pcnt_del_channel(channel));
|
||||
TEST_ESP_OK(pcnt_unit_stop(unit));
|
||||
TEST_ESP_OK(pcnt_unit_disable(unit));
|
||||
TEST_ESP_OK(pcnt_del_unit(unit));
|
||||
}
|
||||
#endif // SOC_PCNT_SUPPORT_ZERO_INPUT
|
||||
#endif // SOC_PCNT_SUPPORT_CLEAR_SIGNAL
|
||||
|
Reference in New Issue
Block a user