zynq中axi_dma的sg模式采集--裸机测试(还有bug)

作者:王明列日期:2026/9/6

参考

约定

PL部分参考 zynq中axi_dma的sg模式采集–PL搭建.csdn

1共有10个BD
21. 采集流的 1  = 22  u32
3   格式为 v0 = 行号  v1 ~ v21 = 连续数据
4    0 行:  0  1   2   ...  21
5    1 行:  1  22  23  ...  42
6   
72. 1  BD = 8  = 704 Bytes
8   10  BD = 80  = 7040 Bytes
9
103. axidma_capture_one_frame_v0()
11   只打印每个 BD  v0,用于快速检查:
12   BD 顺序、行号连续性、BD 边界是否正确。
13
144. axidma_capture_one_frame()
15   打印一个完整 BD  8  × 22 个数据,
16   用于检查 BD 内的完整数据是否正确。
17

目录

1PS D:\myr6\vitis_prj\hello\src> ls
2
3
4    目录: D:\myr6\vitis_prj\hello\src
5
6
7Mode                 LastWriteTime         Length Name
8----                 -------------         ------ ----
9-a----          2026/9/4     12:46          25508 AtShell.cpp
10-a----          2026/9/4     12:49           9330 AtShell.h
11-a----          2026/9/4     13:30          13908 at_app_axi_dma_sg.cpp
12-a----          2026/9/4     13:34          14658 at_app_axi_dma_sg_cycle.cpp
13-a----          2026/8/4     21:53           5323 bsp.cpp
14-a----          2026/8/4     21:53            517 bsp.h
15-a----         2026/6/23     22:45           1631 FifoBuffer.cpp
16-a----         2026/6/23     22:45            510 FifoBuffer.h
17-a----         2026/6/23     22:45           6303 lscript.ld
18-a----          2026/9/4     14:11            616 main.cpp
19-a----         2026/6/23     22:45            101 README.txt
20-a----         2026/6/23     22:45             36 Xilinx.spec
21
22

AtShell

引用 嵌入式终端AtShell.csdn

bsp和 FifoBuffer

引用 zynq中axi_dma的四个实验-第2课:Vitis裸机测试.csdn

main.cpp

1#include "bsp.h"
2#include "AtShell.h"
3
4extern int at_app_axi_dma_sg_cycle_read(int argc, char** argv);
5extern int at_app_axi_dma_sg_read(int argc, char** argv);
6
7void at_app_init(void)
8{
9	AT_SHELL_EXPORT(sg_cycle_read, sg_cycle_read, at_app_axi_dma_sg_cycle_read,0);
10	AT_SHELL_EXPORT(sg_read, sg_read, at_app_axi_dma_sg_read,0);
11}
12
13
14int main()
15{
16    BspInit();
17    at_init(Bsp_shell_write);
18    at_app_init();
19    at_show_version();
20    while (1) {
21        uint32_t ms = BspGetMillis();
22        int len = BspUartRead((uint8_t *)AT_m_buf, -1);
23        at_import((uint8_t *)AT_m_buf, len, ms);
24    }
25
26    return 0;
27}
28
29

at_app_axi_dma_sg.cpp

sg模式

