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