1.图像转十六进制。
2.串口发送,通过串口接收模块接收。
3.串口接受模块把数据传递给图像处理模块,图像处理模块对图像数据进行“逐行处理”,例如:
FPGA图像处理基础~sobel算子_NoNoUnknow的博客-CSDN博客
当然实现这个操作需要依赖两个FIFO来缓存一行数据,也有其他的方法可以实现。
4.处理好的数据传输到RAM里,RAM可以放在图像显示模块里。
这是因为:串口传图的速度很慢!调到比较快的参数也只有115200比特/秒,只能输入到RAM里,再通过显示协议的时钟需求去读取!
一些工程细节:
1.RAM取出数据的时间是在输入读取地址的1~3个时钟周期以后(需要关注是否配置了寄存器,不配置默认是1),所以我们需要在需要读取数据的前1一个时钟周期去输入读取地址。
2.这里的代码仅仅是“单通道的sobel”,还是那个原因!串口发送速率太慢了!多通道会更复杂!
assign RD_EN = (((H_cnt > (H_Sync + H_backporch + H_left -2'd2) + H_cnt_move))
&& ((H_cnt <= (H_Sync + H_backporch + H_left -2'd2) + H_cnt_move + window))
&& ((V_cnt > (V_Sync + V_backporch + V_left -1'b1) + V_cnt_move))
&& ((V_cnt <= (V_Sync + V_backporch + V_left -1'b1) + V_cnt_move + window)));
这个操作将读取操作放在了显示操作(PIXAL)前,保证了对齐。
同时我把之前的视频输出代码进行了修改:(时序电路改成组合电路)
// always@(posedge Sys_clk or negedge Rst_n) begin
// if(Rst_n == 0) begin
// set_sign <= 0;
// end else if(Pixl_avai) begin
// if((H_addr <= H_cnt_move + window -1'b1)
// && (H_addr >= H_cnt_move)
// && (V_addr <= V_cnt_move + window -1'b1)
// && (V_addr >= V_cnt_move)) begin
// set_sign <= 1'b1;
// end else begin
// set_sign <= 0;
// end
// end else begin
// set_sign <= 0;
// end
// end
assign set_sign = (Pixl_avai)?((((H_addr <= H_cnt_move + window -1'b1)
&& (H_addr >= H_cnt_move)
&& (V_addr <= V_cnt_move + window -1'b1)
&& (V_addr >= V_cnt_move)))
?(1'b1):(1'b0))
:1'b0;
assign rgb = (set_sign)?(RD_DATA):(black);
// always@(posedge Sys_clk or negedge Rst_n) begin
// if(Rst_n == 0) begin
// rgb <= black;
// end else if(set_sign) begin
// rgb <= white;
// end else begin
// rgb <= black;
// end
// end
///
这是为了让“开窗”这个操作能够对准时序,否则会丢失第一行和最后一行的显示。
穿插一些小知识:
FPGA内部的RAM资源分为Block RAM 和分布式 RAM,在调用FIFO,RAM等IP核的时候都可以进行选择,其中Block RAM性能更好,也不需要占用逻辑资源(LUT),但是资源有限,而且总是会调用一整块的RAM,比如存储哪怕一个数据的RAM也需要占用一个9K的BRAM,在这个基础上,我们可以“时分复用”地调用相关的IP核,但也会带来开发上的困难(时钟变复杂了)。
部分代码:
色彩协议:FPGA:参数化的VGA控制器,可用于DVI/HDMI。_NoNoUnknow的博客-CSDN博客
TX&RX:
可参考:串口收发与RAM读写_NoNoUnknow的博客-CSDN博客
下面也是一种实现方法,大同小异,但是参数化了!可以随便改,真好。
module tx_driver#(
parameter Sys_clk_frq = 50_000_000 ,
parameter bot = 115200 ,
parameter div_cnt_max = Sys_clk_frq/bot,
parameter cnt_width = $clog2(div_cnt_max)
)(
input wire Sys_clk ,
input wire Rst_n ,
input wire [7:0] data_in ,
input wire uart_en ,
output reg data_out,
output wire done_flag
);
localparam start_flag = 1'b0;
localparam end_flag = 1'b1;
reg [cnt_width-1:0] div_cnt ;
reg [7:0] r_data_in;
reg [3:0] baud_cnt ;
reg baud_flag;
reg uart_state;
assign done_flag = (baud_flag && baud_cnt == 4'd8)?1'b1:1'b0;
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
r_data_in <= 8'd0;
end else if(uart_en == 1'b1) begin
r_data_in <= data_in;
end else begin
r_data_in <= r_data_in;
end
end
//uart_state
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
uart_state <= 1'b0;
end else if(uart_en == 1'b1) begin
uart_state <= 1'b1;
end else if(done_flag == 1'b1) begin
uart_state <= 1'b0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
div_cnt <= 0;
end else if(uart_state == 1'b1) begin
if(div_cnt == div_cnt_max -1'b1) begin
div_cnt <= 0;
end else begin
div_cnt <= div_cnt + 1'b1;
end
end else begin
div_cnt <= 0;
end
end
//baud_cnt
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
baud_flag <= 1'b0;
end else if(div_cnt == (div_cnt_max -1'b1)) begin
baud_flag <= 1'b1;
end else begin
baud_flag <= 1'b0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
baud_cnt <= 4'd0;
end else if(baud_flag && baud_cnt == 4'd8) begin
baud_cnt <= 4'd0;
end else if(baud_flag) begin
baud_cnt <= baud_cnt + 1'b1;
end else begin
baud_cnt <= baud_cnt;
end
end
//tx
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
data_out <= 1'b1;
end else if(uart_en ) begin
data_out <= 1'b0;
end else if (baud_cnt <= 4'd7 && baud_flag) begin
data_out <= r_data_in[baud_cnt];
end else if(baud_flag && baud_cnt == 4'd8) begin
data_out <= 1'b1;
end else begin
data_out <= data_out;
end
end
endmodule
module rx_teach #(
parameter Sys_clk_frq = 50_000_000,
parameter baud_frq = 115200 ,
parameter div_cnt_max = Sys_clk_frq/baud_frq,
parameter cnt_width = $clog2(div_cnt_max)
)(
input wire Sys_clk,
input wire Rst_n ,
input wire data_in,
output reg [7:0] data_receive,
output reg rx_done
);
reg [cnt_width-1:0] div_cnt;
reg reg_data_A;
reg reg_data_B;
reg uart_state;
reg receive_flag ;
reg [3:0] bit_cnt ;
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
{reg_data_A,reg_data_B} <= 2'b00;
end else begin
{reg_data_A,reg_data_B} <= {data_in,reg_data_A};
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
rx_done <= 1'b0;
end else if(bit_cnt == 4'd8 && receive_flag) begin
rx_done <= 1'b1;
end else begin
rx_done <= 1'b0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
uart_state <= 1'b0;
end else if((!reg_data_A)&&(reg_data_B)) begin
uart_state <= 1'b1;
end else if(rx_done) begin
uart_state <= 1'b0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
div_cnt <= 'd0;
end else if(uart_state == 1'b1) begin
if(div_cnt == div_cnt_max -1'b1) begin
div_cnt <= 'd0;
end else begin
div_cnt <= div_cnt + 1'b1;
end
end else begin
div_cnt <= 'd0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
receive_flag <= 1'b0;
end else if(div_cnt == (div_cnt_max - 1'b1)>>1) begin
receive_flag <= 1'b1;
end else begin
receive_flag <= 1'b0;
end
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
bit_cnt <= 'd0;
end else if(bit_cnt == 4'd8 && receive_flag) begin
bit_cnt <= 'd0;
end else if(receive_flag) begin
bit_cnt <= bit_cnt + 1'b1;
end else
bit_cnt <= bit_cnt;
end
always @(posedge Sys_clk or negedge Rst_n) begin
if(!Rst_n) begin
data_receive <= 8'd0;
end else if(bit_cnt >= 1'b1 && receive_flag) begin
data_receive <= {reg_data_B,data_receive[7:1]};
// case (bit_cnt)
// 4'd0:data_receive <= data_receive;
// 4'd1:data_receive[0] <= reg_data_B;
// 4'd2:data_receive[1] <= reg_data_B;
// 4'd3:data_receive[2] <= reg_data_B;
// 4'd4:data_receive[3] <= reg_data_B;
// 4'd5:data_receive[4] <= reg_data_B;
// 4'd6:data_receive[5] <= reg_data_B;
// 4'd7:data_receive[6] <= reg_data_B;
// 4'd8:data_receive[7] <= reg_data_B;
// default:data_receive <= data_receive;
// endcase
end
end
endmodule