当前位置: 首页 > news >正文

ZYNQ实现FFT信号处理项目

项目概述

本项目实现一个基于Zynq-7020的FFT信号处理系统:

  • PS端(ARM)生成测试信号(例如正弦波等)

  • PL端(FPGA)实现1024点FFT计算(1024个时域采样点)

  • 使用AXI DMA进行高速数据传输

  • 结果显示在串口终端

整体框图如下

使用block design进行设计

具体操作如下:

    • Zynq的FCLK_CLK0连接所有IP时钟

    • Zynq的FCLK_RESET0_N连接所有IP复位

    • Zynq的M_AXI_GP0连接所有控制接口

    • Zynq的S_AXI_HP0连接DMA的S_AXI_HP接口

  1. 连接DMA的M_AXIS_MM2S到FFT的S_AXIS_DATA

  2. 连接FFT的M_AXIS_DATA到DMA的S_AXIS_S2MM

  3. 连接Zynq的M_AXI_GP0到FFT的S_AXI_CONFIG

连接System ILA

  1. 连接FFT的输入接口到ILA的slot0

  2. 连接FFT的输出接口到ILA的slot1

进行XDC约束

# 时钟约束
create_clock -period 10.000 -name clk_fpga_0 [get_ports FCLK_CLK0]# 串口约束
set_property PACKAGE_PIN T18 [get_ports UART1_TX]
set_property IOSTANDARD LVCMOS33 [get_ports UART1_TX]
set_property PACKAGE_PIN U18 [get_ports UART1_RX]
set_property IOSTANDARD LVCMOS33 [get_ports UART1_RX]

进行VITIS开发

程序如下

