test_parlio_tx.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <stdio.h>
  7. #include "sdkconfig.h"
  8. #include "freertos/FreeRTOS.h"
  9. #include "freertos/task.h"
  10. #include "unity.h"
  11. #include "driver/parlio_tx.h"
  12. #include "driver/gpio.h"
  13. #include "soc/soc_caps.h"
  14. #include "esp_attr.h"
  15. #include "test_board.h"
  16. #if CONFIG_PARLIO_ISR_IRAM_SAFE
  17. #define TEST_PARLIO_CALLBACK_ATTR IRAM_ATTR
  18. #else
  19. #define TEST_PARLIO_CALLBACK_ATTR
  20. #endif
  21. TEST_CASE("parallel_tx_unit_install_uninstall", "[parlio_tx]")
  22. {
  23. printf("install tx units exhaustively\r\n");
  24. parlio_tx_unit_handle_t units[SOC_PARLIO_GROUPS * SOC_PARLIO_TX_UNITS_PER_GROUP];
  25. int k = 0;
  26. parlio_tx_unit_config_t config = {
  27. .clk_src = PARLIO_CLK_SRC_DEFAULT,
  28. .data_width = SOC_PARLIO_TX_UNIT_MAX_DATA_WIDTH,
  29. .clk_in_gpio_num = -1, // clock source from internal
  30. .clk_out_gpio_num = 0,
  31. .output_clk_freq_hz = 1 * 1000 * 1000,
  32. .trans_queue_depth = 4,
  33. .max_transfer_size = 64,
  34. .valid_gpio_num = -1,
  35. };
  36. for (int i = 0; i < SOC_PARLIO_GROUPS; i++) {
  37. for (int j = 0; j < SOC_PARLIO_TX_UNITS_PER_GROUP; j++) {
  38. TEST_ESP_OK(parlio_new_tx_unit(&config, &units[k++]));
  39. }
  40. }
  41. TEST_ESP_ERR(ESP_ERR_NOT_FOUND, parlio_new_tx_unit(&config, &units[0]));
  42. for (int i = 0; i < k; i++) {
  43. TEST_ESP_OK(parlio_del_tx_unit(units[i]));
  44. }
  45. printf("install tx unit with valid signal and external core clock\r\n");
  46. // clock from external
  47. config.clk_in_gpio_num = 2;
  48. // failed because of invalid clock source frequency
  49. TEST_ESP_ERR(ESP_ERR_INVALID_ARG, parlio_new_tx_unit(&config, &units[0]));
  50. config.input_clk_src_freq_hz = 1000000;
  51. config.valid_gpio_num = 0;
  52. // failed because of data line conflict with valid signal
  53. TEST_ESP_ERR(ESP_ERR_INVALID_ARG, parlio_new_tx_unit(&config, &units[0]));
  54. config.data_width = 4;
  55. TEST_ESP_OK(parlio_new_tx_unit(&config, &units[0]));
  56. TEST_ESP_OK(parlio_tx_unit_enable(units[0]));
  57. // delete unit before it's disabled is not allowed
  58. TEST_ESP_ERR(ESP_ERR_INVALID_STATE, parlio_del_tx_unit(units[0]));
  59. TEST_ESP_OK(parlio_tx_unit_disable(units[0]));
  60. TEST_ESP_OK(parlio_del_tx_unit(units[0]));
  61. }
  62. TEST_PARLIO_CALLBACK_ATTR
  63. static bool test_parlio_tx_done_callback(parlio_tx_unit_handle_t tx_unit, const parlio_tx_done_event_data_t *edata, void *user_ctx)
  64. {
  65. BaseType_t high_task_wakeup = pdFALSE;
  66. TaskHandle_t task = (TaskHandle_t)user_ctx;
  67. vTaskNotifyGiveFromISR(task, &high_task_wakeup);
  68. return high_task_wakeup == pdTRUE;
  69. }
  70. TEST_CASE("parallel_tx_unit_trans_done_event", "[parlio_tx]")
  71. {
  72. printf("install parlio tx unit\r\n");
  73. parlio_tx_unit_handle_t tx_unit = NULL;
  74. parlio_tx_unit_config_t config = {
  75. .clk_src = PARLIO_CLK_SRC_DEFAULT,
  76. .data_width = 8,
  77. .clk_in_gpio_num = -1, // use internal clock source
  78. .valid_gpio_num = -1, // don't generate valid signal
  79. .clk_out_gpio_num = TEST_CLK_GPIO,
  80. .data_gpio_nums = {
  81. TEST_DATA0_GPIO,
  82. TEST_DATA1_GPIO,
  83. TEST_DATA2_GPIO,
  84. TEST_DATA3_GPIO,
  85. TEST_DATA4_GPIO,
  86. TEST_DATA5_GPIO,
  87. TEST_DATA6_GPIO,
  88. TEST_DATA7_GPIO,
  89. },
  90. .output_clk_freq_hz = 1 * 1000 * 1000,
  91. .trans_queue_depth = 8,
  92. .max_transfer_size = 128,
  93. .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB,
  94. .sample_edge = PARLIO_SAMPLE_EDGE_POS,
  95. };
  96. TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit));
  97. TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
  98. printf("register trans_done event callback\r\n");
  99. parlio_tx_event_callbacks_t cbs = {
  100. .on_trans_done = test_parlio_tx_done_callback,
  101. };
  102. TEST_ESP_OK(parlio_tx_unit_register_event_callbacks(tx_unit, &cbs, xTaskGetCurrentTaskHandle()));
  103. printf("send packets and check event is fired\r\n");
  104. parlio_transmit_config_t transmit_config = {
  105. .idle_value = 0x00,
  106. };
  107. uint8_t payload[64] = {0};
  108. for (int i = 0; i < 64; i++) {
  109. payload[i] = i;
  110. }
  111. TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 64 * sizeof(uint8_t) * 8, &transmit_config));
  112. TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdTRUE, portMAX_DELAY));
  113. TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 64 * sizeof(uint8_t) * 8, &transmit_config));
  114. TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdTRUE, portMAX_DELAY));
  115. TEST_ESP_OK(parlio_tx_unit_disable(tx_unit));
  116. TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
  117. };
  118. TEST_CASE("parallel_tx_unit_enable_disable", "[parlio_tx]")
  119. {
  120. printf("install parlio tx unit\r\n");
  121. parlio_tx_unit_handle_t tx_unit = NULL;
  122. parlio_tx_unit_config_t config = {
  123. .clk_src = PARLIO_CLK_SRC_DEFAULT,
  124. .data_width = 8,
  125. .clk_in_gpio_num = -1, // use internal clock source
  126. .valid_gpio_num = -1, // don't generate valid signal
  127. .clk_out_gpio_num = TEST_CLK_GPIO,
  128. .data_gpio_nums = {
  129. TEST_DATA0_GPIO,
  130. TEST_DATA1_GPIO,
  131. TEST_DATA2_GPIO,
  132. TEST_DATA3_GPIO,
  133. TEST_DATA4_GPIO,
  134. TEST_DATA5_GPIO,
  135. TEST_DATA6_GPIO,
  136. TEST_DATA7_GPIO,
  137. },
  138. .output_clk_freq_hz = 1 * 1000 * 1000,
  139. .trans_queue_depth = 64,
  140. .max_transfer_size = 256,
  141. .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB,
  142. .sample_edge = PARLIO_SAMPLE_EDGE_POS,
  143. };
  144. TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit));
  145. TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
  146. printf("send packets for multiple times\r\n");
  147. parlio_transmit_config_t transmit_config = {
  148. .idle_value = 0x00,
  149. };
  150. uint8_t payload[128] = {0};
  151. for (int i = 0; i < 128; i++) {
  152. payload[i] = i;
  153. }
  154. for (int j = 0; j < 64; j++) {
  155. TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 128 * sizeof(uint8_t) * 8, &transmit_config));
  156. }
  157. printf("disable the transaction in the middle\r\n");
  158. while (parlio_tx_unit_disable(tx_unit) != ESP_OK) {
  159. esp_rom_delay_us(1000);
  160. }
  161. vTaskDelay(pdMS_TO_TICKS(100));
  162. printf("resume the transaction and pending packets should continue\r\n");
  163. TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
  164. TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1));
  165. TEST_ESP_OK(parlio_tx_unit_disable(tx_unit));
  166. TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
  167. }
  168. TEST_CASE("parallel_tx_unit_idle_value", "[parlio_tx]")
  169. {
  170. printf("install parlio tx unit\r\n");
  171. parlio_tx_unit_handle_t tx_unit = NULL;
  172. parlio_tx_unit_config_t config = {
  173. .clk_src = PARLIO_CLK_SRC_DEFAULT,
  174. .data_width = 8,
  175. .clk_in_gpio_num = -1, // use internal clock source
  176. .valid_gpio_num = -1, // don't generate valid signal
  177. .clk_out_gpio_num = TEST_CLK_GPIO,
  178. .data_gpio_nums = {
  179. TEST_DATA0_GPIO,
  180. TEST_DATA1_GPIO,
  181. TEST_DATA2_GPIO,
  182. TEST_DATA3_GPIO,
  183. TEST_DATA4_GPIO,
  184. TEST_DATA5_GPIO,
  185. TEST_DATA6_GPIO,
  186. TEST_DATA7_GPIO,
  187. },
  188. .output_clk_freq_hz = 1 * 1000 * 1000,
  189. .trans_queue_depth = 4,
  190. .max_transfer_size = 64,
  191. .bit_pack_order = PARLIO_BIT_PACK_ORDER_LSB,
  192. .sample_edge = PARLIO_SAMPLE_EDGE_POS,
  193. .flags.io_loop_back = 1, // enable loop back by GPIO matrix, so that we can read the level of the data line by gpio driver
  194. };
  195. TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit));
  196. TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
  197. printf("send packet with different idle_value\r\n");
  198. parlio_transmit_config_t transmit_config = {
  199. .idle_value = 0x00,
  200. };
  201. uint8_t payload[8] = {0};
  202. for (int i = 0; i < 8; i++) {
  203. payload[i] = i;
  204. }
  205. for (int j = 0; j < 16; j++) {
  206. transmit_config.idle_value = j;
  207. TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, sizeof(payload) * 8, &transmit_config));
  208. TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, 100));
  209. TEST_ASSERT_EQUAL(j & 0x01, gpio_get_level(TEST_DATA0_GPIO));
  210. }
  211. TEST_ESP_OK(parlio_tx_unit_disable(tx_unit));
  212. TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
  213. }
  214. #if SOC_PARLIO_TX_CLK_SUPPORT_GATING
  215. TEST_CASE("parallel_tx_clock_gating", "[paralio_tx]")
  216. {
  217. printf("install parlio tx unit\r\n");
  218. parlio_tx_unit_handle_t tx_unit = NULL;
  219. parlio_tx_unit_config_t config = {
  220. .clk_src = PARLIO_CLK_SRC_DEFAULT,
  221. .data_width = 2,
  222. .clk_in_gpio_num = -1, // use internal clock source
  223. .valid_gpio_num = TEST_DATA7_GPIO, // generate the valid signal
  224. .clk_out_gpio_num = TEST_CLK_GPIO,
  225. .data_gpio_nums = {
  226. TEST_DATA0_GPIO,
  227. TEST_DATA1_GPIO,
  228. },
  229. .output_clk_freq_hz = 1 * 1000 * 1000,
  230. .trans_queue_depth = 4,
  231. .max_transfer_size = 64,
  232. .bit_pack_order = PARLIO_BIT_PACK_ORDER_MSB,
  233. .sample_edge = PARLIO_SAMPLE_EDGE_POS,
  234. .flags.clk_gate_en = true, // enable clock gating, controlled by the level of TEST_DATA7_GPIO
  235. .flags.io_loop_back = true, // for reading the level of the clock line in IDLE state
  236. };
  237. TEST_ESP_OK(parlio_new_tx_unit(&config, &tx_unit));
  238. TEST_ESP_OK(parlio_tx_unit_enable(tx_unit));
  239. printf("send packets and see if the clock is gated when there's no transaction on line\r\n");
  240. parlio_transmit_config_t transmit_config = {
  241. .idle_value = 0x00,
  242. };
  243. uint8_t payload[8] = {0};
  244. for (int i = 0; i < 8; i++) {
  245. payload[i] = 0x1B; // 8'b00011011, in PARLIO_BIT_PACK_ORDER_MSB, you should see 2'b00, 2'b01, 2'b10, 2'b11 on the data line
  246. }
  247. TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 8 * sizeof(uint8_t) * 8, &transmit_config));
  248. TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1));
  249. // check if the level on the clock line is low
  250. TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO));
  251. TEST_ESP_OK(parlio_tx_unit_transmit(tx_unit, payload, 8 * sizeof(uint8_t) * 8, &transmit_config));
  252. TEST_ESP_OK(parlio_tx_unit_wait_all_done(tx_unit, -1));
  253. TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO));
  254. TEST_ASSERT_EQUAL(0, gpio_get_level(TEST_CLK_GPIO));
  255. TEST_ESP_OK(parlio_tx_unit_disable(tx_unit));
  256. TEST_ESP_OK(parlio_del_tx_unit(tx_unit));
  257. }
  258. #endif // SOC_PARLIO_TX_CLK_SUPPORT_GATING