FPGA教程学习
第十五章 HDMI字符显示实验
文章目录
- FPGA教程学习
- 前言
- 实验原理
- 程序设计
- 像素点坐标模块
- 字符叠加模块
- 实验结果
- 知识点
- 总结
前言
在HDMI输出彩条的基础上输出osd叠加信息。
实验原理
实验通过字符转换工具将字符转换为 16 进制 coe 文件存放到单端口的 ROM IP 核中,再从
ROM 中把转换后的数据读取出来显示到 HDMI 上。
大致过程是将视频时序再经过一次处理模块,替换其中特定位置的数据,除了数据其余均不发生变化。
程序设计
与之前的彩条显示多了一个osd叠加模块。
像素点坐标模块
该模块输入信号和输出信号一致,主要是为了计数像素的坐标。
module timing_gen_xy(
input rst_n,
input clk,
input i_hs,
input i_vs,
input i_de,
input[23:0] i_data,
output o_hs,
output o_vs,
output o_de,
output[23:0] o_data,
output[11:0] x, // video position X
output[11:0] y // video position y
);
计数的原理:
场信号在前肩到同步时是上升沿,表示是一副图像的开始,可以根据场信号的上升沿(或者下降沿,一个就行)来将行计数清零,即第零行。行递增计数的话使用DE信号的下降沿进行计数,当DE变为无效时,说明已经输出了一行像素点。
而行信号表示是一行的开始,这里没有用到,直接使用了DE信号,DE信号表示像素点有效,即有效像素点的开始,跳过行前肩+行同步+行后肩,用来计数一行的像素点。
注意数据也需要进行两次延时。
字符叠加模块
由上面的模块已经获取到了当前的坐标,接下来只要知道字符起始位置和需要叠加的字符,将输出的数据进行替换即可。如果当前坐标(像素点)需要叠加,就设置为需要的颜色,否则保持不变即可。
确定区域位置,使用一个寄存器表示,坐标在叠加区域的话就设置为有效。
//OSD区域设置,起始坐标为(9,9),区域大小根据生成的字符长宽设置
always@(posedge pclk)
begin
if(pos_y >= 12'd9 && pos_y <= 12'd9 + OSD_HEGIHT - 12'd1 && pos_x >= 12'd9 && pos_x <= 12'd9 + OSD_WIDTH - 12'd1)
region_active <= 1'b1;
else
region_active <= 1'b0;
end
rom读取,在叠加区域内开始计数,实际计数的是像素点,但是一次读取数据为8bit,所以将低三位去掉即可。
//产生ROM的读地址,在region_active有效时,地址加1
always@(posedge pclk)
begin
if(pos_vs_d1 == 1'b1 && pos_vs_d0 == 1'b0)
osd_ram_addr <= 16'd0;
else if(region_active == 1'b1)
osd_ram_addr <= osd_ram_addr + 16'd1;
end
osd_rom osd_rom_m0 (
.clka (pclk ),
.ena (1'b1 ),
.addra (osd_ram_addr[15:3] ), //生成的字符一个点为1bit,由于数据宽度为8bit,因此8个周期检查一次数据
.douta (q )
);
有了字符叠加区域和字符值,可以进行数据替换,注意这里是依次将8位数据替换,osd_x是像素的横坐标,取低三位作为像素点的计数下标即可。
always@(posedge pclk)
begin
if(region_active_d0 == 1'b1)
if(q[osd_x[2:0]] == 1'b1) //检查bit位是否是1,如果是1,将此像素设为红色
v_data <= 24'hff0000;
else
v_data <= pos_data; //否则保持原来的值
else
v_data <= pos_data;
end
实验结果
直接跑的demo,这里截个官方的图放在这里。
知识点
- rom的创建和初始数据(coe文件设置)的设置。
- rom的读时序。
- 视频时序。
- 边沿检测。
当前一状态和当前状态不同的时候,可认为采样到了边沿信号。
当前一状态为高电平,当前状态为低电平时,说明是下降沿。
当前一状态为低电平,当前状态为高电平时,说明是下降沿。
i_vs,vs_d0 ,vs_d1三个信号去分析的话,要把整个过程理解成并行的,vs_d0 、vs_d1是两个记录状态的寄存器,理解成串行vs->d0->d1是错的。d0是vs的上一个状态,d1是d0上一个状态的记录,或者说,d0是vs延时一个周期的信号,d1是d0延时一个周期的信号。d0可以看作最新的状态,d1是上一个状态,d0&~d1是上升沿。同理可以分析DE的边沿。
assign vs_edge = vs_d0 & ~vs_d1; //VS posedge
assign de_falling = ~de_d0 & de_d1; //DE negedge
always@(posedge clk)
begin
de_d0 <= i_de;
de_d1 <= de_d0;
vs_d0 <= i_vs;
vs_d1 <= vs_d0;
hs_d0 <= i_hs;
hs_d1 <= hs_d0;
end
总结
本实验在HDMI显示彩条的基础上,通过对视频时序的处理以及像素数据的替换,将rom中的字模叠加到画面中,实现了OSD信息的叠加。