1#include "AtShell.h"
2#include "bsp.h"
3#include "xaxidma.h"
4#include "xaxidma_hw.h"
5#include "xil_cache.h"
6#include "xil_io.h"
7#include "xparameters.h"
8#include "xstatus.h"
9#include <stdint.h>
10#include <string.h>
11
12// -----------------------------------------------------------------------------
13// 普通 SG 模式(非循环)
14// DMA 完成 BD 后自动停止,软件必须重新分配并提交已完成的 BD。
15// cmd=0 : 打印所有已完成 BD  v0(十进制),每 BD 一行。
16// cmd=1 : 仅打印最新完成的 BD 的完整行数据(22  word),每行十六进制。
17// -----------------------------------------------------------------------------
18
19#define AXIS_LINE_WORD_COUNT      22u
20#define AXIS_LINES_PER_BD         8u
21#define AXIS_BD_COUNT             10u
22#define AXIS_LINE_BYTE_COUNT      (AXIS_LINE_WORD_COUNT * sizeof(uint32_t))
23#define AXIS_BD_WORD_COUNT        (AXIS_LINE_WORD_COUNT * AXIS_LINES_PER_BD)
24#define AXIS_BD_BYTE_COUNT        (AXIS_BD_WORD_COUNT * sizeof(uint32_t))
25#define RX_BD_COUNT               AXIS_BD_COUNT
26#define RX_BD_SPACE_BYTES         XAxiDma_BdRingMemCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, RX_BD_COUNT)
27
28static XAxiDma s_axis_dma;
29static int s_axis_dma_ready = 0;
30static XAxiDma_BdRing *s_rx_ring = NULL;
31static uint8_t s_rx_bd_space[RX_BD_SPACE_BYTES] __attribute__((aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT)));
32static uint32_t s_axis_rx_buf[AXIS_BD_WORD_COUNT * RX_BD_COUNT] __attribute__((aligned(64)));
33static uint32_t s_frame_seq = 0;
34
35static void axidma_print_s2mm_diag(const char *tag)
36{
37    uint32_t sr = XAxiDma_ReadReg(s_axis_dma.RegBase,
38                                  XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET);
39    AT_printf("%s: S2MM_SR=0x%08X ring_err=0x%08X\r\n",
40              tag, sr, (unsigned int)XAxiDma_BdRingGetError(s_rx_ring));
41}
42
43static void axidma_reset_runtime(void)
44{
45    XAxiDma_Reset(&s_axis_dma);
46    while (!XAxiDma_ResetIsDone(&s_axis_dma)) { }
47    s_axis_dma_ready = 0;
48    s_rx_ring = NULL;
49}
50
51// 打印完整行数据(22  word,十六进制)
52static void axidma_dump_bd_lines(const uint32_t *words, uint32_t line_count)
53{
54    for (uint32_t line = 0u; line < line_count; line++) {
55        AT_printf("%04u :", (unsigned int)line);
56        for (uint32_t word = 0u; word < AXIS_LINE_WORD_COUNT; word++) {
57            AT_printf(" %08X", (unsigned int)words[line * AXIS_LINE_WORD_COUNT + word]);
58        }
59        AT_printf("\r\n");
60    }
61}
62
63// 初始化:创建 BD ring,分配全部 10  BD,提交并启动(不使能循环)
64static int at_app_axi_full_dma_init(void)
65{
66    if (s_axis_dma_ready) return XST_SUCCESS;
67
68    XAxiDma_Config *cfg = XAxiDma_LookupConfig(XPAR_AXI_DMA_0_DEVICE_ID);
69    if (cfg == NULL) {
70        AT_printf("ERR: AXI DMA config not found\r\n");
71        return XST_FAILURE;
72    }
73
74    int status = XAxiDma_CfgInitialize(&s_axis_dma, cfg);
75    if (status != XST_SUCCESS) {
76        AT_printf("ERR: AXI DMA init failed: %d\r\n", status);
77        return status;
78    }
79
80    if (!XAxiDma_HasSg(&s_axis_dma)) {
81        AT_printf("ERR: AXI DMA must use SG mode\r\n");
82        return XST_FAILURE;
83    }
84    if (!s_axis_dma.HasS2Mm) {
85        AT_printf("ERR: AXI DMA S2MM channel disabled\r\n");
86        return XST_FAILURE;
87    }
88
89    s_rx_ring = XAxiDma_GetRxRing(&s_axis_dma);
90    if (s_rx_ring == NULL) {
91        AT_printf("ERR: RX ring not found\r\n");
92        axidma_reset_runtime();
93        return XST_FAILURE;
94    }
95
96    XAxiDma_BdRingIntDisable(s_rx_ring, XAXIDMA_IRQ_ALL_MASK);
97    XAxiDma_IntrDisable(&s_axis_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
98
99    status = XAxiDma_BdRingCreate(s_rx_ring,
100                                  (UINTPTR)s_rx_bd_space,
101                                  (UINTPTR)s_rx_bd_space,
102                                  XAXIDMA_BD_MINIMUM_ALIGNMENT,
103                                  RX_BD_COUNT);
104    if (status != XST_SUCCESS) {
105        AT_printf("ERR: RX bd ring create failed: %d\r\n", status);
106        axidma_reset_runtime();
107        return status;
108    }
109
110    XAxiDma_Bd bd_template;
111    XAxiDma_BdClear(&bd_template);
112    status = XAxiDma_BdRingClone(s_rx_ring, &bd_template);
113    if (status != XST_SUCCESS) {
114        AT_printf("ERR: RX bd ring clone failed: %d\r\n", status);
115        axidma_reset_runtime();
116        return status;
117    }
118
119    status = XAxiDma_BdRingCheck(s_rx_ring);
120    if (status != XST_SUCCESS) {
121        AT_printf("ERR: RX bd ring check failed: %d\r\n", status);
122        axidma_reset_runtime();
123        return status;
124    }
125
126    int free_count = XAxiDma_BdRingGetFreeCnt(s_rx_ring);
127    if (free_count < (int)RX_BD_COUNT) {
128        AT_printf("ERR: RX bd ring free BDs not enough\r\n");
129        axidma_reset_runtime();
130        return XST_FAILURE;
131    }
132
133    XAxiDma_Bd *bd_ptr = NULL;
134    status = XAxiDma_BdRingAlloc(s_rx_ring, RX_BD_COUNT, &bd_ptr);
135    if (status != XST_SUCCESS) {
136        AT_printf("ERR: RX bd alloc failed: %d\r\n", status);
137        axidma_reset_runtime();
138        return status;
139    }
140
141    XAxiDma_Bd *bd_cur = bd_ptr;
142    for (uint32_t i = 0u; i < RX_BD_COUNT; i++) {
143        UINTPTR buf_addr = (UINTPTR)&s_axis_rx_buf[i * AXIS_BD_WORD_COUNT];
144        status = XAxiDma_BdSetBufAddr(bd_cur, buf_addr);
145        if (status != XST_SUCCESS) {
146            AT_printf("ERR: set buffer addr failed: %d\r\n", status);
147            axidma_reset_runtime();
148            return status;
149        }
150        status = XAxiDma_BdSetLength(bd_cur, AXIS_BD_BYTE_COUNT, s_rx_ring->MaxTransferLen);
151        if (status != XST_SUCCESS) {
152            AT_printf("ERR: set length failed: %d\r\n", status);
153            axidma_reset_runtime();
154            return status;
155        }
156        XAxiDma_BdSetCtrl(bd_cur, 0);
157        XAxiDma_BdSetId(bd_cur, (UINTPTR)(i + 1));
158        bd_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, bd_cur);
159    }
160
161    Xil_DCacheInvalidateRange((INTPTR)s_axis_rx_buf, sizeof(s_axis_rx_buf));
162
163    // 提交全部 BD(普通模式,不使能循环)
164    status = XAxiDma_BdRingToHw(s_rx_ring, RX_BD_COUNT, bd_ptr);
165    if (status != XST_SUCCESS) {
166        AT_printf("ERR: submit to hw failed: %d\r\n", status);
167        axidma_reset_runtime();
168        return status;
169    }
170
171    // 启动 DMA(完成后自动停止)
172    status = XAxiDma_BdRingStart(s_rx_ring);
173    if (status != XST_SUCCESS) {
174        AT_printf("ERR: start failed: %d\r\n", status);
175        axidma_reset_runtime();
176        return status;
177    }
178
179    s_axis_dma_ready = 1;
180    return XST_SUCCESS;
181}
182
183// 重新提交已完成的 BD(公共函数,用于 cmd=0  cmd=1)
184static int axidma_resubmit_completed_bds(int bd_count, XAxiDma_Bd *bd_ptr)
185{
186    if (bd_count <= 0) return XST_SUCCESS;
187
188    // 1. 释放已完成 BD
189    int status = XAxiDma_BdRingFree(s_rx_ring, bd_count, bd_ptr);
190    if (status != XST_SUCCESS) {
191        AT_printf("ERR: free BD failed: %d\r\n", status);
192        axidma_reset_runtime();
193        return status;
194    }
195
196    // 2. 检查 free list 中可用数量
197    int free_cnt = XAxiDma_BdRingGetFreeCnt(s_rx_ring);
198    if (free_cnt < bd_count) {
199        AT_printf("ERR: free cnt %d < %d, resetting\r\n", free_cnt, bd_count);
200        axidma_reset_runtime();
201        return XST_FAILURE;
202    }
203
204    // 3. 重新分配 bd_count  BD
205    XAxiDma_Bd *new_bd_ptr = NULL;
206    status = XAxiDma_BdRingAlloc(s_rx_ring, bd_count, &new_bd_ptr);
207    if (status != XST_SUCCESS) {
208        AT_printf("ERR: alloc BD failed: %d\r\n", status);
209        axidma_reset_runtime();
210        return status;
211    }
212
213    // 4. 设置新分配的 BD(使用全局缓冲区的前 bd_count 个)
214    XAxiDma_Bd *new_cur = new_bd_ptr;
215    for (uint32_t i = 0; i < (uint32_t)bd_count; i++) {
216        UINTPTR buf_addr = (UINTPTR)&s_axis_rx_buf[i * AXIS_BD_WORD_COUNT];
217        status = XAxiDma_BdSetBufAddr(new_cur, buf_addr);
218        if (status != XST_SUCCESS) {
219            AT_printf("ERR: set buf addr failed: %d\r\n", status);
220            axidma_reset_runtime();
221            return status;
222        }
223        status = XAxiDma_BdSetLength(new_cur, AXIS_BD_BYTE_COUNT, s_rx_ring->MaxTransferLen);
224        if (status != XST_SUCCESS) {
225            AT_printf("ERR: set length failed: %d\r\n", status);
226            axidma_reset_runtime();
227            return status;
228        }
229        XAxiDma_BdSetCtrl(new_cur, 0);
230        XAxiDma_BdSetId(new_cur, (UINTPTR)(i + 1));
231        new_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, new_cur);
232    }
233
234    // 5. 提交这些 BD 到硬件
235    status = XAxiDma_BdRingToHw(s_rx_ring, bd_count, new_bd_ptr);
236    if (status != XST_SUCCESS) {
237        AT_printf("ERR: re-submit BD failed: %d\r\n", status);
238        axidma_reset_runtime();
239        return status;
240    }
241
242    // 6. 重启 DMA
243    status = XAxiDma_BdRingStart(s_rx_ring);
244    if (status != XST_SUCCESS) {
245        AT_printf("WARN: restart DMA returned %d\r\n", status);
246        axidma_reset_runtime();
247        return status;
248    }
249
250    return XST_SUCCESS;
251}
252
253// cmd=0: 打印所有已完成 BD  v0(十进制),每 BD 一行
254static int axidma_capture_one_frame_v0(void)
255{
256    XAxiDma_Bd *bd_ptr = NULL;
257    int bd_count = XAxiDma_BdRingFromHw(s_rx_ring, XAXIDMA_ALL_BDS, &bd_ptr);
258
259    if (bd_count <= 0) {
260        uint32_t sr = XAxiDma_ReadReg(s_axis_dma.RegBase,
261                                      XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET);
262        if ((sr & XAXIDMA_ERR_ALL_MASK) != 0u) {
263            AT_printf("ERR: AXI DMA S2MM fault\r\n");
264            axidma_print_s2mm_diag("AXI DMA fault");
265            axidma_reset_runtime();
266            return XST_FAILURE;
267        }
268        AT_printf("dma_read: no frame ready\r\n");
269        return XST_SUCCESS;
270    }
271
272    AT_printf("dma_read frame=%u completed_bd=%d/%u\r\n",
273              (unsigned int)s_frame_seq++, bd_count, (unsigned int)RX_BD_COUNT);
274
275    XAxiDma_Bd *bd_cur = bd_ptr;
276    for (int i = 0; i < bd_count; i++) {
277        UINTPTR bd_id = XAxiDma_BdGetId(bd_cur);
278        UINTPTR buf_addr = XAxiDma_BdGetBufAddr(bd_cur);
279        uint32_t actual_len = XAxiDma_BdGetActualLength(bd_cur, s_rx_ring->MaxTransferLen);
280        uint32_t line_count = actual_len / AXIS_LINE_BYTE_COUNT;
281        if (line_count > AXIS_LINES_PER_BD) line_count = AXIS_LINES_PER_BD;
282
283        Xil_DCacheInvalidateRange((INTPTR)buf_addr, AXIS_BD_BYTE_COUNT);
284        const uint32_t *bd_words = (const uint32_t *)buf_addr;
285
286        AT_printf("BD %u:", (unsigned int)bd_id);
287        for (uint32_t line = 0; line < line_count; line++) {
288            uint32_t v0 = bd_words[line * AXIS_LINE_WORD_COUNT];
289            AT_printf(" %u", (unsigned int)v0);
290        }
291        AT_printf("\r\n");
292
293        if (i < bd_count - 1) {
294            bd_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, bd_cur);
295        }
296    }
297
298    // 重新提交所有已完成 BD
299    return axidma_resubmit_completed_bds(bd_count, bd_ptr);
300}
301
302// cmd=1: 仅打印最新完成的 BD 的完整行数据(22  word,十六进制)
303static int axidma_capture_one_frame_full(void)
304{
305    XAxiDma_Bd *bd_ptr = NULL;
306    int bd_count = XAxiDma_BdRingFromHw(s_rx_ring, XAXIDMA_ALL_BDS, &bd_ptr);
307
308    if (bd_count <= 0) {
309        uint32_t sr = XAxiDma_ReadReg(s_axis_dma.RegBase,
310                                      XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET);
311        if ((sr & XAXIDMA_ERR_ALL_MASK) != 0u) {
312            AT_printf("ERR: AXI DMA S2MM fault\r\n");
313            axidma_print_s2mm_diag("AXI DMA fault");
314            axidma_reset_runtime();
315            return XST_FAILURE;
316        }
317        AT_printf("dma_read: no frame ready\r\n");
318        return XST_SUCCESS;
319    }
320
321    // 取链表最后一个(最新完成)
322    XAxiDma_Bd *latest_bd = bd_ptr;
323    XAxiDma_Bd *bd_cur = bd_ptr;
324    for (int i = 1; i < bd_count; i++) {
325        bd_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, bd_cur);
326        latest_bd = bd_cur;
327    }
328
329    UINTPTR latest_bd_id = XAxiDma_BdGetId(latest_bd);
330    UINTPTR latest_buf_addr = XAxiDma_BdGetBufAddr(latest_bd);
331    uint32_t actual_len = XAxiDma_BdGetActualLength(latest_bd, s_rx_ring->MaxTransferLen);
332    uint32_t line_count = actual_len / AXIS_LINE_BYTE_COUNT;
333    if (line_count > AXIS_LINES_PER_BD) line_count = AXIS_LINES_PER_BD;
334
335    Xil_DCacheInvalidateRange((INTPTR)latest_buf_addr, AXIS_BD_BYTE_COUNT);
336    const uint32_t *bd_words = (const uint32_t *)latest_buf_addr;
337
338    if (actual_len != AXIS_BD_BYTE_COUNT) {
339        AT_printf("WARN: RX length actual=%u expected=%u\r\n",
340                  (unsigned int)actual_len, (unsigned int)AXIS_BD_BYTE_COUNT);
341    }
342
343    AT_printf("dma_read frame=%u completed_bd=%d/%u latest_bd=%u actual=%u\r\n",
344              (unsigned int)s_frame_seq++, bd_count,
345              (unsigned int)RX_BD_COUNT,
346              (unsigned int)latest_bd_id,
347              (unsigned int)actual_len);
348    axidma_dump_bd_lines(bd_words, line_count);
349
350    // 重新提交所有已完成 BD(包括最新及其他)
351    return axidma_resubmit_completed_bds(bd_count, bd_ptr);
352}
353
354// 对外接口:支持两个子命令
355//   s_macManage 0  -> 打印所有 BD  v0(十进制)
356//   s_macManage 1  -> 打印最新 BD 的完整行数据(十六进制)
357int at_app_axi_dma_sg_read(int argc, char** argv)
358{
359    if (!s_axis_dma_ready) {
360        int status = at_app_axi_full_dma_init();
361        Xil_DCacheDisable();   // 调试用,可移除
362        if (status != XST_SUCCESS) return status;
363    }
364
365    if (argc == 1) {
366        AT_printf("Usage: s_macManage <cmd>\r\n");
367        AT_printf("  cmd=0 : print v0 of all completed BDs (decimal)\r\n");
368        AT_printf("  cmd=1 : print full lines of latest BD (hex)\r\n");
369        return 0;
370    }
371
372    int cmd = at_param_to_int(1);
373    if (cmd == 0) {
374        return axidma_capture_one_frame_v0();
375    } else if (cmd == 1) {
376        return axidma_capture_one_frame_full();
377    } else {
378        AT_printf("Invalid cmd: %d\r\n", cmd);
379        return XST_FAILURE;
380    }
381}
382

