FPGA实现AD9708和AD9280波形收发输出HDMI模拟示波器,串口协议帧控制显示,提供工程源码和技术支持

1、AD9708芯片解读和电路设计

AD9708 很简单,8 位分辨率,125MSPS 采样率,输入参考电压3~5V,内置 1.2V 参考电压,8bit数字信号输入,差分电流输出;芯片操作不需要软件配置,给个时钟信号就工作,简单得很,根据官方手册,内部结构如下:
在这里插入图片描述
在这里插入图片描述
SLEEP引脚提供芯片休眠功能,当不需要使用该芯片时可拉高SLEEP以降低电路板功耗,当不使用休眠功能时,官方建议该引脚悬空;
REFLO引脚接模拟地开启内置1.2V 参考电压功能,既然芯片都提供了这样的功能,当然要用啊,不用时要接AVDD;
芯片外围电路就这么简单,照着官方手册画就完事儿了,重要的是芯片输出的匹配电路设计,AD9708 是差分输出,若要用线缆输出连接其他设备,必然要实现差分转单端的功能,为了为了防止噪声干扰,保持输出波形的线条完美,参考了网上大佬,推荐使用7 阶巴特沃斯低通滤波器;原理图部分如下:
在这里插入图片描述
然后再使用差分转单端芯片输出模拟单端信号;

2、AD9280芯片解读和电路设计

AD9280也 很简单,8 位分辨率,32MSPS 采样率,输入参考电压2.7~5.5V,芯片操作不需要软件配置,给个时钟信号就工作,简单得很,根据官方手册,内部结构如下:
在这里插入图片描述
在这里插入图片描述
STBY引脚接高电平进入休眠模式,接低电平则一直工作;根据电路板功耗要求设计;
这里重点将一下输入电压AIN;作为模拟输入,它可以配置为多种模式,分别由不同引脚得上下拉决定,具体看手册,说得很清楚,这里只将我这里的配置,参考了官方给的设计如下:
在这里插入图片描述
根据官方给的公式:
在这里插入图片描述
REFBS引脚接地;REFTS引脚接地2V;

3、FPGA设计框架

在这里插入图片描述
可以看到:本设计哟如下功能:
1、上位机软件生成波形文件,通过AD9708发送出去;
2、AD9280接收AD9708发出的波形(回环);并采集;
3、HDMI显示器显示AD9280采集的波形;
4、AD9708发送的波形类型由串口配置;
5、HDMI显示波形的位置由串口配置;

4、AD9708波形生成并发送

采用上位机软件生成波形文件,并转化为.coe文件,vivado调用rom ip核,将.coe文件固化进去即可,波形数据直接给到AD9708输出接口即可,简单得很;
本设计设计了三种波形,正弦波,三角波,正弦波和三角波结合的自定义波形;
AD9708输出哪种波形由串口控制,串口发送不同数据,AD9708输出不同波形;
波形生成上位机软件附带在工程目录下,可直接转化为.coe文件,如下:
在这里插入图片描述

5、AD9280采集接收波形

AD9280采集接收AD9708发来波形;由于要适配显示器,所以AD9280采集需要设置时间间隔,不然看不到波形了;同时,AD9280采集数据后需要写入ram中,由视频时序生成器读出数据,达到跨时钟的作用;AD9280采集时钟为32M,视频时钟为65M;

6、HDMI波形显示算法

波形在屏幕上的显示效果如下:
在这里插入图片描述
显示分辨率设为1024X768;
对照上图,设置相关参数如下:

wire [23:0] GRID_BACK         = 24'h000000                     ;	//波形显示区域背景颜色
wire [23:0] GRID_WAVE         = 24'h00ff00                     ;	//波形格子条纹颜色
wire [10:0] GRID_LENGTH       = 11'd1010                       ;	//波形显示区域长度
wire [10:0] GRID_WIDTH        = 11'd300                        ;	//波形显示区域宽度
//parameter GRID_X_START      = 11'd9                        ;	//波形显示区域背景x轴起始坐标
wire [10:0] GRID_X_END        = i_grid_x_start+GRID_LENGTH-1'b1;	//波形显示区域背景x轴终点坐标
//parameter GRID_Y_START      = 11'd243                      ;	//波形显示区域背景y轴起始坐标	
wire [10:0] GRID_Y_END        = i_grid_y_start+GRID_WIDTH-1'b1 ;	//波形显示区域背景y轴终点坐标	
wire [10:0] GRID_CENTRE       = i_grid_y_start+GRID_WIDTH/2    ;	//波形显示区域背景中间线位置
wire [10:0] GRID_Y_WAVE_START = i_grid_y_start+11'd23          ;	//波形格子条纹y轴起始坐标
wire [10:0] GRID_Y_WAVE_END   = GRID_Y_END-11'd21            	 ;	//波形格子条纹y轴终点坐标

其中波形显示区域背景x轴起始坐标和波形显示区域背景y轴起始坐标由输入接口决定,如下:

	input  [10:0] i_grid_x_start,
	input  [10:0] i_grid_y_start,

