test_rmt.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. // RMT driver unit test is based on extended NEC protocol
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include "sdkconfig.h"
  10. #include "hal/cpu_hal.h"
  11. #include "hal/gpio_hal.h"
  12. #include "freertos/FreeRTOS.h"
  13. #include "freertos/task.h"
  14. #include "esp_log.h"
  15. #include "unity.h"
  16. #include "test_utils.h"
  17. #include "esp_rom_gpio.h"
  18. #if SOC_RMT_SUPPORTED
  19. #include "ir_tools.h"
  20. #include "driver/rmt.h"
  21. #define RMT_RX_CHANNEL_ENCODING_START (SOC_RMT_CHANNELS_PER_GROUP-SOC_RMT_TX_CANDIDATES_PER_GROUP)
  22. #define RMT_TX_CHANNEL_ENCODING_END (SOC_RMT_TX_CANDIDATES_PER_GROUP-1)
  23. // CI ONLY: Don't connect any other signals to this GPIO
  24. #define RMT_DATA_IO (0) // bind signal RMT_SIG_OUT0_IDX and RMT_SIG_IN0_IDX on the same GPIO
  25. #define RMT_TESTBENCH_FLAGS_ALWAYS_ON (1<<0)
  26. #define RMT_TESTBENCH_FLAGS_CARRIER_ON (1<<1)
  27. #define RMT_TESTBENCH_FLAGS_LOOP_ON (1<<2)
  28. static const char *TAG = "RMT.test";
  29. static ir_builder_t *s_ir_builder = NULL;
  30. static ir_parser_t *s_ir_parser = NULL;
  31. static void rmt_setup_testbench(int tx_channel, int rx_channel, uint32_t flags)
  32. {
  33. // RMT channel configuration
  34. if (tx_channel >= 0) {
  35. rmt_config_t tx_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, tx_channel);
  36. if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
  37. tx_config.flags |= RMT_CHANNEL_FLAGS_AWARE_DFS;
  38. }
  39. if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
  40. tx_config.tx_config.carrier_en = true;
  41. }
  42. #if SOC_RMT_SUPPORT_TX_LOOP_COUNT
  43. if (flags & RMT_TESTBENCH_FLAGS_LOOP_ON) {
  44. tx_config.tx_config.loop_en = true;
  45. tx_config.tx_config.loop_count = 10;
  46. }
  47. #endif
  48. TEST_ESP_OK(rmt_config(&tx_config));
  49. }
  50. if (rx_channel >= 0) {
  51. rmt_config_t rx_config = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, rx_channel);
  52. if (flags & RMT_TESTBENCH_FLAGS_ALWAYS_ON) {
  53. rx_config.flags |= RMT_CHANNEL_FLAGS_AWARE_DFS;
  54. }
  55. #if SOC_RMT_SUPPORT_RX_DEMODULATION
  56. if (flags & RMT_TESTBENCH_FLAGS_CARRIER_ON) {
  57. rx_config.rx_config.rm_carrier = true;
  58. rx_config.rx_config.carrier_freq_hz = 38000;
  59. rx_config.rx_config.carrier_duty_percent = 33;
  60. rx_config.rx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH;
  61. }
  62. #endif
  63. TEST_ESP_OK(rmt_config(&rx_config));
  64. }
  65. // Routing internal signals by IO Matrix (bind rmt tx and rx signal on the same GPIO)
  66. gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[RMT_DATA_IO], PIN_FUNC_GPIO);
  67. TEST_ESP_OK(gpio_set_direction(RMT_DATA_IO, GPIO_MODE_INPUT_OUTPUT));
  68. esp_rom_gpio_connect_out_signal(RMT_DATA_IO, RMT_SIG_OUT0_IDX + tx_channel, 0, 0);
  69. esp_rom_gpio_connect_in_signal(RMT_DATA_IO, RMT_SIG_IN0_IDX + rx_channel, 0);
  70. // install driver
  71. if (tx_channel >= 0) {
  72. TEST_ESP_OK(rmt_driver_install(tx_channel, 0, 0));
  73. ir_builder_config_t ir_builder_config = IR_BUILDER_DEFAULT_CONFIG((ir_dev_t)tx_channel);
  74. ir_builder_config.flags = IR_TOOLS_FLAGS_PROTO_EXT;
  75. s_ir_builder = ir_builder_rmt_new_nec(&ir_builder_config);
  76. TEST_ASSERT_NOT_NULL(s_ir_builder);
  77. }
  78. if (rx_channel >= 0) {
  79. TEST_ESP_OK(rmt_driver_install(rx_channel, 3000, 0));
  80. ir_parser_config_t ir_parser_config = IR_PARSER_DEFAULT_CONFIG((ir_dev_t)rx_channel);
  81. ir_parser_config.flags = IR_TOOLS_FLAGS_PROTO_EXT | IR_TOOLS_FLAGS_INVERSE;
  82. s_ir_parser = ir_parser_rmt_new_nec(&ir_parser_config);
  83. TEST_ASSERT_NOT_NULL(s_ir_parser);
  84. }
  85. }
  86. static void rmt_clean_testbench(int tx_channel, int rx_channel)
  87. {
  88. if (tx_channel >= 0) {
  89. TEST_ESP_OK(rmt_driver_uninstall(tx_channel));
  90. TEST_ESP_OK(s_ir_builder->del(s_ir_builder));
  91. s_ir_builder = NULL;
  92. }
  93. if (rx_channel >= 0) {
  94. TEST_ESP_OK(rmt_driver_uninstall(rx_channel));
  95. TEST_ESP_OK(s_ir_parser->del(s_ir_parser));
  96. s_ir_parser = NULL;
  97. }
  98. }
  99. TEST_CASE("RMT wrong configuration", "[rmt]")
  100. {
  101. rmt_config_t correct_config = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
  102. rmt_config_t wrong_config = correct_config;
  103. wrong_config.clk_div = 0;
  104. TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
  105. wrong_config = correct_config;
  106. wrong_config.channel = SOC_RMT_CHANNELS_PER_GROUP;
  107. TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
  108. wrong_config = correct_config;
  109. wrong_config.channel = 2;
  110. wrong_config.mem_block_num = 8;
  111. TEST_ASSERT(rmt_config(&wrong_config) == ESP_ERR_INVALID_ARG);
  112. TEST_ASSERT(rmt_set_mem_block_num(wrong_config.channel, -1) == ESP_ERR_INVALID_ARG);
  113. }
  114. TEST_CASE("RMT miscellaneous functions", "[rmt]")
  115. {
  116. rmt_channel_t channel = 0;
  117. uint8_t div_cnt;
  118. rmt_source_clk_t src_clk;
  119. uint8_t memNum;
  120. uint16_t idle_thres;
  121. rmt_mem_owner_t owner;
  122. // TX related functions
  123. rmt_setup_testbench(channel, -1, 0);
  124. TEST_ESP_OK(rmt_set_mem_block_num(channel, 2));
  125. TEST_ESP_OK(rmt_get_mem_block_num(channel, &memNum));
  126. TEST_ASSERT_EQUAL_UINT8(2, memNum);
  127. TEST_ESP_OK(rmt_set_clk_div(channel, 160));
  128. TEST_ESP_OK(rmt_get_clk_div(channel, &div_cnt));
  129. TEST_ASSERT_EQUAL_UINT8(160, div_cnt);
  130. #if SOC_RMT_SUPPORT_REF_TICK
  131. TEST_ESP_OK(rmt_set_source_clk(channel, RMT_BASECLK_REF));
  132. TEST_ESP_OK(rmt_get_source_clk(channel, &src_clk));
  133. TEST_ASSERT_EQUAL_INT(RMT_BASECLK_REF, src_clk);
  134. #endif
  135. #if SOC_RMT_SUPPORT_XTAL
  136. TEST_ESP_OK(rmt_set_source_clk(channel, RMT_BASECLK_XTAL));
  137. TEST_ESP_OK(rmt_get_source_clk(channel, &src_clk));
  138. TEST_ASSERT_EQUAL_INT(RMT_BASECLK_XTAL, src_clk);
  139. #endif
  140. TEST_ESP_OK(rmt_set_tx_carrier(channel, 0, 10, 10, 1));
  141. TEST_ESP_OK(rmt_set_idle_level(channel, 1, 0));
  142. rmt_clean_testbench(channel, -1);
  143. // RX related functions
  144. channel = RMT_RX_CHANNEL_ENCODING_START;
  145. rmt_setup_testbench(-1, channel, 0);
  146. TEST_ESP_OK(rmt_set_rx_idle_thresh(channel, 200));
  147. TEST_ESP_OK(rmt_get_rx_idle_thresh(channel, &idle_thres));
  148. TEST_ASSERT_EQUAL_UINT16(200, idle_thres);
  149. TEST_ESP_OK(rmt_set_rx_filter(channel, 1, 100));
  150. TEST_ESP_OK(rmt_set_memory_owner(channel, RMT_MEM_OWNER_RX));
  151. TEST_ESP_OK(rmt_get_memory_owner(channel, &owner));
  152. TEST_ASSERT_EQUAL_INT(RMT_MEM_OWNER_RX, owner);
  153. rmt_clean_testbench(-1, channel);
  154. }
  155. TEST_CASE("RMT multiple channels", "[rmt]")
  156. {
  157. rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
  158. for (int i = 0; i < SOC_RMT_TX_CANDIDATES_PER_GROUP; i++) {
  159. tx_cfg.channel = i;
  160. TEST_ESP_OK(rmt_config(&tx_cfg));
  161. TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 0, 0));
  162. }
  163. for (int i = 0; i < SOC_RMT_TX_CANDIDATES_PER_GROUP; i++) {
  164. TEST_ESP_OK(rmt_driver_uninstall(i));
  165. }
  166. rmt_config_t rx_cfg = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, RMT_RX_CHANNEL_ENCODING_START);
  167. for (int i = RMT_RX_CHANNEL_ENCODING_START; i < SOC_RMT_CHANNELS_PER_GROUP; i++) {
  168. rx_cfg.channel = i;
  169. TEST_ESP_OK(rmt_config(&rx_cfg));
  170. TEST_ESP_OK(rmt_driver_install(rx_cfg.channel, 0, 0));
  171. }
  172. for (int i = RMT_RX_CHANNEL_ENCODING_START; i < SOC_RMT_CHANNELS_PER_GROUP; i++) {
  173. TEST_ESP_OK(rmt_driver_uninstall(i));
  174. }
  175. }
  176. TEST_CASE("RMT install/uninstall test", "[rmt]")
  177. {
  178. rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, RMT_TX_CHANNEL_ENCODING_END);
  179. TEST_ESP_OK(rmt_config(&tx_cfg));
  180. for (int i = 0; i < 100; i++) {
  181. TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 1000, 0));
  182. TEST_ESP_OK(rmt_driver_uninstall(tx_cfg.channel));
  183. }
  184. rmt_config_t rx_cfg = RMT_DEFAULT_CONFIG_RX(RMT_DATA_IO, RMT_RX_CHANNEL_ENCODING_START);
  185. TEST_ESP_OK(rmt_config(&rx_cfg));
  186. for (int i = 0; i < 100; i++) {
  187. TEST_ESP_OK(rmt_driver_install(rx_cfg.channel, 1000, 0));
  188. TEST_ESP_OK(rmt_driver_uninstall(rx_cfg.channel));
  189. }
  190. }
  191. static void test_rmt_translator(const void *src, rmt_item32_t *dest, size_t src_size,
  192. size_t wanted_num, size_t *translated_size, size_t *item_num)
  193. {
  194. const rmt_item32_t bit0 = {{{ 10, 1, 20, 0 }}}; //Logical 0
  195. const rmt_item32_t bit1 = {{{ 20, 1, 10, 0 }}}; //Logical 1
  196. size_t size = 0;
  197. size_t num = 0;
  198. uint8_t *psrc = (uint8_t *)src;
  199. rmt_item32_t *pdest = dest;
  200. while (size < src_size && num < wanted_num) {
  201. for (int i = 0; i < 8; i++) {
  202. // MSB first
  203. if (*psrc & (1 << (7 - i))) {
  204. pdest->val = bit1.val;
  205. } else {
  206. pdest->val = bit0.val;
  207. }
  208. num++;
  209. pdest++;
  210. }
  211. size++;
  212. psrc++;
  213. }
  214. *translated_size = size;
  215. *item_num = num;
  216. int *user_data = NULL;
  217. rmt_translator_get_context(item_num, (void **)&user_data);
  218. esp_rom_printf("user data=%d\r\n", *user_data);
  219. *user_data = 100;
  220. }
  221. TEST_CASE("RMT translator with user context", "[rmt]")
  222. {
  223. rmt_config_t tx_cfg = RMT_DEFAULT_CONFIG_TX(RMT_DATA_IO, 0);
  224. TEST_ESP_OK(rmt_config(&tx_cfg));
  225. TEST_ESP_OK(rmt_driver_install(tx_cfg.channel, 0, 0));
  226. rmt_translator_init(tx_cfg.channel, test_rmt_translator);
  227. int user_data = 999;
  228. rmt_translator_set_context(tx_cfg.channel, &user_data);
  229. uint8_t test_buf[] = {1, 2, 3, 4, 5, 6};
  230. rmt_write_sample(tx_cfg.channel, test_buf, sizeof(test_buf), true);
  231. vTaskDelay(pdMS_TO_TICKS(100));
  232. TEST_ASSERT_EQUAL(100, user_data);
  233. TEST_ESP_OK(rmt_driver_uninstall(tx_cfg.channel));
  234. }
  235. static void do_nec_tx_rx(uint32_t flags)
  236. {
  237. RingbufHandle_t rb = NULL;
  238. rmt_item32_t *items = NULL;
  239. size_t length = 0;
  240. uint32_t addr = 0x10;
  241. uint32_t cmd = 0x20;
  242. bool repeat = false;
  243. int tx_channel = 0;
  244. int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
  245. // test on different flags combinations
  246. rmt_setup_testbench(tx_channel, rx_channel, flags);
  247. // get ready to receive
  248. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  249. TEST_ASSERT_NOT_NULL(rb);
  250. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  251. vTaskDelay(pdMS_TO_TICKS(1000));
  252. // build NEC codes
  253. cmd = 0x20;
  254. while (cmd <= 0x30) {
  255. ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
  256. // Send new key code
  257. TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
  258. TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length));
  259. if (cmd & 0x01) {
  260. TEST_ESP_OK(rmt_write_items(tx_channel, items, length, false)); // no wait
  261. TEST_ESP_OK(rmt_wait_tx_done(tx_channel, portMAX_DELAY));
  262. } else {
  263. TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
  264. }
  265. cmd++;
  266. }
  267. // parse NEC codes
  268. while (rb) {
  269. items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  270. if (items) {
  271. length /= 4; // one RMT = 4 Bytes
  272. if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) {
  273. if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
  274. ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
  275. }
  276. }
  277. vRingbufferReturnItem(rb, (void *) items);
  278. } else {
  279. ESP_LOGI(TAG, "done");
  280. break;
  281. }
  282. }
  283. TEST_ASSERT_EQUAL(0x30, cmd);
  284. rmt_clean_testbench(tx_channel, rx_channel);
  285. }
  286. // basic nec tx and rx test, using APB source clock, no modulation
  287. TEST_CASE("RMT NEC TX and RX (APB)", "[rmt]")
  288. {
  289. do_nec_tx_rx(0);
  290. }
  291. // test with RMT_TESTBENCH_FLAGS_ALWAYS_ON will take a long time (REF_TICK is much slower than APB CLOCK)
  292. TEST_CASE("RMT NEC TX and RX (always on)", "[rmt][timeout=240]")
  293. {
  294. do_nec_tx_rx(RMT_TESTBENCH_FLAGS_ALWAYS_ON);
  295. }
  296. #if SOC_RMT_SUPPORT_RX_DEMODULATION
  297. // basic nec tx and rx test, using APB source clock, with modulation and demodulation on
  298. TEST_CASE("RMT NEC TX and RX (Modulation/Demodulation)", "[rmt]")
  299. {
  300. do_nec_tx_rx(RMT_TESTBENCH_FLAGS_CARRIER_ON);
  301. }
  302. #endif
  303. TEST_CASE("RMT TX (SOC_RMT_MEM_WORDS_PER_CHANNEL-1) symbols", "[rmt][boundary]")
  304. {
  305. int tx_channel = 0;
  306. rmt_setup_testbench(tx_channel, -1, 0);
  307. rmt_item32_t *items = malloc(sizeof(rmt_item32_t) * (SOC_RMT_MEM_WORDS_PER_CHANNEL - 1));
  308. for (int i = 0; i < SOC_RMT_MEM_WORDS_PER_CHANNEL - 1; i++) {
  309. items[i] = (rmt_item32_t) {
  310. {{
  311. 200, 1, 200, 0
  312. }
  313. }
  314. };
  315. }
  316. TEST_ESP_OK(rmt_write_items(tx_channel, items, SOC_RMT_MEM_WORDS_PER_CHANNEL - 1, 1));
  317. free(items);
  318. rmt_clean_testbench(tx_channel, -1);
  319. }
  320. TEST_CASE("RMT TX stop", "[rmt]")
  321. {
  322. RingbufHandle_t rb = NULL;
  323. rmt_item32_t *frames = NULL;
  324. size_t length = 0;
  325. uint32_t count = 10;
  326. uint32_t addr = 0x10;
  327. uint32_t cmd = 0x20;
  328. bool repeat = false;
  329. int tx_channel = 0;
  330. int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
  331. rmt_setup_testbench(tx_channel, rx_channel, 0);
  332. // re-install ir_builder, to enlarge internal buffer size
  333. TEST_ESP_OK(s_ir_builder->del(s_ir_builder));
  334. ir_builder_config_t ir_builder_config = IR_BUILDER_DEFAULT_CONFIG((ir_dev_t)tx_channel);
  335. ir_builder_config.buffer_size *= count;
  336. ir_builder_config.flags = IR_TOOLS_FLAGS_PROTO_EXT;
  337. s_ir_builder = ir_builder_rmt_new_nec(&ir_builder_config);
  338. TEST_ASSERT_NOT_NULL(s_ir_builder);
  339. // get ready to receive
  340. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  341. TEST_ASSERT_NOT_NULL(rb);
  342. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  343. vTaskDelay(pdMS_TO_TICKS(1000));
  344. // build NEC codes
  345. ESP_LOGI(TAG, "Plan to send command 0x%x~0x%x to address 0x%x", cmd, cmd + count, addr);
  346. for (int i = 0; i <= count; i++) {
  347. TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
  348. cmd++;
  349. }
  350. TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &frames, &length));
  351. // send for 1 second and then stop
  352. TEST_ESP_OK(rmt_write_items(tx_channel, frames, length, true));
  353. vTaskDelay(pdMS_TO_TICKS(100));
  354. TEST_ESP_OK(rmt_tx_stop(tx_channel));
  355. // parse NEC codes
  356. uint32_t num = 0;
  357. while (rb) {
  358. frames = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  359. if (frames) {
  360. length /= 4; // one RMT = 4 Bytes
  361. if (s_ir_parser->input(s_ir_parser, frames, length) == ESP_OK) {
  362. if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
  363. ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
  364. num++;
  365. }
  366. }
  367. vRingbufferReturnItem(rb, (void *) frames);
  368. } else {
  369. ESP_LOGI(TAG, "done");
  370. break;
  371. }
  372. }
  373. TEST_ASSERT(num < count);
  374. rmt_clean_testbench(tx_channel, rx_channel);
  375. }
  376. #if SOC_RMT_SUPPORT_RX_PINGPONG
  377. TEST_CASE("RMT Ping-Pong operation", "[rmt]")
  378. {
  379. int tx_channel = 0;
  380. int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
  381. rmt_item32_t frames[SOC_RMT_MEM_WORDS_PER_CHANNEL * 2]; // send two block data using ping-pong
  382. RingbufHandle_t rb = NULL;
  383. uint32_t size = sizeof(frames) / sizeof(frames[0]);
  384. // The design of the following test frame should trigger three rx threshold interrupt and one rx end interrupt
  385. int i = 0;
  386. for (i = 0; i < size - 1; i++) {
  387. frames[i].level0 = 1;
  388. frames[i].duration0 = 100;
  389. frames[i].level1 = 0;
  390. frames[i].duration1 = 100;
  391. }
  392. frames[i].level0 = 1;
  393. frames[i].duration0 = 0;
  394. frames[i].level1 = 0;
  395. frames[i].duration1 = 0;
  396. rmt_setup_testbench(tx_channel, rx_channel, 0);
  397. // get ready to receive
  398. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  399. TEST_ASSERT_NOT_NULL(rb);
  400. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  401. vTaskDelay(pdMS_TO_TICKS(1000));
  402. for (uint32_t test_count = 0; test_count < 5; test_count++) {
  403. TEST_ESP_OK(rmt_write_items(tx_channel, frames, size, true));
  404. // parse received data
  405. size_t length = 0;
  406. rmt_item32_t *items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  407. if (items) {
  408. vRingbufferReturnItem(rb, (void *) items);
  409. }
  410. TEST_ASSERT_EQUAL(4 * (size - 1), length);
  411. }
  412. rmt_clean_testbench(tx_channel, rx_channel);
  413. }
  414. #endif
  415. #if SOC_RMT_SUPPORT_TX_SYNCHRO
  416. static uint32_t tx_end_time0, tx_end_time1;
  417. static void rmt_tx_end_cb(rmt_channel_t channel, void *arg)
  418. {
  419. if (channel == 0) {
  420. tx_end_time0 = cpu_hal_get_cycle_count();
  421. } else {
  422. tx_end_time1 = cpu_hal_get_cycle_count();
  423. }
  424. }
  425. TEST_CASE("RMT TX simultaneously", "[rmt]")
  426. {
  427. rmt_item32_t frames[SOC_RMT_MEM_WORDS_PER_CHANNEL];
  428. uint32_t size = sizeof(frames) / sizeof(frames[0]);
  429. int channel0 = 0;
  430. int channel1 = 1;
  431. int i = 0;
  432. for (i = 0; i < size - 1; i++) {
  433. frames[i].level0 = 1;
  434. frames[i].duration0 = 1000;
  435. frames[i].level1 = 0;
  436. frames[i].duration1 = 1000;
  437. }
  438. frames[i].level0 = 0;
  439. frames[i].duration0 = 0;
  440. frames[i].level1 = 0;
  441. frames[i].duration1 = 0;
  442. rmt_config_t tx_config0 = RMT_DEFAULT_CONFIG_TX(4, channel0);
  443. rmt_config_t tx_config1 = RMT_DEFAULT_CONFIG_TX(5, channel1);
  444. TEST_ESP_OK(rmt_config(&tx_config0));
  445. TEST_ESP_OK(rmt_config(&tx_config1));
  446. TEST_ESP_OK(rmt_driver_install(channel0, 0, 0));
  447. TEST_ESP_OK(rmt_driver_install(channel1, 0, 0));
  448. rmt_register_tx_end_callback(rmt_tx_end_cb, NULL);
  449. TEST_ESP_OK(rmt_add_channel_to_group(channel0));
  450. TEST_ESP_OK(rmt_add_channel_to_group(channel1));
  451. TEST_ESP_OK(rmt_write_items(channel0, frames, size, false));
  452. vTaskDelay(pdMS_TO_TICKS(1000));
  453. TEST_ESP_OK(rmt_write_items(channel1, frames, size, false));
  454. TEST_ESP_OK(rmt_wait_tx_done(channel0, portMAX_DELAY));
  455. TEST_ESP_OK(rmt_wait_tx_done(channel1, portMAX_DELAY));
  456. ESP_LOGI(TAG, "tx_end_time0=%u, tx_end_time1=%u", tx_end_time0, tx_end_time1);
  457. TEST_ASSERT_LESS_OR_EQUAL_UINT32(2000, tx_end_time1 - tx_end_time0);
  458. TEST_ESP_OK(rmt_remove_channel_from_group(channel0));
  459. TEST_ESP_OK(rmt_remove_channel_from_group(channel1));
  460. TEST_ESP_OK(rmt_driver_uninstall(channel0));
  461. TEST_ESP_OK(rmt_driver_uninstall(channel1));
  462. }
  463. #endif
  464. #if SOC_RMT_SUPPORT_TX_LOOP_COUNT
  465. static void rmt_tx_loop_end(rmt_channel_t channel, void *arg)
  466. {
  467. rmt_tx_stop(channel);
  468. }
  469. TEST_CASE("RMT TX loop", "[rmt]")
  470. {
  471. RingbufHandle_t rb = NULL;
  472. rmt_item32_t *items = NULL;
  473. size_t length = 0;
  474. uint32_t addr = 0x10;
  475. uint32_t cmd = 0x20;
  476. bool repeat = false;
  477. int tx_channel = 0;
  478. int rx_channel = RMT_RX_CHANNEL_ENCODING_START + 1;
  479. uint32_t count = 0;
  480. rmt_setup_testbench(tx_channel, rx_channel, RMT_TESTBENCH_FLAGS_LOOP_ON);
  481. // get ready to receive
  482. TEST_ESP_OK(rmt_get_ringbuf_handle(rx_channel, &rb));
  483. TEST_ASSERT_NOT_NULL(rb);
  484. TEST_ESP_OK(rmt_rx_start(rx_channel, true));
  485. vTaskDelay(pdMS_TO_TICKS(1000));
  486. // register callback functions, invoked when tx loop count to ceiling
  487. rmt_register_tx_end_callback(rmt_tx_loop_end, NULL);
  488. // build NEC codes
  489. ESP_LOGI(TAG, "Send command 0x%x to address 0x%x", cmd, addr);
  490. // Send new key code
  491. TEST_ESP_OK(s_ir_builder->build_frame(s_ir_builder, addr, cmd));
  492. TEST_ESP_OK(s_ir_builder->get_result(s_ir_builder, &items, &length));
  493. TEST_ESP_OK(rmt_write_items(tx_channel, items, length, true)); // wait until done
  494. // parse NEC codes
  495. while (rb) {
  496. items = (rmt_item32_t *) xRingbufferReceive(rb, &length, 1000);
  497. if (items) {
  498. length /= 4; // one RMT = 4 Bytes
  499. if (s_ir_parser->input(s_ir_parser, items, length) == ESP_OK) {
  500. if (s_ir_parser->get_scan_code(s_ir_parser, &addr, &cmd, &repeat) == ESP_OK) {
  501. count++;
  502. ESP_LOGI(TAG, "Scan Code %s --- addr: 0x%04x cmd: 0x%04x", repeat ? "(repeat)" : "", addr, cmd);
  503. }
  504. }
  505. vRingbufferReturnItem(rb, (void *) items);
  506. } else {
  507. ESP_LOGI(TAG, "done");
  508. break;
  509. }
  510. }
  511. TEST_ASSERT_EQUAL(10, count);
  512. rmt_clean_testbench(tx_channel, rx_channel);
  513. }
  514. #endif
  515. #endif // SOC_RMT_SUPPORTED