at_app_axi_dma_sg_cycle.cpp

sg循环模式

1#include "AtShell.h"
2#include "bsp.h"
3#include "xaxidma.h"
4#include "xaxidma_hw.h"
5#include "xil_cache.h"
6#include "xil_io.h"
7#include "xparameters.h"
8#include "xstatus.h"
9#include <stdint.h>
10#include <string.h>
11
12// -----------------------------------------------------------------------------
13// 数据布局说明
14// 1) 这里的“一行”固定为 22  u32,也就是 88 字节,这 22  u32 对应 PL 端一次完整采样帧中的一行数据。
15// 2) 一个 BD 负责承载 8 行数据,因此单个 BD 的有效数据量是, 8 * 22 * 4 = 704 字节。
16// 3) 这里使用 10  BD 组成循环接收环。DMA 持续工作时,会把新收到的,数据写入下一个 BD 对应的 buffer,形成连续不断的采集链路。
17// 4) 每次调用 axidma_capture_one_frame() 时,只从完成链表中挑出最新的
18//    1  BD 来打印,这样串口输出会更清晰,也更适合循环 DMA 调试。
19// -----------------------------------------------------------------------------
20
21#define AXIS_LINE_WORD_COUNT      22u
22#define AXIS_LINES_PER_BD         8u
23#define AXIS_BD_COUNT             10u
24#define AXIS_LINE_BYTE_COUNT      (AXIS_LINE_WORD_COUNT * sizeof(uint32_t))
25#define AXIS_BD_WORD_COUNT        (AXIS_LINE_WORD_COUNT * AXIS_LINES_PER_BD)
26#define AXIS_BD_BYTE_COUNT        (AXIS_BD_WORD_COUNT * sizeof(uint32_t))
27#define RX_BD_COUNT               AXIS_BD_COUNT
28#define RX_BD_SPACE_BYTES         XAxiDma_BdRingMemCalc(XAXIDMA_BD_MINIMUM_ALIGNMENT, RX_BD_COUNT)
29
30static XAxiDma s_axis_dma;
31static int s_axis_dma_ready = 0;
32static XAxiDma_BdRing *s_rx_ring = NULL;
33static uint8_t s_rx_bd_space[RX_BD_SPACE_BYTES] __attribute__((aligned(XAXIDMA_BD_MINIMUM_ALIGNMENT)));
34// RX 端缓冲区按 BD 切成 10 份,
35// 每份都对应一个独立的接收 buffer。
36static uint32_t s_axis_rx_buf[AXIS_BD_WORD_COUNT * RX_BD_COUNT] __attribute__((aligned(64)));
37static uint32_t s_frame_seq = 0;
38
39static void axidma_print_s2mm_diag(const char *tag)
40{
41    uint32_t sr = XAxiDma_ReadReg(s_axis_dma.RegBase,
42                                  XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET);
43
44    AT_printf("%s: S2MM_SR=0x%08X ring_err=0x%08X\r\n",
45              tag,
46              sr,
47              (unsigned int)XAxiDma_BdRingGetError(s_rx_ring));
48}
49
50
51// 将一个 BD 的有效载荷按“行”打印出来。
52// 每行固定 22  32-bit word,输出格式是:
53//   0000 : v0 v1 ... v21
54static void axidma_dump_bd_lines(const uint32_t *words, uint32_t line_count)
55{
56    for (uint32_t line = 0u; line < line_count; line++) {
57        AT_printf("%04u :", (unsigned int)line);
58        for (uint32_t word = 0u; word < AXIS_LINE_WORD_COUNT; word++) {
59            AT_printf(" %08X", (unsigned int)words[line * AXIS_LINE_WORD_COUNT + word]);
60        }
61        AT_printf("\r\n");
62    }
63}
64
65// DMA 出现错误后,先复位硬件和软件状态,避免残留错误影响下一次采集。
66static void axidma_reset_runtime(void)
67{
68    XAxiDma_Reset(&s_axis_dma);
69    while (!XAxiDma_ResetIsDone(&s_axis_dma)) {
70    }
71    s_axis_dma_ready = 0;
72    s_rx_ring = NULL;
73}
74
75// 初始化阶段负责把 RX BD ring、缓冲区和 DMA 通道一次性准备好。
76// 只要这个函数成功返回,后续 read 命令就可以直接轮询已完成 BD。
77static int at_app_axi_full_dma_init(void)
78{
79    if (s_axis_dma_ready) {
80        return XST_SUCCESS;
81    }
82
83    //  BSP 生成的设备表里找到 AXI DMA 配置,再交给驱动初始化。
84    XAxiDma_Config *cfg = XAxiDma_LookupConfig(XPAR_AXI_DMA_0_DEVICE_ID);
85    if (cfg == NULL) {
86        AT_printf("ERR: AXI DMA config not found\r\n");
87        return XST_FAILURE;
88    }
89
90    int status = XAxiDma_CfgInitialize(&s_axis_dma, cfg);
91    if (status != XST_SUCCESS) {
92        AT_printf("ERR: AXI DMA init failed: %d\r\n", status);
93        return status;
94    }
95
96    // 这里依赖 SG/BD Ring 工作方式,并且只使用 S2MM 接收通道。
97    if (!XAxiDma_HasSg(&s_axis_dma)) {
98        AT_printf("ERR: AXI DMA must use SG mode\r\n");
99        return XST_FAILURE;
100    }
101
102    if (!s_axis_dma.HasS2Mm) {
103        AT_printf("ERR: AXI DMA S2MM channel disabled\r\n");
104        return XST_FAILURE;
105    }
106
107    s_rx_ring = XAxiDma_GetRxRing(&s_axis_dma);
108    if (s_rx_ring == NULL) {
109        AT_printf("ERR: RX ring not found\r\n");
110        axidma_reset_runtime();
111        return XST_FAILURE;
112    }
113
114    // 这个命令走轮询路径,不依赖中断,因此把 RX ring 中断先关掉。
115    XAxiDma_BdRingIntDisable(s_rx_ring, XAXIDMA_IRQ_ALL_MASK);
116    XAxiDma_IntrDisable(&s_axis_dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);
117
118    // 在预分配的 s_rx_bd_space 里创建 BD ring,后续所有 BD 都从这里取。
119    status = XAxiDma_BdRingCreate(s_rx_ring,
120                                  (UINTPTR)s_rx_bd_space,
121                                  (UINTPTR)s_rx_bd_space,
122                                  XAXIDMA_BD_MINIMUM_ALIGNMENT,
123                                  RX_BD_COUNT);
124    if (status != XST_SUCCESS) {
125        AT_printf("ERR: RX bd ring create failed: %d\r\n", status);
126        axidma_reset_runtime();
127        return status;
128    }
129
130    // 先构造一个空模板,再把整个 ring 复制成统一的默认状态。
131    XAxiDma_Bd bd_template;
132    XAxiDma_BdClear(&bd_template);
133    status = XAxiDma_BdRingClone(s_rx_ring, &bd_template);
134    if (status != XST_SUCCESS) {
135        AT_printf("ERR: RX bd ring clone failed: %d\r\n", status);
136        axidma_reset_runtime();
137        return status;
138    }
139
140    // 让驱动自检一下 BD ring 的结构是否正确,避免后面 DMA 运行时才暴露问题。
141    status = XAxiDma_BdRingCheck(s_rx_ring);
142    if (status != XST_SUCCESS) {
143        AT_printf("ERR: RX bd ring check failed: %d\r\n", status);
144        axidma_reset_runtime();
145        return status;
146    }
147
148    // 确认 free list 里有足够的 BD,一次性把整套接收环都挂到硬件上。
149    int free_count = XAxiDma_BdRingGetFreeCnt(s_rx_ring);
150    if (free_count < (int)RX_BD_COUNT) {
151        AT_printf("ERR: RX bd ring free BDs not enough\r\n");
152        axidma_reset_runtime();
153        return XST_FAILURE;
154    }
155
156    XAxiDma_Bd *bd_ptr = NULL;
157    status = XAxiDma_BdRingAlloc(s_rx_ring, RX_BD_COUNT, &bd_ptr);
158    if (status != XST_SUCCESS) {
159        AT_printf("ERR: RX bd alloc failed: %d\r\n", status);
160        axidma_reset_runtime();
161        return status;
162    }
163
164    XAxiDma_Bd *bd_cur = bd_ptr;
165    // 给每个 BD 绑定独立 buffer,避免多个 BD 互相覆盖同一块内存。
166    for (uint32_t i = 0u; i < RX_BD_COUNT; i++) {
167        UINTPTR buf_addr = (UINTPTR)&s_axis_rx_buf[i * AXIS_BD_WORD_COUNT];
168
169        status = XAxiDma_BdSetBufAddr(bd_cur, buf_addr);
170        if (status != XST_SUCCESS) {
171            AT_printf("ERR: RX set buffer addr failed: %d\r\n", status);
172            axidma_reset_runtime();
173            return status;
174        }
175
176        status = XAxiDma_BdSetLength(bd_cur,
177                                     AXIS_BD_BYTE_COUNT,
178                                     s_rx_ring->MaxTransferLen);
179        if (status != XST_SUCCESS) {
180            AT_printf("ERR: RX set length failed: %d\r\n", status);
181            axidma_reset_runtime();
182            return status;
183        }
184
185        XAxiDma_BdSetCtrl(bd_cur, 0);
186        // ID 直接写成 1-based  BD 编号,后面打印时更直观。
187        XAxiDma_BdSetId(bd_cur, (UINTPTR)(i + 1u));
188        bd_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, bd_cur);
189    }
190
191    //  CPU 侧缓存失效掉,避免后面把旧数据当成 DMA 新写入的数据。
192    Xil_DCacheInvalidateRange((INTPTR)s_axis_rx_buf, sizeof(s_axis_rx_buf));
193
194    // 将整条 BD 链提交给硬件,DMA 从这一刻开始可以向这些 buffer 写数据。
195    status = XAxiDma_BdRingToHw(s_rx_ring, RX_BD_COUNT, bd_ptr);
196    if (status != XST_SUCCESS) {
197        AT_printf("ERR: RX submit to hw failed: %d\r\n", status);
198        axidma_reset_runtime();
199        return status;
200    }
201
202    // 打开 cyclic 模式,让 DMA  BD ring 里循环运行,不会在单轮结束后停住。
203    XAxiDma_BdRingEnableCyclicDMA(s_rx_ring);
204    status = XAxiDma_SelectCyclicMode(&s_axis_dma, XAXIDMA_DEVICE_TO_DMA, 1);
205    if (status != XST_SUCCESS) {
206        AT_printf("ERR: RX cyclic enable failed: %d\r\n", status);
207        axidma_reset_runtime();
208        return status;
209    }
210
211    // 正式启动 RX ring,S2MM 通道开始接收 PL 端送来的 AXI-Stream 数据。
212    status = XAxiDma_BdRingStart(s_rx_ring);
213    if (status != XST_SUCCESS) {
214        AT_printf("ERR: RX start failed: %d\r\n", status);
215        axidma_reset_runtime();
216        return status;
217    }
218
219    s_axis_dma_ready = 1;
220    return XST_SUCCESS;
221}
222
223
224static int axidma_capture_one_frame_v0(void)
225{
226    XAxiDma_Bd *bd_ptr = NULL;
227    int bd_count = XAxiDma_BdRingFromHw(s_rx_ring, XAXIDMA_ALL_BDS, &bd_ptr);
228
229    if (bd_count <= 0) {
230        uint32_t sr = XAxiDma_ReadReg(s_axis_dma.RegBase,
231                                      XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET);
232        if ((sr & XAXIDMA_ERR_ALL_MASK) != 0u) {
233            AT_printf("ERR: AXI DMA S2MM fault\r\n");
234            axidma_print_s2mm_diag("AXI DMA fault");
235            axidma_reset_runtime();
236            return XST_FAILURE;
237        }
238        AT_printf("dma_read: no frame ready\r\n");
239        return XST_SUCCESS;
240    }
241
242    // 打印摘要
243    AT_printf("dma_read frame=%u completed_bd=%d/%u\r\n",
244              (unsigned int)s_frame_seq++,
245              bd_count,
246              (unsigned int)RX_BD_COUNT);
247
248    // 遍历所有完成的BD
249    XAxiDma_Bd *bd_cur = bd_ptr;
250    for (int i = 0; i < bd_count; i++) {
251        UINTPTR bd_id = XAxiDma_BdGetId(bd_cur);
252        UINTPTR buf_addr = XAxiDma_BdGetBufAddr(bd_cur);
253        uint32_t actual_len = XAxiDma_BdGetActualLength(bd_cur, s_rx_ring->MaxTransferLen);
254        uint32_t line_count = actual_len / AXIS_LINE_BYTE_COUNT;
255        if (line_count > AXIS_LINES_PER_BD) line_count = AXIS_LINES_PER_BD;
256
257        // 失效缓存
258        Xil_DCacheInvalidateRange((INTPTR)buf_addr, AXIS_BD_BYTE_COUNT);
259
260        const uint32_t *bd_words = (const uint32_t *)buf_addr;
261
262        // 打印此BD的v0值:一行
263        AT_printf("BD %u:", (unsigned int)bd_id);
264        for (uint32_t line = 0; line < line_count; line++) {
265            uint32_t v0 = bd_words[line * AXIS_LINE_WORD_COUNT];
266            AT_printf(" %u", (unsigned int)v0);
267        }
268        AT_printf("\r\n");
269
270        // 移到下一个BD
271        bd_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, bd_cur);
272    }
273
274    return XST_SUCCESS;
275}
276
277
278// 读取阶段只做三件事:
279// 1) 从硬件侧取回已经完成的 BD;
280// 2) 失效该 BD 对应的 cache;
281// 3) 按“行号 : v0 ... v21”格式打印出来。
282static int axidma_capture_one_frame(void)
283{
284    XAxiDma_Bd *bd_ptr = NULL;
285    // 从硬件侧取回已经完成的 BD。这里先尽量把当前完成链表里的 BD 都取出来。
286    int bd_count = XAxiDma_BdRingFromHw(s_rx_ring, XAXIDMA_ALL_BDS, &bd_ptr);
287
288    // 没有拿到完成 BD 时,先区分“暂时还没到帧”还是“DMA 已经出错”。
289    if (bd_count <= 0) {
290        uint32_t sr = XAxiDma_ReadReg(s_axis_dma.RegBase,
291                                      XAXIDMA_RX_OFFSET + XAXIDMA_SR_OFFSET);
292        if ((sr & XAXIDMA_ERR_ALL_MASK) != 0u) {
293            AT_printf("ERR: AXI DMA S2MM fault\r\n");
294            axidma_print_s2mm_diag("AXI DMA fault");
295            axidma_reset_runtime();
296            return XST_FAILURE;
297        }
298
299        AT_printf("dma_read: no frame ready\r\n");
300        return XST_SUCCESS;
301    }
302
303    // 如果一次返回了多个 BD,就取链表里的最后一个作为“最新完成的 BD”。
304    // 这样每次命令只打印一个 BD,串口输出会更规整。
305    XAxiDma_Bd *latest_bd = bd_ptr;
306    XAxiDma_Bd *bd_cur = bd_ptr;
307    for (int i = 1; i < bd_count; i++) {
308        bd_cur = (XAxiDma_Bd *)XAxiDma_BdRingNext(s_rx_ring, bd_cur);
309        latest_bd = bd_cur;
310    }
311
312    // 取出这个 BD 的元信息:编号、buffer 地址和实际接收长度。
313    UINTPTR latest_bd_id = XAxiDma_BdGetId(latest_bd);
314    UINTPTR latest_buf_addr = XAxiDma_BdGetBufAddr(latest_bd);
315    uint32_t actual_len = XAxiDma_BdGetActualLength(latest_bd, s_rx_ring->MaxTransferLen);
316    uint32_t line_count = actual_len / AXIS_LINE_BYTE_COUNT;
317    const uint32_t *bd_words = (const uint32_t *)latest_buf_addr;
318
319    // 失效这个 BD 对应的 cache,确保后面打印到的是 DMA 刚写进内存的新数据。
320    Xil_DCacheInvalidateRange((INTPTR)latest_buf_addr, AXIS_BD_BYTE_COUNT);
321
322    if (line_count > AXIS_LINES_PER_BD) {
323        line_count = AXIS_LINES_PER_BD;
324    }
325
326    // 正常情况下,一个 BD 的长度应该刚好等于整块 BD 缓冲区大小。
327    if (actual_len != AXIS_BD_BYTE_COUNT) {
328        AT_printf("WARN: RX length actual=%u expected=%u\r\n",
329                  (unsigned int)actual_len,
330                  (unsigned int)AXIS_BD_BYTE_COUNT);
331    }
332
333    // 先打印一个简短摘要,方便快速知道这次读到了哪一个 BD。
334    AT_printf("dma_read frame=%u completed_bd=%d/%u latest_bd=%u actual=%u\r\n",
335              (unsigned int)s_frame_seq++,
336              bd_count,
337              (unsigned int)RX_BD_COUNT,
338              (unsigned int)latest_bd_id,
339              (unsigned int)actual_len);
340    // 最后把这个 BD  8 行数据逐行打印出来。
341    axidma_dump_bd_lines(bd_words, line_count);
342
343    return XST_SUCCESS;
344}
345
346
347// read 命令的入口:第一次调用时完成初始化,后续直接读取并打印最新 BD。
348int at_app_axi_dma_sg_cycle_read(int argc, char** argv)
349{
350
351     if (!s_axis_dma_ready) {
352        int status = at_app_axi_full_dma_init();
353        // 为了简化这个调试命令,这里关闭 DCache,避免缓存一致性影响观察结果。
354        Xil_DCacheDisable();
355        if (status != XST_SUCCESS) {
356            return status;
357        }
358     }
359
360	  if (argc == 1) {
361			at_printf("Usage: s_macManage <cmd>\r\n");
362			at_printf("  cmd=0 : axidma_capture_one_frame_v0\r\n");
363			at_printf("  cmd=1 : axidma_capture_one_frame\r\n");
364			return 0;
365		}
366	  int cmd = at_param_to_int(1);
367	  if(cmd==0){
368		  return axidma_capture_one_frame_v0();
369	  }
370	  if(cmd==1){
371		  return axidma_capture_one_frame();
372	  }
373}
374
375

