test_pcnt.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /*
  2. * SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /**
  7. * this case is used for test PCNT
  8. * prepare job for test environment UT_T1_PCNT:
  9. * 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.
  10. * 1. prepare one ESP-WROOM-32 board and connect it to PC.
  11. * 2. connect GPIO21 with GPIO4
  12. * 3. GPIO5 connect to 3.3v
  13. * 4. GPIO19 connect to GND
  14. * 5. logic analyzer will help too if possible
  15. *
  16. * the GPIO18 is the pulse producer, the GPIO4 is the input GPIO
  17. */
  18. #include <stdio.h>
  19. #include "freertos/FreeRTOS.h"
  20. #include "freertos/task.h"
  21. #include "freertos/queue.h"
  22. #include "soc/soc_caps.h"
  23. #if SOC_PCNT_SUPPORTED
  24. #include "driver/gpio.h"
  25. #include "driver/pcnt.h"
  26. #include "driver/ledc.h"
  27. #include "esp_attr.h"
  28. #include "esp_log.h"
  29. #include "soc/gpio_periph.h"
  30. #include "soc/pcnt_struct.h"
  31. #include "unity.h"
  32. #include "esp_rom_gpio.h"
  33. #define PULSE_IO 21
  34. #define PCNT_INPUT_IO 4
  35. #define PCNT_CTRL_VCC_IO 5
  36. #define PCNT_CTRL_GND_IO 2
  37. #define HIGHEST_LIMIT 10
  38. #define LOWEST_LIMIT 0
  39. #define MAX_THRESHOLD 5
  40. #define MIN_THRESHOLD 0
  41. #define PCNT_CTRL_HIGH_LEVEL 1
  42. #define PCNT_CTRL_LOW_LEVEL 0
  43. static xQueueHandle pcnt_evt_queue = NULL;
  44. typedef struct {
  45. int zero_times;
  46. int h_limit;
  47. int l_limit;
  48. int h_threshold;
  49. int l_threshold;
  50. int filter_time;
  51. } event_times;
  52. static void pcnt_test_io_config(int ctrl_level)
  53. {
  54. // Connect internal signals using IO matrix.
  55. gpio_set_direction(PULSE_IO, GPIO_MODE_INPUT_OUTPUT);
  56. esp_rom_gpio_connect_out_signal(PULSE_IO, LEDC_LS_SIG_OUT1_IDX, 0, 0); // LEDC_TIMER_1, LEDC_LOW_SPEED_MODE
  57. esp_rom_gpio_connect_in_signal(PULSE_IO, PCNT_SIG_CH0_IN0_IDX, 0); // PCNT_UNIT_0, PCNT_CHANNEL_0
  58. 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
  59. }
  60. /* use LEDC to produce pulse for PCNT
  61. * the frequency of LEDC is 1000, so every second will get 1000 count values
  62. * the PCNT count the LEDC pulse
  63. * */
  64. static void produce_pulse(void)
  65. {
  66. ledc_timer_config_t ledc_timer = {
  67. .speed_mode = LEDC_LOW_SPEED_MODE,
  68. .timer_num = LEDC_TIMER_1,
  69. .duty_resolution = LEDC_TIMER_14_BIT,
  70. .freq_hz = 2,
  71. .clk_cfg = LEDC_AUTO_CLK,
  72. };
  73. ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
  74. ledc_channel_config_t ledc_channel = {
  75. .speed_mode = LEDC_LOW_SPEED_MODE,
  76. .channel = LEDC_CHANNEL_1,
  77. .timer_sel = LEDC_TIMER_1,
  78. .intr_type = LEDC_INTR_DISABLE,
  79. .gpio_num = PULSE_IO,
  80. .duty = 100,
  81. .hpoint = 0,
  82. };
  83. ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
  84. }
  85. static void IRAM_ATTR pcnt_intr_handler(void *arg)
  86. {
  87. uint32_t intr_status = PCNT.int_st.val;
  88. int i;
  89. uint32_t status;
  90. BaseType_t port_status = pdFALSE;
  91. for (i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
  92. if (intr_status & (BIT(i))) {
  93. status = PCNT.status_unit[i].val;
  94. PCNT.int_clr.val = BIT(i);
  95. xQueueSendFromISR(pcnt_evt_queue, &status, &port_status);
  96. if (port_status == pdTRUE) {
  97. portYIELD_FROM_ISR();
  98. }
  99. }
  100. }
  101. }
  102. static void event_calculate(event_times *event)
  103. {
  104. int16_t test_counter = 0;
  105. int times = 0;
  106. BaseType_t port_status;
  107. uint32_t status = 0;
  108. while (times < 10) {
  109. port_status = xQueueReceive(pcnt_evt_queue, &status, 1001 / portTICK_PERIOD_MS);
  110. if (port_status == pdTRUE) {
  111. event->filter_time++;
  112. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  113. printf("Current counter value :%d\n", test_counter);
  114. if (status & PCNT_EVT_THRES_1) {
  115. printf("THRES1 EVT\n");
  116. event->h_threshold++;
  117. }
  118. if (status & PCNT_EVT_THRES_0) {
  119. printf("THRES0 EVT\n");
  120. event->l_threshold++;
  121. }
  122. if (status & PCNT_EVT_L_LIM) {
  123. printf("L_LIM EVT\n");
  124. event->l_limit++;
  125. }
  126. if (status & PCNT_EVT_H_LIM) {
  127. printf("H_LIM EVT\n");
  128. event->h_limit++;
  129. }
  130. if (status & PCNT_EVT_ZERO) {
  131. printf("ZERO EVT\n");
  132. event->zero_times++;
  133. }
  134. } else {
  135. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  136. printf("Current counter value :%d\n", test_counter);
  137. }
  138. times++;
  139. }
  140. printf("%d, %d, %d, %d, %d, %d\n", event->h_threshold, event->l_threshold,
  141. event->l_limit, event->h_limit, event->zero_times, event->filter_time);
  142. }
  143. /*
  144. * There exist 2 kind of counting methods: positive and negative counting method
  145. * 1. when control IO is high level, PCNT is positive counting mode
  146. * 2. when control IO is low level, PCNT is positive negative mode
  147. * the positive method standard is as below:
  148. * ----------------------------------------------------------------------------------
  149. * POS_ MODE | LCTRL_ MODE | HCTRL_ MODE | sig l→h when ctrl=0 | sig l→h when ctrl=1
  150. * NEG_ MODE | | | |
  151. * ===================================================================================
  152. * 1 (inc) | 0 (-) | 0 (-) | Inc ctr | Inc ctr
  153. * 2 (dec) | 0 (-) | 0 (-) | Dec ctr | Dec ctr
  154. * 0 (-) | x | x | No action | No action
  155. * 1 (inc) | 0 (-) | 1 (inv) | Inc ctr | Dec ctr
  156. * 1 (inc) | 1 (inv) | 0 (-) | Dec ctr | Inc ctr
  157. * 2 (dec) | 0 (-) | 1 (inv) | Dec ctr | Inc ctr
  158. * 1 (inc) | 0 (-) | 2 (dis) | Inc ctr | No action
  159. * 1 (inc) | 2 (dis) | 0 (-) | No action | Inc ctr
  160. * -----------------------------------------------------------------------------------
  161. * */
  162. static void count_mode_test(gpio_num_t ctl_io)
  163. {
  164. int16_t test_counter;
  165. //produce pulse, 100HZ
  166. ledc_timer_config_t ledc_timer = {
  167. .speed_mode = LEDC_LOW_SPEED_MODE,
  168. .timer_num = LEDC_TIMER_1,
  169. .duty_resolution = LEDC_TIMER_10_BIT,
  170. .freq_hz = 100,
  171. .clk_cfg = LEDC_AUTO_CLK,
  172. };
  173. ledc_timer_config(&ledc_timer);
  174. ledc_channel_config_t ledc_channel = {
  175. .speed_mode = LEDC_LOW_SPEED_MODE,
  176. .channel = LEDC_CHANNEL_1,
  177. .timer_sel = LEDC_TIMER_1,
  178. .intr_type = LEDC_INTR_DISABLE,
  179. .gpio_num = PULSE_IO,
  180. .duty = 100,
  181. .hpoint = 0,
  182. };
  183. ledc_channel_config(&ledc_channel);
  184. pcnt_config_t pcnt_config = {
  185. .pulse_gpio_num = PCNT_INPUT_IO,
  186. .ctrl_gpio_num = ctl_io,
  187. .channel = PCNT_CHANNEL_0,
  188. .unit = PCNT_UNIT_0,
  189. .pos_mode = PCNT_COUNT_INC,
  190. .neg_mode = PCNT_COUNT_DIS,
  191. .lctrl_mode = PCNT_MODE_REVERSE,
  192. .hctrl_mode = PCNT_MODE_KEEP,
  193. .counter_h_lim = 101,
  194. .counter_l_lim = -101,
  195. };
  196. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  197. pcnt_test_io_config((ctl_io == PCNT_CTRL_VCC_IO) ? PCNT_CTRL_HIGH_LEVEL : PCNT_CTRL_LOW_LEVEL);
  198. int16_t result1[8] = {100, -100, 0, -100, 100, 100, 0, 100};
  199. int16_t result2[8] = {100, -100, 0, 100, -100, -100, 100, 0};
  200. int16_t *result;
  201. if (ctl_io == PCNT_CTRL_VCC_IO) {
  202. result = result1;
  203. } else {
  204. result = result2;
  205. }
  206. // Wait for ledc and pcnt settling down
  207. vTaskDelay(500 / portTICK_RATE_MS);
  208. // 1, 0, 0, 0
  209. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  210. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  211. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  212. PCNT_COUNT_INC, PCNT_COUNT_DIS,
  213. PCNT_MODE_KEEP, PCNT_MODE_KEEP));
  214. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  215. vTaskDelay(1000 / portTICK_RATE_MS);
  216. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  217. printf("value: %d\n", test_counter);
  218. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[0]);
  219. //2, 0, 0, 0
  220. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  221. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  222. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  223. PCNT_COUNT_DEC, PCNT_COUNT_DIS,
  224. PCNT_MODE_KEEP, PCNT_MODE_KEEP));
  225. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  226. vTaskDelay(1000 / portTICK_RATE_MS);
  227. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  228. printf("value: %d\n", test_counter);
  229. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[1]);
  230. //0,0,0,0
  231. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  232. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  233. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  234. PCNT_COUNT_DIS, PCNT_COUNT_DIS,
  235. PCNT_MODE_KEEP, PCNT_MODE_KEEP));
  236. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  237. vTaskDelay(1000 / portTICK_RATE_MS);
  238. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  239. printf("value: %d\n", test_counter);
  240. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[2]);
  241. //1,0,1,0
  242. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  243. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  244. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  245. PCNT_COUNT_INC, PCNT_COUNT_DIS,
  246. PCNT_MODE_REVERSE, PCNT_MODE_KEEP));
  247. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  248. vTaskDelay(1000 / portTICK_RATE_MS);
  249. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  250. printf("value: %d\n", test_counter);
  251. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[3]);
  252. //1,0,0,1
  253. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  254. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  255. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  256. PCNT_COUNT_INC, PCNT_COUNT_DIS,
  257. PCNT_MODE_KEEP, PCNT_MODE_REVERSE));
  258. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  259. vTaskDelay(1000 / portTICK_RATE_MS);
  260. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  261. printf("value: %d\n", test_counter);
  262. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[4]);
  263. //2,0,0,1
  264. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  265. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  266. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  267. PCNT_COUNT_DEC, PCNT_COUNT_DIS,
  268. PCNT_MODE_REVERSE, PCNT_MODE_KEEP));
  269. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  270. vTaskDelay(1000 / portTICK_RATE_MS);
  271. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  272. printf("value: %d\n", test_counter);
  273. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[5]);
  274. //1,0,2,0
  275. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  276. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  277. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  278. PCNT_COUNT_INC, PCNT_COUNT_DIS,
  279. PCNT_MODE_DISABLE, PCNT_MODE_KEEP));
  280. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  281. vTaskDelay(1000 / portTICK_RATE_MS);
  282. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  283. printf("value: %d\n", test_counter);
  284. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[6]);
  285. //1,0,0,2
  286. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  287. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  288. TEST_ESP_OK(pcnt_set_mode(PCNT_UNIT_0, PCNT_CHANNEL_0,
  289. PCNT_COUNT_INC, PCNT_COUNT_DIS,
  290. PCNT_MODE_KEEP, PCNT_MODE_DISABLE));
  291. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  292. vTaskDelay(1000 / portTICK_RATE_MS);
  293. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  294. printf("value: %d\n", test_counter);
  295. TEST_ASSERT_INT16_WITHIN(1, test_counter, result[7]);
  296. }
  297. // test PCNT basic configuration
  298. TEST_CASE("PCNT test config", "[pcnt]")
  299. {
  300. pcnt_config_t pcnt_config = {
  301. .pulse_gpio_num = PCNT_INPUT_IO,
  302. .ctrl_gpio_num = PCNT_CTRL_VCC_IO,
  303. .channel = PCNT_CHANNEL_0,
  304. .unit = PCNT_UNIT_0,
  305. .pos_mode = PCNT_COUNT_INC,
  306. .neg_mode = PCNT_COUNT_DIS,
  307. .lctrl_mode = PCNT_MODE_REVERSE,
  308. .hctrl_mode = PCNT_MODE_KEEP,
  309. .counter_h_lim = 100,
  310. .counter_l_lim = 0,
  311. };
  312. // basic configuration
  313. pcnt_config_t temp_pcnt_config = pcnt_config;
  314. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  315. // test SOC_PCNT_UNITS_PER_GROUP units, from 0-(SOC_PCNT_UNITS_PER_GROUP-1)
  316. pcnt_config = temp_pcnt_config;
  317. pcnt_config.unit = SOC_PCNT_UNITS_PER_GROUP;
  318. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  319. for (int i = 0; i < SOC_PCNT_UNITS_PER_GROUP; i++) {
  320. pcnt_config.unit = i;
  321. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  322. }
  323. // test channels
  324. pcnt_config = temp_pcnt_config;
  325. pcnt_config.channel = PCNT_CHANNEL_MAX;
  326. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  327. pcnt_config = temp_pcnt_config;
  328. pcnt_config.pulse_gpio_num = -1;
  329. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  330. pcnt_config = temp_pcnt_config;
  331. pcnt_config.pulse_gpio_num = GPIO_NUM_MAX + 1;
  332. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  333. // test pulse_gpio_num and ctrl_gpio_num is the same
  334. pcnt_config = temp_pcnt_config;
  335. pcnt_config.pulse_gpio_num = PCNT_INPUT_IO;
  336. pcnt_config.ctrl_gpio_num = PCNT_INPUT_IO;
  337. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  338. pcnt_config = temp_pcnt_config;
  339. pcnt_config.pos_mode = PCNT_COUNT_MAX;
  340. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  341. pcnt_config = temp_pcnt_config;
  342. pcnt_config.hctrl_mode = PCNT_MODE_MAX;
  343. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  344. pcnt_config = temp_pcnt_config;
  345. pcnt_config.lctrl_mode = PCNT_MODE_MAX;
  346. TEST_ASSERT_NOT_NULL((void *)pcnt_unit_config(&pcnt_config));
  347. }
  348. /* PCNT basic property:
  349. * 1. pause counter
  350. * 2. resume counter
  351. * 3. clear counter
  352. * 4. check the counter value*/
  353. TEST_CASE("PCNT basic function test", "[pcnt]")
  354. {
  355. int16_t test_counter;
  356. int16_t time = 0;
  357. int clear_count = 0;
  358. int resume_count = 0;
  359. int temp_value = 0;
  360. pcnt_config_t pcnt_config = {
  361. .pulse_gpio_num = PCNT_INPUT_IO,
  362. .ctrl_gpio_num = PCNT_CTRL_VCC_IO,
  363. .channel = PCNT_CHANNEL_0,
  364. .unit = PCNT_UNIT_0,
  365. .pos_mode = PCNT_COUNT_INC,
  366. .neg_mode = PCNT_COUNT_DIS,
  367. .lctrl_mode = PCNT_MODE_REVERSE,
  368. .hctrl_mode = PCNT_MODE_KEEP,
  369. .counter_h_lim = 10,
  370. .counter_l_lim = -10,
  371. };
  372. TEST_ESP_OK(pcnt_unit_config(&pcnt_config));
  373. // use LEDC to produce the pulse, then the PCNT to count it
  374. produce_pulse();
  375. pcnt_test_io_config(PCNT_CTRL_HIGH_LEVEL);
  376. // initialize first, the initail value should be 0
  377. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  378. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  379. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  380. TEST_ASSERT_EQUAL_INT16(test_counter, 0);
  381. // resume the PCNT
  382. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  383. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  384. TEST_ASSERT_EQUAL_INT16(test_counter, 0);
  385. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  386. TEST_ASSERT_EQUAL_INT16(test_counter, 0);
  387. //count now
  388. while (time != 10) {
  389. vTaskDelay(501 / portTICK_RATE_MS); // in case of can't wait to get counter(edge effect)
  390. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  391. printf("COUNT: %d\n", test_counter);
  392. TEST_ASSERT_NOT_EQUAL(test_counter, temp_value);
  393. temp_value = test_counter;
  394. if (test_counter == 5 || test_counter == -5) {
  395. //test clear
  396. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  397. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  398. TEST_ASSERT_EQUAL_INT16(test_counter, 0);
  399. clear_count++;
  400. }
  401. if (test_counter == 0) {
  402. //test pause
  403. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  404. vTaskDelay(500 / portTICK_RATE_MS);
  405. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  406. printf("PAUSE: %d\n", test_counter);
  407. TEST_ASSERT_EQUAL_INT16(test_counter, 0);
  408. // test resume
  409. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  410. vTaskDelay(500 / portTICK_RATE_MS);
  411. TEST_ESP_OK(pcnt_get_counter_value(PCNT_UNIT_0, &test_counter));
  412. printf("RESUME: %d\n", test_counter);
  413. TEST_ASSERT_EQUAL_INT16(test_counter, 1);
  414. resume_count++;
  415. }
  416. time++;
  417. }
  418. TEST_ASSERT_EQUAL_INT16(clear_count, 2);
  419. TEST_ASSERT_EQUAL_INT16(resume_count, 2);
  420. }
  421. /**
  422. * there are 4 situations will be tested:
  423. * 1. set event to interrupt triggered
  424. * 2. disable interrupt to stop triggering interrupt
  425. * 3. enable interrupt to interrupt triggered again
  426. * 4. disable event to stop triggering interrupt
  427. *
  428. * PCNT interrupt type:
  429. * 1. PCNT_EVT_THRES_1
  430. * 2. PCNT_EVT_THRES_0
  431. * 3. PCNT_EVT_ZERO
  432. * 4. PCNT_EVT_H_LIM
  433. * 5. PCNT_EVT_L_LIM
  434. * */
  435. TEST_CASE("PCNT interrupt method test(control IO is high)", "[pcnt][timeout=120]")
  436. {
  437. pcnt_config_t config = {
  438. .pulse_gpio_num = PCNT_INPUT_IO,
  439. .ctrl_gpio_num = PCNT_CTRL_VCC_IO,
  440. .channel = PCNT_CHANNEL_0,
  441. .unit = PCNT_UNIT_0,
  442. .pos_mode = PCNT_COUNT_INC,
  443. .neg_mode = PCNT_COUNT_DIS,
  444. .lctrl_mode = PCNT_MODE_REVERSE,
  445. .hctrl_mode = PCNT_MODE_KEEP,
  446. .counter_h_lim = 10,
  447. .counter_l_lim = 0,
  448. };
  449. TEST_ESP_OK(pcnt_unit_config(&config));
  450. produce_pulse();
  451. pcnt_test_io_config(PCNT_CTRL_HIGH_LEVEL);
  452. event_times event = {
  453. .zero_times = 0,
  454. .h_limit = 0,
  455. .l_limit = 0,
  456. .h_threshold = 0,
  457. .l_threshold = 0,
  458. .filter_time = 0,
  459. };
  460. //interrupt set
  461. TEST_ESP_OK(pcnt_set_filter_value(PCNT_UNIT_0, 2));
  462. TEST_ESP_OK(pcnt_filter_enable(PCNT_UNIT_0));
  463. TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, 8)); // when arrive to max threshold trigger
  464. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
  465. TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, 2)); // when arrive to minimum threshold trigger
  466. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
  467. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
  468. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM)); // when arrive to max limit trigger
  469. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM)); // when arrive to minimum limit trigger
  470. // initialize first, the initail value should be 0
  471. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  472. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  473. pcnt_evt_queue = xQueueCreate(10, sizeof(uint32_t));
  474. pcnt_isr_handle_t pcnt_isr_service;
  475. TEST_ESP_OK(pcnt_isr_register(pcnt_intr_handler, NULL, 0, &pcnt_isr_service));
  476. TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
  477. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  478. // test event
  479. event_calculate(&event);
  480. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
  481. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 2);
  482. TEST_ASSERT(event.l_limit == 0);
  483. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 2);
  484. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
  485. TEST_ASSERT_INT_WITHIN(3, event.filter_time, 4);
  486. // test interrupt disable
  487. TEST_ESP_OK(pcnt_intr_disable(PCNT_UNIT_0));
  488. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  489. // for the original control io disable interrupt status
  490. event_calculate(&event);
  491. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
  492. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 2);
  493. TEST_ASSERT(event.l_limit == 0);
  494. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 2);
  495. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
  496. TEST_ASSERT_INT_WITHIN(3, event.filter_time, 4);
  497. // enable the intr
  498. TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
  499. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  500. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  501. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  502. event_calculate(&event);
  503. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 4);
  504. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 4);
  505. TEST_ASSERT(event.l_limit == 0);
  506. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 4);
  507. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 4);
  508. TEST_ASSERT_INT_WITHIN(3, event.filter_time, 10);
  509. // disable part of events
  510. TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_ZERO));
  511. TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_L_LIM));
  512. TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
  513. event_calculate(&event);
  514. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 5);
  515. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 4);
  516. TEST_ASSERT(event.l_limit == 0);
  517. TEST_ASSERT_INT_WITHIN(3, event.h_limit, 6);
  518. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 4);
  519. TEST_ASSERT_INT_WITHIN(3, event.filter_time, 14);
  520. // Because this test uses its own ISR, we need to release it with `pcnt_isr_unregister` instead of `pcnt_isr_service_uninstall`
  521. TEST_ESP_OK(pcnt_isr_unregister(pcnt_isr_service));
  522. vQueueDelete(pcnt_evt_queue);
  523. }
  524. TEST_CASE("PCNT interrupt method test(control IO is low)", "[pcnt][timeout=120]")
  525. {
  526. pcnt_config_t config = {
  527. .pulse_gpio_num = PCNT_INPUT_IO,
  528. .ctrl_gpio_num = PCNT_CTRL_GND_IO,
  529. .channel = PCNT_CHANNEL_0,
  530. .unit = PCNT_UNIT_0,
  531. .pos_mode = PCNT_COUNT_INC,
  532. .neg_mode = PCNT_COUNT_DIS,
  533. .lctrl_mode = PCNT_MODE_REVERSE,
  534. .hctrl_mode = PCNT_MODE_KEEP,
  535. .counter_h_lim = 0,
  536. .counter_l_lim = -10,
  537. };
  538. TEST_ESP_OK(pcnt_unit_config(&config));
  539. produce_pulse();
  540. pcnt_test_io_config(PCNT_CTRL_LOW_LEVEL);
  541. event_times event = {
  542. .zero_times = 0,
  543. .h_limit = 0,
  544. .l_limit = 0,
  545. .h_threshold = 0,
  546. .l_threshold = 0,
  547. .filter_time = 0,
  548. };
  549. //interrupt set
  550. TEST_ESP_OK(pcnt_set_filter_value(PCNT_UNIT_0, 2));
  551. TEST_ESP_OK(pcnt_filter_enable(PCNT_UNIT_0));
  552. TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, -8)); // when arrive to max threshold trigger
  553. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
  554. TEST_ESP_OK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, 0)); // when arrive to minimum threshold trigger
  555. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
  556. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
  557. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM)); // when arrive to max limit trigger
  558. TEST_ESP_OK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM)); // when arrive to minimum limit trigger
  559. // to initialize for PCNT
  560. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  561. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  562. pcnt_evt_queue = xQueueCreate(10, sizeof(uint32_t));
  563. pcnt_isr_handle_t pcnt_isr_service;
  564. TEST_ESP_OK(pcnt_isr_register(pcnt_intr_handler, NULL, 0, &pcnt_isr_service));
  565. TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
  566. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  567. // test event
  568. event_calculate(&event);
  569. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 1);
  570. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 1);
  571. TEST_ASSERT_INT_WITHIN(2, event.l_limit, 1);
  572. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
  573. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 1);
  574. TEST_ASSERT_INT_WITHIN(2, event.filter_time, 2);
  575. // test interrupt disable
  576. TEST_ESP_OK(pcnt_intr_disable(PCNT_UNIT_0));
  577. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  578. // for the original control io disable interrupt status
  579. event_calculate(&event);
  580. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 1);
  581. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 1);
  582. TEST_ASSERT_INT_WITHIN(2, event.l_limit, 1);
  583. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
  584. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 1);
  585. TEST_ASSERT_INT_WITHIN(2, event.filter_time, 2);
  586. // enable the intr
  587. pcnt_unit_config(&config);
  588. pcnt_test_io_config(PCNT_CTRL_LOW_LEVEL);
  589. TEST_ESP_OK(pcnt_intr_enable(PCNT_UNIT_0));
  590. TEST_ESP_OK(pcnt_counter_pause(PCNT_UNIT_0));
  591. TEST_ESP_OK(pcnt_counter_clear(PCNT_UNIT_0));
  592. TEST_ESP_OK(pcnt_counter_resume(PCNT_UNIT_0));
  593. event_calculate(&event);
  594. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 2);
  595. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 3);
  596. TEST_ASSERT_INT_WITHIN(2, event.l_limit, 2);
  597. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
  598. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
  599. TEST_ASSERT_INT_WITHIN(2, event.filter_time, 6);
  600. // disable part of events
  601. TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_ZERO));
  602. TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_L_LIM));
  603. TEST_ESP_OK(pcnt_event_disable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
  604. event_calculate(&event);
  605. TEST_ASSERT_INT_WITHIN(2, event.h_threshold, 4);
  606. TEST_ASSERT_INT_WITHIN(2, event.l_threshold, 3);
  607. TEST_ASSERT_INT_WITHIN(2, event.l_limit, 2);
  608. TEST_ASSERT_INT_WITHIN(2, event.h_limit, 0);
  609. TEST_ASSERT_INT_WITHIN(2, event.zero_times, 2);
  610. TEST_ASSERT_INT_WITHIN(2, event.filter_time, 8);
  611. // Because this test uses its own ISR, we need to release it with `pcnt_isr_unregister` instead of `pcnt_isr_service_uninstall`
  612. TEST_ESP_OK(pcnt_isr_unregister(pcnt_isr_service));
  613. vQueueDelete(pcnt_evt_queue);
  614. }
  615. TEST_CASE("PCNT counting mode test", "[pcnt]")
  616. {
  617. printf("PCNT mode test for positive count\n");
  618. count_mode_test(PCNT_CTRL_VCC_IO);
  619. printf("PCNT mode test for negative count\n");
  620. count_mode_test(PCNT_CTRL_GND_IO);
  621. }
  622. #endif // #if SOC_PCNT_SUPPORTED