#include <stdio.h>          
#include "xil_printf.h"     // Xilinx专用打印函数(支持串口输出)
#include "xil_io.h"         // Xilinx IO操作函数(读写寄存器)
#include "xaxidma.h"        // AXI DMA驱动库(控制DMA传输)
#include "xparameters.h"    // 设备参数定义(包含硬件IP的ID、基地址等)
#include "xscugic.h"        // 中断控制器驱动库(管理ZYNQ的中断)
#include "xil_exception.h"  // 异常处理函数(注册中断处理逻辑)
#include "xfft.h"           // FFT IP核驱动库(控制FFT硬件加速)
#include "math.h"           // 数学函数库(如sin、sqrt)// 设备ID定义(与硬件工程中的IP核ID对应,来自xparameters.h)
#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID  // DMA设备ID
#define FFT_DEV_ID XPAR_FFT_0_DEVICE_ID    // FFT IP核ID
#define INTC_DEV_ID XPAR_SCUGIC_SINGLE_DEVICE_ID  // 中断控制器ID// 内存地址定义(DDR中的缓冲区地址,需与硬件工程中的地址分配一致)
#define MEM_BASE_ADDR 0x01000000           // 基础内存地址
#define TX_BUFFER_BASE (MEM_BASE_ADDR + 0x00100000)  // 发送缓冲区(输入FFT的数据)
#define RX_BUFFER_BASE (MEM_BASE_ADDR + 0x00300000)  // 接收缓冲区(FFT输出的结果)// FFT参数
#define FFT_LENGTH 1024                    // FFT变换长度(1024点)
#define FFT_SIZE (FFT_LENGTH * 8)          // 总数据量(每个复数8字节:2个float,每个4字节)// 复数结构体(FFT处理的是复数信号,包含实部和虚部)
typedef struct {float real;  // 实部float imag;  // 虚部
} complex_t;// 全局变量(硬件设备实例,用于在函数间共享设备状态)
XAxiDma dma;          // DMA设备实例(控制DMA传输)
XScuGic intc;        // 中断控制器实例(管理中断)
Xfft fft_inst;       // FFT设备实例(控制FFT硬件)// 生成测试信号(两个正弦波叠加:基频 + 3倍频谐波)
void generate_signal(complex_t *signal, int freq) {for (int i = 0; i < FFT_LENGTH; i++) {// 实部:100Hz正弦波 + 0.5倍振幅的300Hz正弦波(3倍频)signal[i].real = sin(2 * M_PI * freq * i / FFT_LENGTH) + 0.5 * sin(2 * M_PI * 3 * freq * i / FFT_LENGTH);signal[i].imag = 0.0f;  // 虚部为0(实数信号)}
}// DMA中断处理函数(当DMA传输完成时触发)
void dma_intr_handler(void *callback) {xil_printf("DMA Transfer Complete!\n");  // 打印传输完成信息
}// 初始化中断系统(配置中断控制器、注册中断处理函数)
int init_intr_system() {XScuGic_Config *intc_config;  // 中断控制器配置结构体Xil_ExceptionInit();          // 初始化异常处理系统// 1. 查找中断控制器的配置信息(根据设备ID)intc_config = XScuGic_LookupConfig(INTC_DEV_ID);if (!intc_config) return XST_FAILURE;  // 配置查找失败// 2. 初始化中断控制器(绑定硬件资源)if (XScuGic_CfgInitialize(&intc, intc_config, intc_config->CpuBaseAddress) != XST_SUCCESS)return XST_FAILURE;  // 初始化失败// 3. 注册全局中断处理函数(将中断转发给中断控制器)Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, &intc);Xil_ExceptionEnable();  // 启用全局异常处理// 4. 连接DMA中断(将DMA的S2MM中断与处理函数绑定)XScuGic_Connect(&intc, XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_INTR, (Xil_ExceptionHandler)dma_intr_handler, &dma);  // 中断号、处理函数、传递给处理函数的参数// 5. 启用DMA的S2MM中断(允许中断触发)XScuGic_Enable(&intc, XPAR_FABRIC_AXIDMA_0_S2MM_INTROUT_INTR);// 6. 启用DMA的所有中断掩码(如传输完成、错误等)XAxiDma_IntrEnable(&dma, XAXIDMA_IRQ_ALL_MASK, XAXIDMA_DEVICE_TO_DMA);  // S2MM方向(设备到内存)return XST_SUCCESS;  // 初始化成功
}// 初始化DMA(配置DMA控制器,准备数据传输)
int init_dma() {XAxiDma_Config *dma_config;  // DMA配置结构体// 1. 查找DMA的配置信息(根据设备ID)dma_config = XAxiDma_LookupConfig(DMA_DEV_ID);if (!dma_config) return XST_FAILURE;  // 配置查找失败// 2. 初始化DMA控制器(绑定硬件资源)if (XAxiDma_CfgInitialize(&dma, dma_config) != XST_SUCCESS)return XST_FAILURE;  // 初始化失败// 3. 检查DMA是否工作在SG模式(Scatter-Gather,分散聚合模式)if (XAxiDma_HasSg(&dma)) {xil_printf("DMA configured in SG mode, not supported\n");return XST_FAILURE;  // 本程序不支持SG模式(仅支持简单传输模式)}return XST_SUCCESS;  // 初始化成功
}// 初始化FFT IP核(配置FFT参数,准备信号处理)
int init_fft() {Xfft_Config *fft_config;  // FFT配置结构体// 1. 查找FFT的配置信息(根据设备ID)fft_config = Xfft_LookupConfig(FFT_DEV_ID);if (!fft_config) return XST_FAILURE;  // 配置查找失败// 2. 初始化FFT IP核(绑定硬件资源)if (Xfft_CfgInitialize(&fft_inst, fft_config, fft_config->BaseAddress) != XST_SUCCESS)return XST_FAILURE;  // 初始化失败// 3. 配置FFT变换长度(1024点)Xfft_SetTransformLength(&fft_inst, FFT_LENGTH);// 4. 配置FFT方向(0表示FFT变换,1表示IFFT逆变换)Xfft_SetDirection(&fft_inst, 0);return XST_SUCCESS;  // 初始化成功
}int main() {complex_t *tx_buffer = (complex_t *)TX_BUFFER_BASE;complex_t *rx_buffer = (complex_t *)RX_BUFFER_BASE;xil_printf("FFT Signal Processing System Initialization\n");// 初始化DMAif (init_dma() != XST_SUCCESS) {xil_printf("DMA initialization failed\n");return XST_FAILURE;}// 初始化FFTif (init_fft() != XST_SUCCESS) {xil_printf("FFT initialization failed\n");return XST_FAILURE;}// 初始化中断系统if (init_intr_system() != XST_SUCCESS) {xil_printf("Interrupt system initialization failed\n");return XST_FAILURE;}// 生成测试信号generate_signal(tx_buffer, 100);xil_printf("Test signal generated\n");// 刷新缓存以确保数据一致性Xil_DCacheFlushRange((u32)tx_buffer, FFT_SIZE);Xil_DCacheFlushRange((u32)rx_buffer, FFT_SIZE);// 启动DMA传输到FFTXAxiDma_SimpleTransfer(&dma, (u32)tx_buffer, FFT_SIZE, XAXIDMA_DMA_TO_DEVICE);// 启动FFT处理Xfft_Start(&fft_inst);xil_printf("FFT processing started\n");// 启动DMA传输从FFTXAxiDma_SimpleTransfer(&dma, (u32)rx_buffer, FFT_SIZE, XAXIDMA_DEVICE_TO_DMA);// 等待传输完成while (XAxiDma_Busy(&dma, XAXIDMA_DEVICE_TO_DMA));// 使缓存无效以读取新数据Xil_DCacheInvalidateRange((u32)rx_buffer, FFT_SIZE);// 打印FFT结果xil_printf("\nFFT Results:\n");xil_printf("Bin\tFrequency\tMagnitude\n");// 打印基波分量for (int i = 98; i < 103; i++) {float mag = sqrt(rx_buffer[i].real * rx_buffer[i].real + rx_buffer[i].imag * rx_buffer[i].imag);xil_printf("%d\t%.1f Hz\t\t%.4f\n", i, (float)i * 100.0, mag);}// 打印谐波分量int harmonic_bin = 300;float mag = sqrt(rx_buffer[harmonic_bin].real * rx_buffer[harmonic_bin].real + rx_buffer[harmonic_bin].imag * rx_buffer[harmonic_bin].imag);xil_printf("%d\t%.1f Hz\t\t%.4f\n", harmonic_bin, (float)harmonic_bin * 100.0, mag);xil_printf("\nFFT Processing Complete!\n");return 0;
}

构建与运行系统

输出

FFT Signal Processing System Initialization
Test signal generated
FFT processing started
DMA Transfer Complete!FFT Results:
Bin     Frequency       Magnitude
98      9800.0 Hz       0.0021
99      9900.0 Hz       0.0085
100     10000.0 Hz      0.9992
101     10100.0 Hz      0.0073
102     10200.0 Hz      0.0018
300     30000.0 Hz      0.4996FFT Processing Complete!

系统调试

使用System ILA

  1. 在Vivado中打开硬件管理器

  2. 编程FPGA后,打开ILA

  3. 设置触发条件:当s_axis_tvalid为高时触发;当m_axis_tvalid为高时触发

  4. 查看波形:输入数据波形;输出数据波形;控制信号时序

在Vitis中添加性能监控代码:

#include "xtime_l.h"// 在main函数中添加
XTime tStart, tEnd;
XTime_GetTime(&tStart);// FFT处理代码XTime_GetTime(&tEnd);
double elapsed = 1.0 * (tEnd - tStart) / (COUNTS_PER_SECOND/1000000);
xil_printf("FFT processing time: %.2f us\n", elapsed);

拓展

后续可添加逻辑分析仪和性能计数器来进行资源分析,同时可以添加VGA显示接口

http://www.lryc.cn/news/612416.html

相关文章:

  • Python科学计算:从基础到工程仿真的完整指南
  • 指挥中心自动化的演变
  • cygwin+php教程(swoole扩展+redis扩展)
  • Redis使用的常见问题及初步认识
  • JDK17新特性全解析
  • TFTP: Linux 系统安装 TFTP,文件系统启动后TFTP使用
  • win服务器系统10060问题解决
  • 【CSS】动态修改浏览器滚动条宽度
  • 楼宇自控系统对建筑碳中和目标的实现具重要价值
  • mysql死锁的常用解决办法
  • Java 里的Tree初认识
  • 【概念学习】什么是深度学习
  • 12、Docker Compose 安装 Redis
  • Effective C++ 条款25:考虑写出一个不抛异常的swap函数
  • 【前端开发】五. ES5和ES6对比
  • imx6ull-驱动开发篇11——gpio子系统
  • 常用排序方法
  • 排序算法归并排序
  • 单变量单步时序预测:CNN-BiGRU卷积神经网络结合双向门控循环单元
  • 202506 电子学会青少年等级考试机器人六级实际操作真题
  • 基于RPR模型的机械臂手写器simulink建模与仿真
  • Qt Frameless Widget跨平台无边框窗口
  • 机器学习-KNN​​
  • 云平台托管集群:EKS、GKE、AKS 深度解析与选型指南-第四章
  • iT 运维: WindoWs CMD 命令表
  • Flutter开发 Image组件使用示例
  • <form> + <iframe> 方式下载大文件的机制
  • 基于Github Pages搭建个人博客站点:hexo环境搭建、本地预览与发布
  • 当前就业形势下,软件测试工程师职业发展与自我提升的必要性
  • AI 软件工程开发 AI 算法 架构与业务