测试

1$:0
2AtShell commands:
3 0.help                 - list cmd
4 1.clean                - clean screen
5 2.sg_cycle_read        - sg_cycle_read
6 3.sg_read              - sg_read
7
8$:3 0
9dma_read frame=13 completed_bd=10/10
10BD 1: 552 553 554 555 556 557 558 559
11BD 2: 560 561 562 563 564 565 566 567
12BD 3: 568 569 570 571 572 573 574 575
13BD 4: 576 577 578 579 580 581 582 583
14BD 5: 584 585 586 587 588 589 590 591
15BD 6: 592 593 594 595 596 597 598 599
16BD 7: 600 601 602 603 604 605 606 607
17BD 8: 608 609 610 611 612 613 614 615
18BD 9: 616 617 618 619 620 621 622 623
19BD 10: 624 625 626 627 628 629 630 631
20
21

zynq中axi_dma的sg模式采集--裸机测试(还有bug)》 是转载文章,点击查看原文


相关推荐


深入理解 Transformer:Transformer 究竟是什么?
渡我白衣2026/8/29

目录 一、先从一张经典结构图开始二、Transformer 不是一个模块,而是一组模块的组合三、什么是 Encoder?四、Encoder Block:Transformer 的基本积木五、第一部分:Multi-Head Self-Attention六、第二部分:为什么 Attention 后面还需要 Add?七、第三部分:Norm 又是什么?八、第四部分:Attention 之后,为什么还需要 FFN?九、现在,我们终于可以看懂 Encoder Block 了十、Encoder 到底输出了什


