| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- /*
- * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- /**
- * this case is used for test PCNT
- * prepare job for test environment UT_T1_PCNT:
- * We use internal signals instead of external wiring, but please keep the following IO connections, or connect nothing to prevent the signal from being disturbed.
- * 1. prepare one ESP-WROOM-32 board and connect it to PC.
- * 2. connect GPIO21 with GPIO4
- * 3. GPIO5 connect to 3.3v
- * 4. GPIO19 connect to GND
- * 5. logic analyzer will help too if possible
- *
- * the GPIO18 is the pulse producer, the GPIO4 is the input GPIO
- */
- #include <stdio.h>
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/queue.h"
- #include "soc/soc_caps.h"
- #if SOC_PCNT_SUPPORTED
- #include "driver/periph_ctrl.h"
- #include "driver/gpio.h"
- #include "driver/pcnt.h"
- #include "driver/ledc.h"
- #include "esp_attr.h"
- #include "esp_log.h"
- #include "soc/gpio_periph.h"
- #include "soc/pcnt_struct.h"
- #include "unity.h"
- #include "esp_rom_gpio.h"
- #define PULSE_IO 21
- #define PCNT_INPUT_IO 4
- #define PCNT_CTRL_VCC_IO 5
- #define PCNT_CTRL_GND_IO 2
- #define HIGHEST_LIMIT 10
- #define LOWEST_LIMIT 0
- #define MAX_THRESHOLD 5
- #define MIN_THRESHOLD 0
- #define PCNT_CTRL_HIGH_LEVEL 1
- #define PCNT_CTRL_LOW_LEVEL 0
- static xQueueHandle pcnt_evt_queue = NULL;
- typedef struct {
- int zero_times;
- int h_limit;
- int l_limit;
- int h_threshold;
- int l_threshold;
- int filter_time;
- } event_times;
- static void pcnt_test_io_config(int ctrl_level)
- {
- // Connect internal signals using IO matrix.
- gpio_set_direction(PULSE_IO, GPIO_MODE_INPUT_OUTPUT);
- esp_rom_gpio_connect_out_signal(PULSE_IO, LEDC_LS_SIG_OUT1_IDX, 0, 0); // LEDC_TIMER_1, LEDC_LOW_SPEED_MODE
- esp_rom_gpio_connect_in_signal(PULSE_IO, PCNT_SIG_CH0_IN0_IDX, 0); // PCNT_UNIT_0, PCNT_CHANNEL_0
- esp_rom_gpio_connect_in_signal(ctrl_level ? GPIO_MATRIX_CONST_ONE_INPUT : GPIO_MATRIX_CONST_ZERO_INPUT, PCNT_CTRL_CH0_IN0_IDX, 0); // PCNT_UNIT_0, PCNT_CHANNEL_0
- }
- /* use LEDC to produce pulse for PCNT
- * the frequency of LEDC is 1000, so every second will get 1000 count values
- * the PCNT count the LEDC pulse
- * */
- static void produce_pulse(void)
- {
- ledc_timer_config_t ledc_timer = {
- .speed_mode = LEDC_LOW_SPEED_MODE,
- .timer_num = LEDC_TIMER_1,
- .duty_resolution = LEDC_TIMER_10_BIT,
- .freq_hz = 1,
- .clk_cfg = LEDC_AUTO_CLK,
- };
- ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
- ledc_channel_config_t ledc_channel = {
- .speed_mode = LEDC_LOW_SPEED_MODE,
- .channel = LEDC_CHANNEL_1,
- .timer_sel = LEDC_TIMER_1,
- .intr_type = LEDC_INTR_DISABLE,
- .gpio_num = PULSE_IO,
- .duty = 100,
- .hpoint = 0,
- };
- ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
- }
- static void IRAM_ATTR pcnt_intr_handler(void *arg)
- {
- uint32_t intr_status = PCNT.int_st.val;
- int i;
- uint32_t status;
- BaseType_t port_status = pdFALSE;
- for (i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
- if (intr_status & (BIT(i))) {
- status = PCNT.status_unit[i].val;
- PCNT.int_clr.val = BIT(i);
- xQueueSendFromISR(pcnt_evt_queue, &status, &port_status);
- if (port_status == pdTRUE) {
- portYIELD_FROM_ISR();
- }
- }
- }
- }
- static void event_calculate(event_times *event)
- {
- int16_t test_counter = 0;
- int times = 0;
- BaseType_t port_status;
- uint32_t status = 0;
- while (times < 10) {
- port_status = xQueueReceive(pcnt_evt_queue, &status, 1000 / portTICK_PERIOD_MS);
- if (port_status == pdTRUE) {
- event->filter_time++;
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("Current counter value :%d\n", test_counter);
- if (status & PCNT_EVT_THRES_1) {
- printf("THRES1 EVT\n");
- event->h_threshold++;
- }
- if (status & PCNT_EVT_THRES_0) {
- printf("THRES0 EVT\n");
- event->l_threshold++;
- }
- if (status & PCNT_EVT_L_LIM) {
- printf("L_LIM EVT\n");
- event->l_limit++;
- }
- if (status & PCNT_EVT_H_LIM) {
- printf("H_LIM EVT\n");
- event->h_limit++;
- }
- if (status & PCNT_EVT_ZERO) {
- printf("ZERO EVT\n");
- event->zero_times++;
- }
- } else {
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("Current counter value :%d\n", test_counter);
- }
- times++;
- }
- printf("%d, %d, %d, %d, %d, %d\n", event->h_threshold, event->l_threshold,
- event->l_limit, event->h_limit, event->zero_times, event->filter_time);
- }
- /*
- * There exist 2 kind of counting methods: positive and negative counting method
- * 1. when control IO is high level, PCNT is positive counting mode
- * 2. when control IO is low level, PCNT is positive negative mode
- * the positive method standard is as below:
- * ----------------------------------------------------------------------------------
- * POS_ MODE | LCTRL_ MODE | HCTRL_ MODE | sig l→h when ctrl=0 | sig l→h when ctrl=1
- * NEG_ MODE | | | |
- * ===================================================================================
- * 1 (inc) | 0 (-) | 0 (-) | Inc ctr | Inc ctr
- * 2 (dec) | 0 (-) | 0 (-) | Dec ctr | Dec ctr
- * 0 (-) | x | x | No action | No action
- * 1 (inc) | 0 (-) | 1 (inv) | Inc ctr | Dec ctr
- * 1 (inc) | 1 (inv) | 0 (-) | Dec ctr | Inc ctr
- * 2 (dec) | 0 (-) | 1 (inv) | Dec ctr | Inc ctr
- * 1 (inc) | 0 (-) | 2 (dis) | Inc ctr | No action
- * 1 (inc) | 2 (dis) | 0 (-) | No action | Inc ctr
- * -----------------------------------------------------------------------------------
- * */
- static void count_mode_test(gpio_num_t ctl_io)
- {
- int16_t test_counter;
- //produce pulse, 100HZ
- ledc_timer_config_t ledc_timer = {
- .speed_mode = LEDC_LOW_SPEED_MODE,
- .timer_num = LEDC_TIMER_1,
- .duty_resolution = LEDC_TIMER_10_BIT,
- .freq_hz = 100,
- .clk_cfg = LEDC_AUTO_CLK,
- };
- ledc_timer_config(&ledc_timer);
- ledc_channel_config_t ledc_channel = {
- .speed_mode = LEDC_LOW_SPEED_MODE,
- .channel = LEDC_CHANNEL_1,
- .timer_sel = LEDC_TIMER_1,
- .intr_type = LEDC_INTR_DISABLE,
- .gpio_num = PULSE_IO,
- .duty = 100,
- .hpoint = 0,
- };
- ledc_channel_config(&ledc_channel);
- pcnt_config_t pcnt_config = {
- .pulse_gpio_num = PCNT_INPUT_IO,
- .ctrl_gpio_num = ctl_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 = 101,
- .counter_l_lim = -101,
- };
- TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
- pcnt_test_io_config((ctl_io == PCNT_CTRL_VCC_IO) ? PCNT_CTRL_HIGH_LEVEL : PCNT_CTRL_LOW_LEVEL);
- int16_t result1[8] = {100, -100, 0, -100, 100, 100, 0, 100};
- int16_t result2[8] = {100, -100, 0, 100, -100, -100, 100, 0};
- int16_t *result;
- if (ctl_io == PCNT_CTRL_VCC_IO) {
- result = result1;
- } else {
- result = result2;
- }
- // 1, 0, 0, 0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_INC, PCNT_COUNT_DIS,
- PCNT_MODE_KEEP, PCNT_MODE_KEEP));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[0]);
- //2, 0, 0, 0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_DEC, PCNT_COUNT_DIS,
- PCNT_MODE_KEEP, PCNT_MODE_KEEP));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[1]);
- //0,0,0,0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_DIS, PCNT_COUNT_DIS,
- PCNT_MODE_KEEP, PCNT_MODE_KEEP));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[2]);
- //1,0,1,0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_INC, PCNT_COUNT_DIS,
- PCNT_MODE_REVERSE, PCNT_MODE_KEEP));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[3]);
- //1,0,0,1
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_INC, PCNT_COUNT_DIS,
- PCNT_MODE_KEEP, PCNT_MODE_REVERSE));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[4]);
- //2,0,0,1
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_DEC, PCNT_COUNT_DIS,
- PCNT_MODE_REVERSE, PCNT_MODE_KEEP));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[5]);
- //1,0,2,0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_INC, PCNT_COUNT_DIS,
- PCNT_MODE_DISABLE, PCNT_MODE_KEEP));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[6]);
- //1,0,0,2
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
- PCNT_COUNT_INC, PCNT_COUNT_DIS,
- PCNT_MODE_KEEP, PCNT_MODE_DISABLE));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("value: %d\n", test_counter);
- TEST_ASSERT_INT16_WITHIN(1, test_counter, result[7]);
- }
- // test PCNT basic configuration
- TEST_CASE("PCNT test config", "[pcnt]")
- {
- pcnt_config_t pcnt_config = {
- .pulse_gpio_num = PCNT_INPUT_IO,
- .ctrl_gpio_num = PCNT_CTRL_VCC_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 = 100,
- .counter_l_lim = 0,
- };
- // basic configuration
- pcnt_config_t temp_pcnt_config = pcnt_config;
- TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
- // test SOC_PCNT_UNITS_PER_GROUP units, from 0-(SOC_PCNT_UNITS_PER_GROUP-1)
- pcnt_config = temp_pcnt_config;
- pcnt_config.unit = SOC_PCNT_UNITS_PER_GROUP;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
- pcnt_config.unit = i;
- TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
- }
- // test channels
- pcnt_config = temp_pcnt_config;
- pcnt_config.channel = PCNT_CHANNEL_MAX;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- pcnt_config = temp_pcnt_config;
- pcnt_config.pulse_gpio_num = -1;
- TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
- pcnt_config = temp_pcnt_config;
- pcnt_config.pulse_gpio_num = GPIO_NUM_MAX + 1;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- // test pulse_gpio_num and ctrl_gpio_num is the same
- pcnt_config = temp_pcnt_config;
- pcnt_config.pulse_gpio_num = PCNT_INPUT_IO;
- pcnt_config.ctrl_gpio_num = PCNT_INPUT_IO;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- pcnt_config = temp_pcnt_config;
- pcnt_config.pos_mode = PCNT_COUNT_MAX;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- pcnt_config = temp_pcnt_config;
- pcnt_config.hctrl_mode = PCNT_MODE_MAX;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- pcnt_config = temp_pcnt_config;
- pcnt_config.lctrl_mode = PCNT_MODE_MAX;
- TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
- }
- /* PCNT basic property:
- * 1. pause counter
- * 2. resume counter
- * 3. clear counter
- * 4. check the counter value*/
- TEST_CASE("PCNT basic function test", "[pcnt]")
- {
- int16_t test_counter;
- int16_t time = 0;
- int clear_count = 0;
- int resume_count = 0;
- int temp_value = 0;
- pcnt_config_t pcnt_config = {
- .pulse_gpio_num = PCNT_INPUT_IO,
- .ctrl_gpio_num = PCNT_CTRL_VCC_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 = 10,
- .counter_l_lim = -10,
- };
- TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
- // use LEDC to produce the pulse, then the PCNT to count it
- produce_pulse();
- pcnt_test_io_config(PCNT_CTRL_HIGH_LEVEL);
- // initialize first, the initail value should be 0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- TEST_ASSERT_EQUAL_INT16(test_counter, 0);
- // resume the PCNT
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- TEST_ASSERT_EQUAL_INT16(test_counter, 0);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- TEST_ASSERT_EQUAL_INT16(test_counter, 0);
- //count now
- while (time != 10) {
- vTaskDelay(1001 / portTICK_RATE_MS); // in case of can't wait to get counter(edge effect)
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("COUNT: %d\n", test_counter);
- TEST_ASSERT_NOT_EQUAL(test_counter, temp_value);
- temp_value = test_counter;
- if (test_counter == 5 || test_counter == -5) {
- //test clear
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- TEST_ASSERT_EQUAL_INT16(test_counter, 0);
- clear_count++;
- }
- if (test_counter == 0) {
- //test pause
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("PAUSE: %d\n", test_counter);
- TEST_ASSERT_EQUAL_INT16(test_counter, 0);
- // test resume
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- vTaskDelay(1000 / portTICK_RATE_MS);
- TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
- printf("RESUME: %d\n", test_counter);
- TEST_ASSERT_EQUAL_INT16(test_counter, 1);
- resume_count++;
- }
- time++;
- }
- TEST_ASSERT_EQUAL_INT16(clear_count, 2);
- TEST_ASSERT_EQUAL_INT16(resume_count, 2);
- }
- /**
- * there are 4 situations will be tested:
- * 1. set event to interrupt triggered
- * 2. disable interrupt to stop triggering interrupt
- * 3. enable interrupt to interrupt triggered again
- * 4. disable event to stop triggering interrupt
- *
- * PCNT interrupt type:
- * 1. PCNT_EVT_THRES_1
- * 2. PCNT_EVT_THRES_0
- * 3. PCNT_EVT_ZERO
- * 4. PCNT_EVT_H_LIM
- * 5. PCNT_EVT_L_LIM
- * */
- TEST_CASE("PCNT interrupt method test(control IO is high)", "[pcnt][timeout=120]")
- {
- pcnt_config_t config = {
- .pulse_gpio_num = PCNT_INPUT_IO,
- .ctrl_gpio_num = PCNT_CTRL_VCC_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 = 5,
- .counter_l_lim = 0,
- };
- TEST_ESP_OK(pcnt_unit_config(&config));
- produce_pulse();
- pcnt_test_io_config(PCNT_CTRL_HIGH_LEVEL);
- event_times event = {
- .zero_times = 0,
- .h_limit = 0,
- .l_limit = 0,
- .h_threshold = 0,
- .l_threshold = 0,
- .filter_time = 0,
- };
- //interrupt set
- TEST_ESP_OK(pcnt_set_filter_value(PCNT_UNIT_0, 2));
- TEST_ESP_OK(pcnt_filter_enable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 4)); // when arrive to max threshold trigger
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
- TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, 1)); // when arrive to minimum threshold trigger
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM)); // when arrive to max limit trigger
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM)); // when arrive to minimum limit trigger
- // initialize first, the initail value should be 0
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- pcnt_evt_queue = xQueueCreate(10, sizeof(uint32_t));
- pcnt_isr_handle_t pcnt_isr_service;
- TEST_ESP_OK(pcnt_isr_register(pcnt_intr_handler, NULL, 0, &pcnt_isr_service));
- TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- // test event
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 2);
- TEST_ASSERT(event.l_limit == 0);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 2);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
- TEST_ASSERT_INT_WITHIN(3, event.filter_time, 4);
- // test interrupt disable
- TEST_ESP_OK(pcnt_intr_disable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- // for the original control io disable interrupt status
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 2);
- TEST_ASSERT(event.l_limit == 0);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 2);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
- TEST_ASSERT_INT_WITHIN(3, event.filter_time, 4);
- // enable the intr
- TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 4);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 4);
- TEST_ASSERT(event.l_limit == 0);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 4);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 4);
- TEST_ASSERT_INT_WITHIN(3, event.filter_time, 10);
- // disable part of events
- TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_ZERO));
- TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_L_LIM));
- TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 5);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 4);
- TEST_ASSERT(event.l_limit == 0);
- TEST_ASSERT_INT_WITHIN(3, event.h_limit, 6);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 4);
- TEST_ASSERT_INT_WITHIN(3, event.filter_time, 14);
- // Because this test uses its own ISR, we need to release it with `pcnt_isr_unregister` instead of `pcnt_isr_service_uninstall`
- TEST_ESP_OK(pcnt_isr_unregister(pcnt_isr_service));
- vQueueDelete(pcnt_evt_queue);
- }
- TEST_CASE("PCNT interrupt method test(control IO is low)", "[pcnt][timeout=120]")
- {
- pcnt_config_t config = {
- .pulse_gpio_num = PCNT_INPUT_IO,
- .ctrl_gpio_num = PCNT_CTRL_GND_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 = 0,
- .counter_l_lim = -5,
- };
- TEST_ESP_OK(pcnt_unit_config(&config));
- produce_pulse();
- pcnt_test_io_config(PCNT_CTRL_LOW_LEVEL);
- event_times event = {
- .zero_times = 0,
- .h_limit = 0,
- .l_limit = 0,
- .h_threshold = 0,
- .l_threshold = 0,
- .filter_time = 0,
- };
- //interrupt set
- TEST_ESP_OK(pcnt_set_filter_value(PCNT_UNIT_0, 2));
- TEST_ESP_OK(pcnt_filter_enable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, -4)); // when arrive to max threshold trigger
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
- TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, 0)); // when arrive to minimum threshold trigger
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM)); // when arrive to max limit trigger
- TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM)); // when arrive to minimum limit trigger
- // to initialize for PCNT
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- pcnt_evt_queue = xQueueCreate(10, sizeof(uint32_t));
- pcnt_isr_handle_t pcnt_isr_service;
- TEST_ESP_OK(pcnt_isr_register(pcnt_intr_handler, NULL, 0, &pcnt_isr_service));
- TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- // test event
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 1);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 1);
- TEST_ASSERT_INT_WITHIN(2, event.l_limit, 1);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 1);
- TEST_ASSERT_INT_WITHIN(2, event.filter_time, 2);
- // test interrupt disable
- TEST_ESP_OK(pcnt_intr_disable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- // for the original control io disable interrupt status
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 1);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 1);
- TEST_ASSERT_INT_WITHIN(2, event.l_limit, 1);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 1);
- TEST_ASSERT_INT_WITHIN(2, event.filter_time, 2);
- // enable the intr
- pcnt_unit_config(&config);
- pcnt_test_io_config(PCNT_CTRL_LOW_LEVEL);
- TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
- TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 3);
- TEST_ASSERT_INT_WITHIN(2, event.l_limit, 2);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
- TEST_ASSERT_INT_WITHIN(2, event.filter_time, 6);
- // disable part of events
- TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_ZERO));
- TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_L_LIM));
- TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
- event_calculate(&event);
- TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 4);
- TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 3);
- TEST_ASSERT_INT_WITHIN(2, event.l_limit, 2);
- TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
- TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
- TEST_ASSERT_INT_WITHIN(2, event.filter_time, 8);
- // Because this test uses its own ISR, we need to release it with `pcnt_isr_unregister` instead of `pcnt_isr_service_uninstall`
- TEST_ESP_OK(pcnt_isr_unregister(pcnt_isr_service));
- vQueueDelete(pcnt_evt_queue);
- }
- TEST_CASE("PCNT counting mode test", "[pcnt]")
- {
- printf("PCNT mode test for positive count\n");
- count_mode_test(PCNT_CTRL_VCC_IO);
- printf("PCNT mode test for negative count\n");
- count_mode_test(PCNT_CTRL_GND_IO);
- }
- #endif // #if SOC_PCNT_SUPPORTED
|