FPGA第五节:ADDA实验

本次主要采用ad9280和ad9708进行ad和da信号转换。
1、信号流通
由ROM中的IP核输出模拟信号,然后经由da9708进行数模转换,经过一根BNC线将ad9708的输出口和ad9280的输入口接到一起,形成一个环路,然后ad9280进行模数转换。
2、模块讲解
模块一:sample。进行8位数字信号的采集,每次采集1280位,然后间隔一段时间采集一次。将采集到的信号,同时还有有效信号,地址信号一同输入到display模块。
模块二:color。主要任务为产生行同步信号,场同步信号还有数据有效信号。同时输出一个彩条RGB信号作为背景。
模块三:display。接收来自sample的数据信号,还有来自color的hs,vs,de,rgb信号。使用IP核将数据信号写入RAM中,并根据不同的频率从ram中读出信号。display模块中还包含一个用于读取图像坐标的getxy模块。
IP核:包括三个IP核,时钟模块,rgb转dvi模块,还有ROM模块(输出预加载波形)
在这里插入图片描述

3、代码讲解
(1)sample模块

module AD_SAMPLE(
input ad_clk,                      //时钟信号
input rst,                         //重置信号
input[7:0] ad_data,                //采集数据
input ad_data_valid,               //信号有效位
output ad_buf_wr,                  //写允许信号
output[11:0] ad_buf_addr,          //写地址
output[7:0] ad_buf_data            //输出信号
    );
    