Go 编程实战:指针 Pointer——理解地址、取址与解引用
程序员爱钓鱼2026/8/21

上一篇我们学习了 Map,到这里已经接触了数组、Slice、Map 等常用数据结构。在继续学习函数之前,还有一个非常重要的基础概念必须掌握——指针 Pointer。 很多刚接触 Go 的开发者看到指针会觉得复杂,其实 Go 的指针相比 C/C++ 简单很多。Go 不支持复杂的指针运算,日常开发主要掌握三个概念即可:变量、内存地址、通过地址访问变量。 理解指针之后,后面学习函数参数、Struct、方法、接口以及并发编程都会更加容易。 一、什么是指针 先看一个普通变量: age := 20 程序


【Linux系统篇】Linux入门基础指令(一)
忧郁兔斯基2026/8/8

在上一篇文章中,我们已经谈过Linux的历史以及如何使用云服务器配置Linux环境和使用Xshell来使用Linux,那么我们在本篇文章中将要开始学习Linux的一些基础指令。 目录 一、关于图形化界面 二、Linux文件以及目录结构 2.1 怎么理解文件 2.2 Linux的文件结构 2.3 Linux的目录结构 2.4 路径 三、简单的指令学习 3.1 pwd 命令 3.2 ls指令 -l 列出文件的详细信息 -a 列出目录下的所有文件 指令选项的组合使用方法 l