波形显示区模块的顶层接口如下:

module helai_grid_disp (
	input         pclk          ,
	input  [10:0] i_grid_x_start,
	input  [10:0] i_grid_y_start,
	input  [10:0] i_pos_x       ,	
	input  [10:0] i_pos_y       ,
	input         i_de          ,
	input  [23:0] i_data        ,     
	output [23:0] o_data        
);

波形显示画线模块的顶层接口如下:

module helai_wav_disp (
	input         pclk          ,  
	input  [23:0] wave_color    ,
	input         adc_clk       ,
	input         adc_buf_wr    ,
	input  [11:0] adc_buf_addr  ,
	input  [7:0]  adc_buf_data  ,
	input  [10:0] i_grid_x_start,
	input  [10:0] i_grid_y_start,	
	input  [10:0] i_pos_x       ,	
	input  [10:0] i_pos_y       ,	
	input         i_de          ,	
	input  [23:0] i_data        ,    
	output [23:0] o_data        
);

只要给出i_grid_x_start和i_grid_y_start两个参数,就能决定波形显示区的位置;
而这两个参数由串口输入决定;

7、串口协议帧控制波形显示

串口协议帧由帧头、数据、和校验、帧尾组成,其中数据4字节,有关串口协议帧,请参考我之前写的文章点击查看串口协议帧
FPGA解析串口协议帧,提取有效的4字节数据,控制波形输出和显示位置,具体协议如下:

//串口有效数据 Byte3 Byte2 Byte1 Byte0
//Byte3:定义波形显示区域背景x轴起始坐标
//Byte2和Byte1:波形显示区域背景y轴起始坐标
//Byte0=0-->输出正弦波
//Byte0=1-->输出三角波
//Byte0=2-->输出自定义波

代码层面如下:

always @(posedge clk_200m) begin
	if(~rst_n) _rx_data<=32'h09_00_f3_00;	//9 ,234 ,0
	else if(o_rx_done) _rx_data<=o_rx_data;
end

reg [7:0] wave_data;