//提前设置状态位数值
 localparam S_IDLE=0;                  //空闲位
 localparam S_SAMPLE=1;                //采样位
 localparam S_WAIT=2;                  //等待位
 
 reg[7:0] ad_data0;                    
 reg[10:0] sample_cnt;                 //采样计数
 reg [31:0] wait_cnt;                  //等待计数
 reg[2:0] state;                       //状态位
 
 assign ad_buf_addr=sample_cnt;        //把采样计数赋给地址 
 assign ad_buf_data=ad_data0;          //给数据
 assign ad_buf_wr=(state==S_SAMPLE && ad_data_valid==1'b1)?1'b1:1'b0;  //在采样时段且数据有效位为高电平
 
 //复位
 always@(posedge ad_clk or posedge rst)
     begin
         if(rst==1'b1)                     //如果复位信号有效
         ad_data0<=8'b0;                   //数据置零
         else if(ad_data_valid==1'b1)      //复位信号无效且数据有效位为高电平
         ad_data0<=ad_data;                //传送数据
     end
 
 //读取设置
always@(posedge ad_clk or posedge rst) 
    begin
        if(rst==1'b1)                      //如果复位信号有效
            begin
            state<=S_IDLE;                 //转为空闲状态
            wait_cnt=32'd0;                //等待技术位置零
            sample_cnt<=11'd0;             //采样计数位置零
            end
         else 
         case(state)
            S_IDLE:                 
                begin
                    state<=S_SAMPLE;                          //转为采样位
                end   
             //像素设置为1280*720,单次采样1280个数据      
            S_SAMPLE:       
                begin
                    if(ad_data_valid==1'b1)                   //如果数据有效位为高电平
                    begin
                        if(sample_cnt==11'd1279)              //采样计数等于1280时
                            begin
                                sample_cnt<=11'd0;            //计数清零
                                state<=S_WAIT;                //转为等待位
                            end
                        else
                            begin
                                sample_cnt<=sample_cnt+1'b1;  //采样计数加一
                            end        
                    end
                end   
            //等待一段时间再次采样             
            S_WAIT:  
                begin
                if(wait_cnt==32'd25_000_000)                  //等待时间/晶振周期=25000000
                    begin
                        state<=S_SAMPLE;                      //转为采样位
                        wait_cnt<=32'd0;                      //等待计数置零
                    end
                else
                    begin
                        wait_cnt<=wait_cnt+1'b1;              //等待计数加一
                    end
                end        
            default:state<=S_IDLE;                            //转回空闲位
            endcase
    end
    
endmodule

(2)color模块
经典LCD RGB控制的典型时序图
在这里插入图片描述

module color_bar(
	input                 clk,           //像素时钟
	input                 rst,           //复位信号高电平激活
	output                hs,            //水平同步
	output                vs,            //垂直同步信号
	output                de,            //视频有效信号
	output[7:0]           rgb_r,         //视频红色数据
	output[7:0]           rgb_g,         //视频绿色数据
	output[7:0]           rgb_b          //视频蓝色数据
);

//if  VIDEO_1280_720
parameter H_ACTIVE = 16'd1280;           //水平活动像素
parameter H_FP = 16'd110;                //水平前沿像素
parameter H_SYNC = 16'd40;               //水平同步像素
parameter H_BP = 16'd220;                //水平后沿时间
parameter V_ACTIVE = 16'd720;            //垂直活动像素
parameter V_FP  = 16'd5;                 //垂直前沿像素
parameter V_SYNC  = 16'd5;               //垂直同步像素
parameter V_BP  = 16'd20;                //垂直后沿像素
parameter HS_POL = 1'b1;                 
parameter VS_POL = 1'b1;                 


parameter H_TOTAL = H_ACTIVE + H_FP + H_SYNC + H_BP;//水平总像素
parameter V_TOTAL = V_ACTIVE + V_FP + V_SYNC + V_BP;//垂直总像素

//8种颜色的RGB信号
parameter WHITE_R       = 8'hff;
parameter WHITE_G       = 8'hff;
parameter WHITE_B       = 8'hff;
parameter YELLOW_R      = 8'hff;
parameter YELLOW_G      = 8'hff;
parameter YELLOW_B      = 8'h00;                                
parameter CYAN_R        = 8'h00;
parameter CYAN_G        = 8'hff;
parameter CYAN_B        = 8'hff;                                
parameter GREEN_R       = 8'h00;
parameter GREEN_G       = 8'hff;
parameter GREEN_B       = 8'h00;
parameter MAGENTA_R     = 8'hff;
parameter MAGENTA_G     = 8'h00;
parameter MAGENTA_B     = 8'hff;
parameter RED_R         = 8'hff;
parameter RED_G         = 8'h00;
parameter RED_B         = 8'h00;
parameter BLUE_R        = 8'h00;
parameter BLUE_G        = 8'h00;
parameter BLUE_B        = 8'hff;
parameter BLACK_R       = 8'h00;
parameter BLACK_G       = 8'h00;
parameter BLACK_B       = 8'h00;

reg hs_reg;                      //水平同步寄存器
reg vs_reg;                      //垂直同步寄存器
reg hs_reg_d0;                   //对 'hs_reg'延时一个时钟
reg vs_reg_d0;                   //对 'vs_reg'延时一个时钟
reg[11:0] h_cnt;                 //水平计数器
reg[11:0] v_cnt;                 //垂直计数器
reg[11:0] active_x;              //视频x的位置
reg[11:0] active_y;              //视频y的位置
reg[7:0] rgb_r_reg;              //视频红色数据寄存器
reg[7:0] rgb_g_reg;              //视频绿色数据寄存器
reg[7:0] rgb_b_reg;              //视频蓝色数据寄存器
reg h_active;                    //水平有效
reg v_active;                    //垂直有效
wire video_active;               //视频有效
reg video_active_d0;             //video_active延时一个时钟

assign hs = hs_reg_d0;
assign vs = vs_reg_d0;
assign video_active = h_active & v_active;  //视频有效等于水平和垂直同时有效
assign de = video_active_d0;
assign rgb_r = rgb_r_reg;
assign rgb_g = rgb_g_reg;
assign rgb_b = rgb_b_reg;

//复位
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		begin
			hs_reg_d0 <= 1'b0;
			vs_reg_d0 <= 1'b0;
			video_active_d0 <= 1'b0;
		end
	else
		begin
			hs_reg_d0 <= hs_reg;
			vs_reg_d0 <= vs_reg;
			video_active_d0 <= video_active;
		end
end

//水平计数一个时钟加1,达到最大值之后更新
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		h_cnt <= 12'd0;
	else if(h_cnt == H_TOTAL - 1)//水平计数最大值
		h_cnt <= 12'd0;
	else
		h_cnt <= h_cnt + 12'd1;
end
//视频x坐标
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		active_x <= 12'd0;
	else if(h_cnt >= H_FP + H_SYNC + H_BP - 1)//水平有效
		active_x <= h_cnt - (H_FP[11:0] + H_SYNC[11:0] + H_BP[11:0] - 12'd1);
	else
		active_x <= active_x;
end

//垂直计数,当水平计满,然后垂直加一一次,最后判断是否记满
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		v_cnt <= 12'd0;
	else if(h_cnt == H_FP  - 1)//水平同步像素
		if(v_cnt == V_TOTAL - 1)/垂直计数最大值
			v_cnt <= 12'd0;
		else
			v_cnt <= v_cnt + 12'd1;
	else
		v_cnt <= v_cnt;
end

//水平同步信号
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		hs_reg <= 1'b0;
	else if(h_cnt == H_FP - 1)//水平同步开始
		hs_reg <= HS_POL;
	else if(h_cnt == H_FP + H_SYNC - 1)//水平同步结束
		hs_reg <= ~hs_reg;
	else
		hs_reg <= hs_reg;
end

//水平活动信号
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		h_active <= 1'b0;
	else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//水平活动开始
		h_active <= 1'b1;
	else if(h_cnt == H_TOTAL - 1)//水平活动结束
		h_active <= 1'b0;
	else
		h_active <= h_active;
end

//垂直同步信号
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		vs_reg <= 1'd0;
	else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//垂直同步开始
		vs_reg <= HS_POL;
	else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//垂直同步结束
		vs_reg <= ~vs_reg;  
	else
		vs_reg <= vs_reg;
end

//垂直活动信号
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		v_active <= 1'd0;
	else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//垂直活动开始
		v_active <= 1'b1;
	else if((v_cnt == V_TOTAL - 1) && (h_cnt == H_FP - 1)) //垂直活动结束
		v_active <= 1'b0;   
	else
		v_active <= v_active;
end

//将屏幕分为8块,赋予不同的RGB数据
always@(posedge clk or posedge rst)
begin
	if(rst == 1'b1)
		begin
			rgb_r_reg <= 8'h00;
			rgb_g_reg <= 8'h00;
			rgb_b_reg <= 8'h00;
		end
	else if(video_active)
		if(active_x == 12'd0)
			begin
				rgb_r_reg <= WHITE_R;
				rgb_g_reg <= WHITE_G;
				rgb_b_reg <= WHITE_B;
			end
		else if(active_x == (H_ACTIVE/8) * 1)
			begin
				rgb_r_reg <= YELLOW_R;
				rgb_g_reg <= YELLOW_G;
				rgb_b_reg <= YELLOW_B;
			end         
		else if(active_x == (H_ACTIVE/8) * 2)
			begin
				rgb_r_reg <= CYAN_R;
				rgb_g_reg <= CYAN_G;
				rgb_b_reg <= CYAN_B;
			end
		else if(active_x == (H_ACTIVE/8) * 3)
			begin
				rgb_r_reg <= GREEN_R;
				rgb_g_reg <= GREEN_G;
				rgb_b_reg <= GREEN_B;
			end
		else if(active_x == (H_ACTIVE/8) * 4)
			begin
				rgb_r_reg <= MAGENTA_R;
				rgb_g_reg <= MAGENTA_G;
				rgb_b_reg <= MAGENTA_B;
			end
		else if(active_x == (H_ACTIVE/8) * 5)
			begin
				rgb_r_reg <= RED_R;
				rgb_g_reg <= RED_G;
				rgb_b_reg <= RED_B;
			end
		else if(active_x == (H_ACTIVE/8) * 6)
			begin
				rgb_r_reg <= BLUE_R;
				rgb_g_reg <= BLUE_G;
				rgb_b_reg <= BLUE_B;
			end 
		else if(active_x == (H_ACTIVE/8) * 7)
			begin
				rgb_r_reg <= BLACK_R;
				rgb_g_reg <= BLACK_G;
				rgb_b_reg <= BLACK_B;
			end
		else
			begin
				rgb_r_reg <= rgb_r_reg;
				rgb_g_reg <= rgb_g_reg;
				rgb_b_reg <= rgb_b_reg;
			end         
	else
		begin
			rgb_r_reg <= 8'h00;
			rgb_g_reg <= 8'h00;
			rgb_b_reg <= 8'h00;
		end
end

endmodule 

(3)display

module DISPLAY(
input               rst,                            //复位信号
input               pclk,                           //像素时钟
input[23:0]         wave_color,                     //波形颜色
input               ad_clk,                         //数字信号输入时钟
input                   i_hs,                       //水平同步信号    
input                   i_vs,                       //垂直同步信号
input                   i_de,                       //视频有效信号
input               ad_buf_wr,                      //写信号
input[11:0]         ad_buf_addr,                    //写地址
input[7:0]          ad_buf_data,                    //数据
output              o_hs,                           //水平同步信号
output              o_vs,                           //垂直同步信号
output              o_de,                           //视频有效信号
output[23:0]        o_data                          //输出数据
    );  
    //一些寄存器命名
    wire [11:0] pos_x;
    wire [11:0] pos_y;
    wire        pos_hs;
    wire        pos_vs;
    wire        pos_de;
    wire[23:0] pos_data;
    reg[23:0]  v_data;
    reg[10:0]  rdaddress;
    wire[7:0] q;
    reg        region_active;
    
    assign o_data=v_data;
    assign o_hs=pos_hs;
    assign o_vs=pos_vs;
    assign o_de=pos_de;
    
    always@(posedge pclk)              //区域有效控制
    begin
        if(pos_y>=12'd9&&pos_y<=12'd308&&pos_x>=12'd9&&pos_x<=12'd1018)
        region_active<=1'b1;
        else 
        region_active<=1'b0;
    end
    
    always@(posedge pclk)             //读地址控制
    begin
        if(region_active==1'b1&&pos_de==1'b1)
        rdaddress<=rdaddress+11'd1;
        else
        rdaddress<=11'd0;
    end    
    
    always@(posedge pclk)
    begin
        if(region_active==1'b1)
             if(12'd287-pos_y=={4'd0,q})
                 v_data<=wave_color;
             else
                 v_data<=pos_data;
         else
             v_data<=pos_data;
    end
    
    //双口RAM,用不同时钟进行读写,包括数据和地址
    dpram2048x8 buffer(
    .clka  (ad_clk),
    .ena   (1'b1),
    .wea(ad_buf_wr),
    .addra(ad_buf_addr[10:0]),
    .dina(ad_buf_data),
    .clkb  (pclk),
    .enb(1'b1),
    .addrb(rdaddress),
    .doutb(q)   
    );
    
    //坐标模块,根据输入的同步信号,得到新同步信号,输出数据,还有视频坐标
timing_gen_xy timing_gen_xy_m0(
	.rst_n    (rst_n    ),
	.clk      (pclk     ),
	.i_hs     (i_hs     ),
	.i_vs     (i_vs     ),
	.i_de     (i_de     ),
	.i_data   (i_data   ),
	.o_hs     (pos_hs   ),
	.o_vs     (pos_vs   ),
	.o_de     (pos_de   ),
	.o_data   (pos_data ),
	.x        (pos_x    ),
	.y        (pos_y    )
);
    
 endmodule

(4)顶层模块

module top(
	input                       sys_clk,
	input                       rst_n,
	input[7:0]                  ad9280_data,
	output                      ad9280_clk,
	output[7:0]                 ad9708_data,
	output                      ad9708_clk,
            output                      TMDS_clk_p,
            output                      TMDS_clk_n,
            output[2:0]                 TMDS_data_p,       
            output[2:0]                 TMDS_data_n,        
            output [0:0]                hdmi_oen

);

wire                            video_clk;
wire                            video_clk5x;
wire                            video_hs;
wire                            video_vs;
wire                            video_de;
wire[7:0]                       video_r;
wire[7:0]                       video_g;
wire[7:0]                       video_b;

wire                            hdmi_hs;
wire                            hdmi_vs;
wire                            hdmi_de;
wire[7:0]                       hdmi_r;
wire[7:0]                       hdmi_g;
wire[7:0]                       hdmi_b;

wire                            wave0_hs;
wire                            wave0_vs;
wire                            wave0_de;
wire[7:0]                       wave0_r;
wire[7:0]                       wave0_g;
wire[7:0]                       wave0_b;

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_data;
reg[8:0]                        rom_addr;

assign hdmi_hs = wave0_hs;
assign hdmi_vs = wave0_vs;
assign hdmi_de = wave0_de;
assign hdmi_r  = wave0_r;
assign hdmi_g  = wave0_g;
assign hdmi_b  = wave0_b;

assign ad9280_clk = adc_clk;
assign ad9708_clk = dac_clk;
assign ad9708_data = dac_data;

video_pll video_pll_m0
 (
	.clk_in1                    (sys_clk                  ),
	.clk_out1                   (video_clk                ),
	.clk_out2                   (video_clk5x              ),
	.reset                      (1'b0                     ),
	.locked                     (                         )
 );

adda_pll adda_pll_m0
 (
	.clk_in1                    (sys_clk                  ),
	.clk_out1                   (adc_clk                  ),
	.clk_out2                   (dac_clk                  ),
	.reset                      (1'b0                     ),
	.locked                     (                         )
 );
 
//dac 125Mhz/512 = 244.14khz
always@(posedge dac_clk)
begin
	rom_addr <= rom_addr + 9'd1;
end
da_rom da_rom_m0 (
	.clka                       (dac_clk                 ),   
	.ena                        (1'b1                    ),     
	.addra                      (rom_addr                ), 
	.douta                      (dac_data                )  
);

color_bar color_bar_m0(
	.clk                        (video_clk                ),
	.rst                        (~rst_n                   ),
	.hs                         (video_hs                 ),
	.vs                         (video_vs                 ),
	.de                         (video_de                 ),
	.rgb_r                      (video_r                  ),
	.rgb_g                      (video_g                  ),
	.rgb_b                      (video_b                  )
);


rgb2dvi_0 rgb2dvi_m0 (
    .TMDS_Clk_p(TMDS_clk_p),
    .TMDS_Clk_n(TMDS_clk_n),
    .TMDS_Data_p(TMDS_data_p),
    .TMDS_Data_n(TMDS_data_n),
    .oen(hdmi_oen),
    .aRst_n(1'b1), //异步清零
    
    .vid_pData({hdmi_r,hdmi_g,hdmi_b}),
    .vid_pVDE(hdmi_de),
    .vid_pHSync(hdmi_hs),
    .vid_pVSync(hdmi_vs),       
    .PixelClk(video_clk),
    
    .SerialClk(video_clk5x)// 5像素clk
    );


ad9280_sample ad9280_sample_m0(
	.adc_clk               (adc_clk                    ),
	.rst                   (~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              )
);

//display 50khz - 1Mhz
wav_display wav_display_m0(
	.rst_n                 (rst_n                      ),
	.pclk                  (video_clk                  ),
	.wave_color            (24'hff0000                 ),
	.adc_clk               (adc_clk                    ),
	.adc_buf_wr            (adc0_buf_wr                ),
	.adc_buf_addr          (adc0_buf_addr              ),
	.adc_buf_data          (adc0_buf_data              ),
	.i_hs                  (video_hs                    ),
	.i_vs                  (video_vs                    ),
	.i_de                  (video_de                    ),
	.i_data                ({video_r,video_g,video_b}     ),
	.o_hs                  (wave0_hs                   ),
	.o_vs                  (wave0_vs                   ),
	.o_de                  (wave0_de                   ),
	.o_data                ({wave0_r,wave0_g,wave0_b}  )
);

endmodule

版权声明:本文为qq_41520766原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。