本次主要采用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版权协议,转载请附上原文出处链接和本声明。