always @(*) begin
	if(_rx_data[7:0]==8'd0) wave_data<=dac_sin;	
	else if(_rx_data[7:0]==8'd1) wave_data<=dac_triangular; 
	else if(_rx_data[7:0]==8'd2) wave_data<=dac_zihui;
	else wave_data<=dac_sin;
end

上电后,波形默认显示在屏幕正中间位置,如下:
在这里插入图片描述

8、vivado工程

开发板:Xilinx Artix7开发板;
开发环境:vivado2019.1;
输入:串口、AD波形;
输出:AD数据、HDMI视频;
代码架构如下:
在这里插入图片描述
顶层代码如下:

module top(
	input        sys_clk_p  ,
	input        sys_clk_n  ,
	input[7:0]   ad9280_data,
	output       ad9280_clk ,
	output[7:0]  ad9708_data,
	output       ad9708_clk ,
    inout        hdmi_scl   ,
    inout        hdmi_sda   ,
    output       hdmi_nreset,
    output       vout_clk   ,
    output       vout_hs    ,
    output       vout_vs    ,
    output       vout_de    ,
    output[23:0] vout_data  ,
	input        i_uart_rx  ,	
	output       o_uart_tx	
	
);

wire      video_clk;
wire      video_hs;
wire      video_vs;
wire      video_de;

wire       adc_clk;
wire       adc0_buf_wr;
wire[10:0] adc0_buf_addr;
wire[7:0]  adc0_buf_data;
wire       dac_clk;

wire [7:0] dac_sin  ;
wire [7:0] dac_triangular;
wire [7:0] dac_zihui;
reg  [8:0] rom_addr;

wire[9:0]  hdmi_lut_index;
wire[31:0] hdmi_lut_data;

assign vout_clk    = video_clk;
assign vout_hs     = video_hs;
assign vout_vs     = video_vs;
assign vout_de     = video_de;
assign vout_data   = wave0_rgb;

assign hdmi_nreset = rst_n;
assign ad9280_clk = adc_clk;
assign ad9708_clk = dac_clk;
assign ad9708_data = wave_data;
wire rst_n;
wire clk_200m;

wire        o_rx_done;
wire [31:0] o_rx_data;
reg  [31:0] _rx_data;

wire [23:0] video_rgb;
wire [10:0] x_pos;
wire [10:0] y_pos;
wire [23:0] grid_rgb;
wire [23:0] wave0_rgb;

clk_wiz_0 u_clk_wiz_0
   (
    // Clock out ports
    .clk_200m(clk_200m),     // output clk_200m
    .clk_video(video_clk),     // output clk_video
    .clk_adc(adc_clk),     // output clk_adc
    .clk_dac(dac_clk),     // output clk_dac
    // Status and control signals
    .locked(rst_n),       // output locked
   // Clock in ports
    .clk_in1_p(sys_clk_p),    // input clk_in1_p
    .clk_in1_n(sys_clk_n));    // input clk_in1_n 
 
 //I2C master controller
i2c_config i2c_config_m2(
   .rst           (~rst_n              ),
   .clk           (clk_200m            ),
   .clk_div_cnt   (16'd500             ),
   .i2c_addr_2byte(1'b0                ),
   .lut_index     (hdmi_lut_index      ),
   .lut_dev_addr  (hdmi_lut_data[31:24]),
   .lut_reg_addr  (hdmi_lut_data[23:8] ),
   .lut_reg_data  (hdmi_lut_data[7:0]  ),
   .error         (                    ),
   .done          (                    ),
   .i2c_scl       (hdmi_scl            ),
   .i2c_sda       (hdmi_sda            )
);
//configure look-up table
lut_hdmi lut_hdmi_m0(
   .lut_index(hdmi_lut_index),
   .lut_data (hdmi_lut_data )
); 
//dac 125Mhz/512 = 244.14khz
always@(posedge dac_clk) rom_addr <= rom_addr + 9'd1;

always @(posedge clk_200m) begin
	if(~rst_n) _rx_data<=32'h09_00_f3_00;	//9 ,234 ,0
	else if(o_rx_done) _rx_data<=o_rx_data;
end

reg [7:0] wave_data;

always @(*) begin
	if(_rx_data[7:0]==8'd0) wave_data<=dac_sin;	
	else if(_rx_data[7:0]==8'd1) wave_data<=dac_triangular; 
	else if(_rx_data[7:0]==8'd2) wave_data<=dac_zihui;
	else wave_data<=dac_sin;
end

sin_rom u_sin_rom (
	.clka (dac_clk ),   
	.ena  (1'b1    ),     
	.addra(rom_addr), 
	.douta(dac_sin )  
);

triangular_rom u_triangular_rom (
  .clka (dac_clk       ),    // input wire clka
  .ena  (1'b1          ),      // input wire ena
  .addra(rom_addr      ),  // input wire [8 : 0] addra
  .douta(dac_triangular)  // output wire [7 : 0] douta
);

zihui_rom u_zihui_rom (
  .clka (dac_clk     ),    // input wire clka
  .ena  (1'b1        ),      // input wire ena
  .addra(rom_addr    ),  // input wire [8 : 0] addra
  .douta(dac_zihui   )  // output wire [7 : 0] douta
);

uart_rx_analysis_top #(
    .CLK_FREQ(200_000_000),  //系统时钟频率
    .UART_BPS(115200     )   //串口波特率
)
u_uart_rx_analysis_top(
	.clk       (clk_200m ),
	.rst_n     (rst_n    ),
	.i_uart_rx (i_uart_rx),
	.o_uart_tx (o_uart_tx),
	.o_rx_done (o_rx_done),
	.o_rx_data (o_rx_data)
);

video_timing_control u_video_timing_control(
	.i_clk  (video_clk ),	
	.i_rst_n(rst_n     ), 
	.i_rgb  (24'hffffff),
	.o_hs   (video_hs  ),
	.o_vs   (video_vs  ),
	.o_de   (video_de  ),
	.o_rgb  (video_rgb ),
	.o_x_pos(x_pos     ),
	.o_y_pos(y_pos     )
);

helai_grid_disp u_helai_grid_disp(
	.pclk          (video_clk      ), 
	.i_grid_x_start(_rx_data[31:24]),
	.i_grid_y_start(_rx_data[23: 8]),	
	.i_pos_x       (x_pos          ),	
	.i_pos_y       (y_pos          ),
	.i_de          (video_de       ),	
	.i_data        (video_rgb      ),     
	.o_data        (grid_rgb       )
);

ad9280_sample ad9280_sample_m0(
	.adc_clk       (adc_clk      ),
	.rstn          (rst_n        ),
	.adc_data      (ad9280_data  ),
	.adc_data_valid(1'b1         ),
	.adc_buf_wr    (adc0_buf_wr  ),
	.adc_buf_addr  (adc0_buf_addr),
	.adc_buf_data  (adc0_buf_data)
);

helai_wav_disp u_helai_wav_disp(
	.pclk          (video_clk      ),  
	.wave_color    (24'h00ff00     ),
	.adc_clk       (adc_clk        ),
	.adc_buf_wr    (adc0_buf_wr    ),
	.adc_buf_addr  (adc0_buf_addr  ),
	.adc_buf_data  (adc0_buf_data  ),
	.i_grid_x_start(_rx_data[31:24]),
	.i_grid_y_start(_rx_data[23: 8]),	
	.i_pos_x       (x_pos          ),	
	.i_pos_y       (y_pos          ),	
	.i_de          (video_de       ),	
	.i_data        (grid_rgb       ),    
	.o_data        (wave0_rgb      )
);
endmodule

9、上板调试验证

演示视频如下:

FPGA实现AD9708和AD9280波形收发输出HDMI模

10、福利:工程源码获取

福利:工程代码的获取
代码太大,无法邮箱发送,以某度网盘链接方式发送,
工程源码下载链接:https://download.csdn.net/download/qq_41667729/87421414
网盘资料如下
在这里插入图片描述

  • 17
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

9527华安

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值