500 个服务时快 6 倍:我们如何将 Kibana APM 服务地图从 Canvas 重构到 React DOM
Elasticsearch2026/7/30

作者:来自 Elastic Jenny Pavlova 每个服务节点都会显示告警、 SLO 和异常健康状态,因此你可以仅筛选违反阈值的服务,并将结果嵌入到任何 Kibana 仪表板中,同时支持在整个拓扑中使用完整的键盘导航。 我们基于 React Flow 重构了 Elastic Observability 中的 Kibana APM 服务地图。在拥有 500 个服务时,渲染时间仅为 64ms,相比之前基于 Cytoscape.js 的实现快约 6 倍,同时 JavaScript 体积减少了


京东零售组织新变革:取消两级管理岗,推全栈化开发
AIHR数智引擎2026/7/22

近日,京东零售的组织调整方案流传出来。 很多人第一反应是:大厂又在砍中层。但把方案里的三条细节放在一起看,你会发现这事和"裁员"关系不大,它真正改写的,是"管理者"这三个字的定义。 细节一:C4、C5 两级管理者的"管理者身份"被取消。人还在,但"管人"这顶帽子没了,他们直接挂靠到 C3;以后员工请假、调休,C3 一个人拍板。 细节二:创新零售业务的前端团队并进服务端,全员转做全栈开发。第三季度开始,首批全栈工程师就要直接介入业务。 细节三:C2 序列的团队规模必须大于 50 人,没达标


