test_pdma.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. * Copyright (c) 2006-2025, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. /*
  7. * Refer to PDMA driver implementation and hardware specifications
  8. * This is a PDMA (Peripheral DMA) device test routine. The program tests:
  9. * - Channel allocation/release functionality
  10. * - DMA transfer from DDR to UART (TX)
  11. * - DMA transfer from UART to DDR (RX)
  12. *
  13. * "test_pdma_tx" tests DDR-to-UART transmission:
  14. * - Should display 3 identical rows of data on screen
  15. * - Each row consists of 62 'x' characters
  16. * - Total output should contain exactly 186 'x' characters
  17. * - Data is transferred from DDR to UART0 TX FIFO via PDMA
  18. *
  19. * "test_pdma_rx" tests UART-to-DDR reception:
  20. * - After "Send test data by keyboard input within 2 seconds" prompt appears:
  21. * - User has 2 seconds to input data via keyboard
  22. * - Input will be captured via UART0 RX FIFO to DDR through PDMA
  23. * - Test will display first 16 bytes of received DDR data
  24. * - Verify output matches partial input data
  25. */
  26. #include <rtthread.h>
  27. #include <rtdevice.h>
  28. #include "utest.h"
  29. #include <mmu.h>
  30. #include "board.h"
  31. #include "drv_pdma.h"
  32. #define UART0_IRQ K230_IRQ_UART0
  33. #define CACHE_LINE_SIZE 64
  34. typedef enum
  35. {
  36. TEST_PDMA_EVENT_NONE,
  37. TEST_PDMA_EVENT_COMPLETE,
  38. TEST_PDMA_EVENT_TIMEOUT
  39. } test_pdma_event_t;
  40. static rt_event_t test_pdma_event = RT_NULL;
  41. void test_pdma_call_back(rt_uint8_t ch, rt_bool_t is_done)
  42. {
  43. /* Send completion or timeout event based on callback status */
  44. test_pdma_event_t event_type = is_done ? TEST_PDMA_EVENT_COMPLETE : TEST_PDMA_EVENT_TIMEOUT;
  45. rt_event_send(test_pdma_event, event_type);
  46. }
  47. void test_pdma_request()
  48. {
  49. rt_uint8_t ch;
  50. rt_err_t err;
  51. /* Test channel allocation for all available channels */
  52. for (rt_uint8_t i = 0; i < PDMA_CH_MAX; i++)
  53. {
  54. err = k230_pdma_request_channel(&ch);
  55. uassert_int_equal(err, RT_EOK);
  56. }
  57. /* Should fail when all channels are allocated */
  58. err = k230_pdma_request_channel(&ch);
  59. uassert_int_equal(err, -RT_EBUSY);
  60. /* Release channel 0 and test re-allocation */
  61. err = k230_pdma_release_channel(0);
  62. uassert_int_equal(err, RT_EOK);
  63. err = k230_pdma_request_channel(&ch);
  64. uassert_int_equal(err, RT_EOK);
  65. /* Cleanup: release all channels */
  66. for (rt_uint8_t i = 0; i < PDMA_CH_MAX; i++)
  67. {
  68. err = k230_pdma_release_channel(i);
  69. uassert_int_equal(err, RT_EOK);
  70. }
  71. }
  72. /* Test DMA transfer from DDR to UART output */
  73. void test_pdma_tx()
  74. {
  75. rt_uint8_t ch;
  76. rt_err_t err;
  77. rt_uint32_t recv_event;
  78. rt_uint32_t len = 192;
  79. /* For software-managed DMA cache coherency, ensure buffer start address and size are cache-line aligned */
  80. uint8_t *buf = rt_malloc_align(len, CACHE_LINE_SIZE);
  81. void *buf_pa = rt_kmem_v2p(buf);
  82. for (int i = 0; i < 192; i++)
  83. {
  84. if ((i + 2) % 64 == 0)
  85. {
  86. buf[i] = '\r';
  87. }
  88. else if ((i + 1) % 64 == 0)
  89. {
  90. buf[i] = '\n';
  91. }
  92. else
  93. {
  94. buf[i] = 'x';
  95. }
  96. }
  97. rt_event_control(test_pdma_event, RT_IPC_CMD_RESET, NULL);
  98. /* Configure DMA transfer */
  99. err = k230_pdma_request_channel(&ch);
  100. uassert_int_equal(err, RT_EOK);
  101. usr_pdma_cfg_t pdma_cfg;
  102. /* Configure DMA parameters */
  103. pdma_cfg.device = UART0_TX;
  104. pdma_cfg.src_addr = buf_pa;
  105. pdma_cfg.dst_addr = (rt_uint8_t *)UART0_BASE_ADDR;
  106. pdma_cfg.line_size = len;
  107. /* Set channel configuration */
  108. pdma_cfg.pdma_ch_cfg.ch_src_type = CONTINUE;
  109. pdma_cfg.pdma_ch_cfg.ch_dev_hsize = PSBYTE1;
  110. pdma_cfg.pdma_ch_cfg.ch_dat_endian = PDEFAULT;
  111. pdma_cfg.pdma_ch_cfg.ch_dev_blen = PBURST_LEN_16;
  112. pdma_cfg.pdma_ch_cfg.ch_priority = 7;
  113. pdma_cfg.pdma_ch_cfg.ch_dev_tout = 0xFFF;
  114. err = k230_pdma_set_callback(ch, test_pdma_call_back);
  115. uassert_int_equal(err, RT_EOK);
  116. err = k230_pdma_config(ch, &pdma_cfg);
  117. uassert_int_equal(err, RT_EOK);
  118. /* Start transfer and wait for completion */
  119. err = k230_pdma_start(ch);
  120. uassert_int_equal(err, RT_EOK);
  121. err = rt_event_recv(test_pdma_event,
  122. TEST_PDMA_EVENT_COMPLETE | TEST_PDMA_EVENT_TIMEOUT,
  123. RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  124. RT_WAITING_FOREVER,
  125. &recv_event);
  126. uassert_int_equal(err, RT_EOK);
  127. uassert_int_equal(recv_event, TEST_PDMA_EVENT_COMPLETE);
  128. /* Cleanup */
  129. err = k230_pdma_stop(ch);
  130. uassert_int_equal(err, RT_EOK);
  131. err = k230_pdma_release_channel(ch);
  132. uassert_int_equal(err, RT_EOK);
  133. rt_free_align(buf);
  134. LOG_I("PDMA TX test completed successfully");
  135. }
  136. /* Test DMA transfer from UART RX FIFO to DDR */
  137. void test_pdma_rx()
  138. {
  139. rt_uint8_t ch;
  140. rt_err_t err;
  141. rt_uint32_t recv_event;
  142. rt_uint32_t len = 16;
  143. uint8_t *buf = rt_malloc_align(64, CACHE_LINE_SIZE);
  144. void *buf_pa = rt_kmem_v2p(buf);
  145. /* Reset event before starting test */
  146. rt_event_control(test_pdma_event, RT_IPC_CMD_RESET, NULL);
  147. /* Request DMA channel */
  148. err = k230_pdma_request_channel(&ch);
  149. uassert_int_equal(err, RT_EOK);
  150. /* Configure DMA parameters */
  151. usr_pdma_cfg_t pdma_cfg;
  152. pdma_cfg.device = UART0_RX;
  153. pdma_cfg.src_addr = (rt_uint8_t *)UART0_BASE_ADDR;
  154. pdma_cfg.dst_addr = buf_pa;
  155. pdma_cfg.line_size = len;
  156. /* Set channel configuration */
  157. pdma_cfg.pdma_ch_cfg.ch_src_type = FIXED;
  158. pdma_cfg.pdma_ch_cfg.ch_dev_hsize = PSBYTE1;
  159. pdma_cfg.pdma_ch_cfg.ch_dat_endian = PDEFAULT;
  160. pdma_cfg.pdma_ch_cfg.ch_dev_blen = PBURST_LEN_16;
  161. pdma_cfg.pdma_ch_cfg.ch_priority = 7;
  162. pdma_cfg.pdma_ch_cfg.ch_dev_tout = 0xFFF;
  163. /* Set callback and configure DMA */
  164. err = k230_pdma_set_callback(ch, test_pdma_call_back);
  165. uassert_int_equal(err, RT_EOK);
  166. err = k230_pdma_config(ch, &pdma_cfg);
  167. uassert_int_equal(err, RT_EOK);
  168. LOG_I("Send test data by keyboard input within 2 seconds (to UART receive buffer)");
  169. /* Setup 2 second timeout */
  170. rt_tick_t timeout = RT_TICK_PER_SECOND * 2;
  171. rt_tick_t start_tick = rt_tick_get();
  172. /* Mask UART0 interrupt to prevent FIFO access by ISR */
  173. rt_hw_interrupt_mask(UART0_IRQ);
  174. /* Wait for timeout period */
  175. while (RT_TRUE)
  176. {
  177. if (rt_tick_get_delta(start_tick) >= timeout)
  178. {
  179. break;
  180. }
  181. }
  182. /* Start DMA transfer */
  183. k230_pdma_start(ch);
  184. /* Wait for transfer completion event */
  185. err = rt_event_recv(test_pdma_event,
  186. TEST_PDMA_EVENT_COMPLETE | TEST_PDMA_EVENT_TIMEOUT,
  187. RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
  188. RT_WAITING_FOREVER,
  189. &recv_event);
  190. uassert_int_equal(err, RT_EOK);
  191. uassert_int_equal(recv_event, TEST_PDMA_EVENT_COMPLETE);
  192. rt_hw_interrupt_umask(UART0_IRQ);
  193. err = k230_pdma_stop(ch);
  194. uassert_int_equal(err, RT_EOK);
  195. err = k230_pdma_release_channel(ch);
  196. uassert_int_equal(err, RT_EOK);
  197. LOG_I("Got: %.*s", len, buf);
  198. rt_free_align(buf);
  199. }
  200. static rt_err_t utest_tc_init(void)
  201. {
  202. test_pdma_event = (rt_event_t)rt_malloc(sizeof(struct rt_event));
  203. if (test_pdma_event == RT_NULL)
  204. {
  205. LOG_E("Failed to allocate memory for pdma_event!");
  206. return -RT_ENOMEM;
  207. }
  208. if (rt_event_init(test_pdma_event, "pdma_event", RT_IPC_FLAG_FIFO) != RT_EOK)
  209. {
  210. LOG_E("Failed to init pdma_event!");
  211. rt_free(test_pdma_event);
  212. return -RT_ERROR;
  213. }
  214. LOG_I("PDMA event initialized successfully!");
  215. return RT_EOK;
  216. }
  217. static rt_err_t utest_tc_cleanup(void)
  218. {
  219. rt_free(test_pdma_event);
  220. /* Check and release all DMA channels */
  221. for (rt_uint8_t ch = 0; ch < PDMA_CH_MAX; ch++)
  222. {
  223. rt_err_t err = k230_pdma_release_channel(ch);
  224. /* Channel was successfully released now - means it wasn't properly released in test case */
  225. if (err == RT_EOK)
  226. {
  227. LOG_W("PDMA channel %d was not released in test case!", ch);
  228. }
  229. /* Channel release failed with error other than -RT_EINVAL (unexpected error) */
  230. else if (err != -RT_EINVAL)
  231. {
  232. LOG_I("PDMA channel %d release failed: %d", ch, err);
  233. }
  234. /* -RT_EINVAL means channel was already released (normal case) - no action needed */
  235. }
  236. return RT_EOK;
  237. }
  238. void test_pdma()
  239. {
  240. UTEST_UNIT_RUN(test_pdma_request);
  241. UTEST_UNIT_RUN(test_pdma_tx);
  242. UTEST_UNIT_RUN(test_pdma_rx);
  243. }
  244. UTEST_TC_EXPORT(test_pdma, "bsp.k230.drivers.pdma", utest_tc_init, utest_tc_cleanup, 10);