test_pcnt.c 25 KB

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