AI编程出海第一步:别急着写代码,先找到老外真正愿意付费的需求
卷福同学2026/7/14

最近在学AI编程出海的项目,简单说就是做海外网站,让老外们付费使用。而第一步就是要确定网站做什么,也就是找需求 1.伪需求 对于小白来说,可能会想到和AI对话,聊出来一个需求,然后就开始做站了。但是这种AI直接生成的需求,只是看起来可以做,却没考虑到真实用户需求,往往做出来后没人用,或者已有成熟工具站了 2.真实的用户需求 以工具站为例,介绍2种方式来找真实的用户需求 Google Suggest 谷歌自动补齐,填写一个关键词到谷歌搜索,接着在前中后尝试输入a…z,会自动带出搜索词下拉列表,


协程深度解析:明明只有 8 个异步任务,为何 App 线程数瞬间突破 一倍?
潜龙勿用之化骨龙2026/7/6

在 Kotlin 协程中,有一个非常隐蔽但真实存在的问题: 你只是加了 Dispatchers.IO,线程数却变多了,多的不是一点点,而是成倍增长 更关键的是: 👉 这个问题在 Application 启动阶段,比 ViewModel 更严重 0. 先讲清楚“业务真实场景” 为了让问题更贴近真实工程,我们假设一个典型 App: App 启动 & UI 初始化行为 整个应用在启动时,会同时触发两类并发任务: ① Application 启动阶段(全局初始化) 启动 App → 自动


