这里的OSD是通过I2C命令,把点阵字模一个点定义为一个字节,送到FPGA的RAM中,再由FPGA根据输出时序进行显示。字符OSD显示在最上面层上。
module osd(
input vin_clk,
input vin_hs,
input vin_vs,
input vin_de,
input vin_f,
input[7:0] vin_r,
input[7:0] vin_g,
input[7:0] vin_b,
output vout_hs,
output vout_vs,
output vout_de,
output vout_f,
output[7:0] vout_r,
output[7:0] vout_g,
output[7:0] vout_b,
input[11:0] osd_wr_addr,
input[1:0] osd_wr_data,
input osd_wren,
input osd_wrclk,
input[11 : 0] top,
input[11 : 0] left
);
/*以下的操作琢磨了一阵,终于明白了用意。ASCII还是16X8的点阵,用0表示不显象素点,用1表示显示像素点。
,在STM32程序中,用一个I2C写一次来表示一个像素,例如:一个H字符,有128个像素点,需要写128次I2C,写的
结果存到ALTER定义的RAM(4096X2),也就是说,一共可以显示4096/128=32个字符。
这样做的结果是,可以用2位表示4种颜色,除去一个背景,还有3种颜色。*/
parameter R0 = 8'd0;
parameter G0 = 8'd0;
parameter B0 = 8'd0; // BLACK
parameter R1 = 8'd255;
parameter G1 = 8'd255;
parameter B1 = 8'd255; // WHITE
parameter R2 = 8'd0;
parameter G2 = 8'd0;
parameter B2 = 8'd255; // BLUE
reg[11:0] rdaddr;
wire[1:0] osd_rd_data;
ram_osd ram_osd_m0(
.data(osd_wr_data),
.rdaddress(rdaddr),
.rdclock(vin_clk),
.wraddress(osd_wr_addr),
.wrclock(osd_wrclk),
.wren(osd_wren),
.q(osd_rd_data));
wire xy_gen_hs;
wire xy_gen_vs;
wire xy_gen_de;
reg xy_gen_hs_d0;
reg xy_gen_vs_d0;
reg xy_gen_de_d0;
reg xy_gen_hs_d1;
reg xy_gen_vs_d1;
reg xy_gen_de_d1;
reg xy_gen_hs_d2;
reg xy_gen_vs_d2;
reg xy_gen_de_d2;
wire[11:0] xy_gen_x;
wire[11:0] xy_gen_y;
wire[11:0] osd_y;
wire[11:0] osd_x;
reg rdreq;
reg rdreq_d0;
wire[11:0] rec_y;
reg[7:0] rgb_r,rgb_g,rgb_b;
reg[7:0] rgb_r_d0,rgb_g_d0,rgb_b_d0;
wire[7:0] r,g,b;
assign rec_y = xy_gen_y[11:0];
assign osd_y = rec_y - top;
assign osd_x = xy_gen_x - left;
assign vout_hs = xy_gen_hs_d2;
assign vout_vs = xy_gen_vs_d2;
assign vout_de = xy_gen_de_d2;
assign vout_f = vin_f;
assign vout_r = rgb_r_d0;
assign vout_g = rgb_g_d0;
assign vout_b = rgb_b_d0;
//assign rdreq = (rec_y > top) && (rec_y <= top + 12'd32) && (xy_gen_x > left) && (xy_gen_x <= left + 12'd128);
timing_gen_xy timing_gen_xy_m0(
.rst_n(1'b1),
.clk(vin_clk),
.i_hs(vin_hs),
.i_vs(vin_vs),
.i_de(vin_de),
.i_data({vin_r,vin_g,vin_b}),
.o_hs(xy_gen_hs),
.o_vs(xy_gen_vs),
.o_de(xy_gen_de),
.o_data({r,g,b}),
.x(xy_gen_x),
.y(xy_gen_y)
);
always@(posedge vin_clk)
begin
rdaddr[11:7] <= osd_y[5:1];
rdaddr[6:0] <= osd_x[7:1];
rdreq <= (rec_y > top) && (rec_y <= top + 12'd64) && (xy_gen_x > left) && (xy_gen_x <= left + 12'd256);
rdreq_d0 <= rdreq;
xy_gen_hs_d0 <= xy_gen_hs;
xy_gen_vs_d0 <= xy_gen_vs;
xy_gen_de_d0 <= xy_gen_de;
xy_gen_hs_d1 <= xy_gen_hs_d0;
xy_gen_vs_d1 <= xy_gen_vs_d0;
xy_gen_de_d1 <= xy_gen_de_d0;
xy_gen_hs_d2 <= xy_gen_hs_d1;
xy_gen_vs_d2 <= xy_gen_vs_d1;
xy_gen_de_d2 <= xy_gen_de_d1;
rgb_r_d0 <= rgb_r;
rgb_g_d0 <= rgb_g;
rgb_b_d0 <= rgb_b;
end
always@(posedge vin_clk)
begin
if(rdreq_d0)
case(osd_rd_data)
2'd0:
begin
rgb_r <= r;
rgb_g <= g;
rgb_b <= b;
end
2'd1:
begin
rgb_r <= R0;
rgb_g <= G0;
rgb_b <= B0;
end
2'd2:
begin
rgb_r <= R1;
rgb_g <= G1;
rgb_b <= B1;
end
2'd3:
begin
rgb_r <= R2;
rgb_g <= G2;
rgb_b <= B2;
end
default:
begin
rgb_r <= r;
rgb_g <= g;
rgb_b <= b;
end
endcase
else
begin
rgb_r <= r;
rgb_g <= g;
rgb_b <= b;
end
end
endmodule
wire[7:0] osd_r;
wire[7:0] osd_g;
wire[7:0] osd_b;
wire osd_hs;
wire osd_vs;
wire osd_de;
vout_display_pro vout_display_pro_m0(
.rst_n(rst_n),
.dp_clk(vga_out_clk),
.h_fp(H_FP[11:0]),
.h_sync(H_SYNC[11:0]),
.h_bp(H_BP[11:0]),
.h_active(H_ACTIVE[11:0]),
.h_total(H_TOTAL[11:0]),
.v_fp(V_FP[11:0]),
.v_sync(V_SYNC[11:0]),
.v_bp(V_BP[11:0]),
.v_active(V_ACTIVE[11:0]),
.v_total(V_TOTAL[11:0]),
.hs(osd_hs), // 输出显示模块的输出不再是直接输出到VGA端口,而是输出到OSD模块
.vs(osd_vs),
.de(osd_de),
.rgb_r(osd_r),
.rgb_g(osd_g),
.rgb_b(osd_b),
.layer0_top(disp_top[16 * CH0 - 5 : 16 * CH0 - 16]),
.layer0_left(disp_left[16 * CH0 - 5 : 16 * CH0 - 16]),
.layer0_width(vout_t_width[16 * CH0 - 5 : 16 * CH0 - 16]),
.layer0_height(vout_t_height[16 * CH0 - 5 : 16 * CH0 - 16]),
.layer0_alpha(alpha[8 * CH0 - 1 : 8 * CH0 - 8]),
.layer0_rdreq(ch0_vout_rd_req),
.layer0_ycbcr(ch0_vout_ycbcr)
);
osd osd_m0(
.vin_clk(vga_out_clk),
.vin_hs(osd_hs),
.vin_vs(osd_vs),
.vin_de(osd_de),
.vin_f(),
.vin_r(osd_r),
.vin_g(osd_g),
.vin_b(osd_b),
.vout_hs(vga_out_hs), // 这才是真正的VGA输出,由OSD模块
.vout_vs(vga_out_vs),
.vout_de(vga_out_de),
.vout_f(),
.vout_r(vga_out_rgb_r),
.vout_g(vga_out_rgb_g),
.vout_b(vga_out_rgb_b),
.osd_wr_addr(osd_wr_addr[11:0]),
.osd_wr_data(osd_wr_data[1:0]),
.osd_wren(osd_wr_en),
.osd_wrclk(clk),
.top(osd_top[11:0]),
.left(osd_left[11:0])
);