码农的AI翻身(三)你好,我叫 Embedding
Kfaino2026/6/28

AI翻身(三) 你好,我叫 Embedding——AI终于学会了理解,而不是死记硬背 大家好。 我叫 Embedding。 有人叫我: 向量。 有人叫我: 词向量。 还有人喜欢给我起一个特别高大上的名字: 语义空间映射。 听起来很厉害。 其实。 我就是一个翻译。 不过。 我翻译的不是中文和英文。 我翻译的是: 文字和数学。 我第一次见到老板的时候 老板(Transformer)对我说: "以后,人类说什么,你负责翻译。" 我愣住了。 "我不会中文啊。" 老板笑了。 "没关系。" "我也不会


笑抽了!DeepSeek识图,豆包完胜了!
甲维斯2026/6/19

听说 DeepSeek 识图功能上线了,我非常兴奋啊!终于要补上多模态这个短板了么? 打开APP和官网看了一眼: 真的出现了一个识图模式!哇塞! 我赶紧拿“梁爷爷”的图片试一波! 看到结果那一刻我瞬间,我忍不住笑出了声! 我的世界观被颠覆了。 原来这个人是腾讯公司高级副总裁、微信创始人张小龙。 我继续追问:那这个人是谁呢? 哇,世界观再次被颠覆!原来这两个人是同一个人?只是换了一个休息的造型而已??? 牛逼,还说出了 1、2、3、4,有理有据!好的,我信你了,这个人叫“张小龙”! 但是


Claude Code 每次调用 API 时,上下文是怎么"拼"出来的?
candyTong2026/6/11

Claude Code 每次调用模型 API 时,传给 API 的 payload 由三部分组成: System Prompt — 定义 Agent 的身份、行为规范和会话上下文 Tools — 工具 schema 列表,告诉模型有哪些能力可用 Messages — 对话消息,包含用户指令、CLAUDE.md 配置、工具执行结果 这三部分都会在 Agent Loop 调用模型时传入,但它们的来源不同:System Prompt 和 Tools 主要在进入循环前准备好,并在循环中保持相对稳定;

首页编辑器站点地图

本站内容在 CC BY-SA 4.0 协议下发布

Copyright © 2026 聚合阅读