FPGA-串口接收圖像寫入RAM并讀出在TFT顯示屏上顯示

系統框圖:

需要用到的模塊有:

1,UART_RX(串口接收模塊);

2,串口接受的數據存放到RAM模塊;

3,RAM IP核;

4,時鐘IP核 (TFT顯示屏驅動時鐘的產生);

5,TFT顯示驅動模塊;

1,UART_RX(串口接收模塊)

具體構建方式及詳見(其中的串口接收部分)

FPGA-UART串口icon-default.png?t=N7T8https://blog.csdn.net/weixin_46897065/article/details/135586405?spm=1001.2014.3001.5502

2,串口接受的數據存放到RAM模塊

串口接受的數據存放到RAM的邏輯時序圖如下:

然后編輯控制器邏輯代碼:

module img_rx_wr(Clk        ,Reset_n    ,rx_data    ,rx_done    ,ram_wren   ,ram_eraddr ,ram_wrdata ,led        );input                  Clk        ;input                  Reset_n    ;input        [7:0]     rx_data    ;input                  rx_done    ;output reg             ram_wren   ;output reg  [15:0]     ram_eraddr ;output      [15:0]     ram_wrdata ;output reg             led        ;reg[16:0]data_cnt;    //統計串口接收數據個數計數器always@(posedge Clk or negedge Reset_n)if(!Reset_n)data_cnt <= 0;else if(rx_done)data_cnt <= data_cnt + 1'd1;reg [15:0]rx_data_temp; always@(posedge Clk or negedge Reset_n)if(!Reset_n)rx_data_temp <= 1'b0;else if(rx_done)rx_data_temp <= {rx_data_temp[7:0],rx_data};always@(posedge Clk or negedge Reset_n)if(!Reset_n)ram_wren <= 0;else if(rx_done && data_cnt[0])ram_wren <= 1'd1;elseram_wren <= 0;always@(posedge Clk or negedge Reset_n)if(!Reset_n)        ram_eraddr <= 0;else if (rx_done && data_cnt[0])ram_eraddr <= data_cnt[16:1];  // data_cnt/2assign ram_wrdata = rx_data_temp;always@(posedge Clk or negedge Reset_n)if(!Reset_n)led <= 0;else if((rx_done)&&(data_cnt == 131071))led <= ~led ;  
endmodule

測試此邏輯代碼的正確性:

編寫測試文件:

`timescale 1ns / 1ps
module img_rx_wr_tb;reg              Clk        ;reg              Reset_n    ;reg    [7:0]     rx_data    ;reg              rx_done    ;wire             ram_wren   ;wire  [15:0]     ram_eraddr ;wire  [15:0]     ram_wrdata ;wire             led        ;img_rx_wr img_rx_wr(.Clk       (Clk       ) ,.Reset_n   (Reset_n   ) ,.rx_data   (rx_data   ) ,.rx_done   (rx_done   ) ,.ram_wren  (ram_wren  ) ,.ram_eraddr(ram_eraddr) ,.ram_wrdata(ram_wrdata) ,.led       (led       ) );initial Clk =1;always #10 Clk = ~Clk;initial beginReset_n = 0;rx_data = 0;rx_done = 0;#201;Reset_n = 1;#2000;rx_data = 8'd255;repeat(131072)beginrx_done = 1;#20;rx_done = 0;#200;rx_data = rx_data - 1;end#2000000;repeat(131072)beginrx_done = 1;#20;rx_done = 0;#200;rx_data = rx_data - 1;end$stop;endendmodule

仿真波形如下:

寫入第一個數據時:

寫入最后一個數據時:

RAM寫邏輯已經完成,接下來完成RAM的讀邏輯。

3,構建RAM IP核

具體構建方式及其內部參數詳見FPGA-學會使用vivado中的存儲器資源RAM(IP核)icon-default.png?t=N7T8https://blog.csdn.net/weixin_46897065/article/details/136325283?spm=1001.2014.3001.5502

4,TFT顯示屏驅動時鐘產生

具體構建方式詳見:

FPGA-時鐘管理單元icon-default.png?t=N7T8https://blog.csdn.net/weixin_46897065/article/details/136356331?spm=1001.2014.3001.5502

5,TFT顯示驅動模塊

具體原理詳見

FPGA- RGB_TFT顯示屏原理及驅動邏輯icon-default.png?t=N7T8https://blog.csdn.net/weixin_46897065/article/details/136401589?spm=1001.2014.3001.5502? ? ? 以及FPGA-VGA成像原理與時序icon-default.png?t=N7T8https://blog.csdn.net/weixin_46897065/article/details/136386813?spm=1001.2014.3001.5502

在以上鏈接中介紹的TFT顯示邏輯其中使用的組合邏輯,為了使得整體得到更好的時序性(RAM得出地址后數據輸出是有延遲時,后面使用時為了確保數據一個都不丟,進行時序對齊)將鏈接中的邏輯代碼重新設計,如下:

`include "disp_parameter_cfg.v" 
//800x480
//H_Right_Borde = 0      V_Bottom_Bord   =  8
//H_Front_Porch = 40     V_Front_Porch   =  2
//H_Sync_Time   = 128    V_Sync_Time     =  2
//H_Back_Porch  = 88     V_Back_Porch    =  25
//H_Left_Border = 0      V_Top_Border    =  8
//H_Data_Time   = 800    V_Data_Time     =  480
//H_Total_Time  = 1056   V_Total_Time    =  525module TFT_Ctrl(Clk_33M   ,Reset_n   ,Data_in   ,Data_req  ,hcount    ,   //行掃描位置(顯示圖像行掃描地址)vcount    ,   //場掃描位置(顯示圖像場掃描地址)TFT_HS    ,   //行同步信號TFT_VS    ,   //場同步信號TFT_DE   ,   //有效數據輸出 TFT_CLK   ,   TFT_DATA ,     //紅綠藍三色 分別8位量化 R[7:0]G[7:0]B[7:0]  TFT_BL);input                Clk_33M;input                Reset_n;input   [15:0]       Data_in;output  reg          Data_req;output  reg [11:0]   hcount;output  reg [11:0]   vcount;output               TFT_HS;output               TFT_VS;output               TFT_DE;output               TFT_CLK;output  reg [15:0]   TFT_DATA;  //紅綠藍三色 分別8位量化 R[7:0]G[7:0]B[7:0]  output               TFT_BL;
//    parameter  VGA_HS_end = 11'd127  ,
//                hdat_begin = 11'd216  ,
//                hdat_end   = 11'd1016 ,
//                hpixel_end = 11'd1055 ,
//                VGA_VS_end = 11'd1    , 
//                vdat_begin = 11'd35   ,
//                vdat_end   = 11'd515  ,
//                vline_end  = 11'd524  ;parameter TFT_HS_end = `H_Sync_Time-1  ;parameter hdat_begin = `H_Sync_Time + `H_Back_Porch +`H_Left_Border - 1'b1;parameter hdat_end = `H_Total_Time - `H_Right_Border -`H_Front_Porch - 1'b1;parameter vdat_begin = `V_Sync_Time + `V_Back_Porch +`V_Top_Border - 1'b1;parameter vdat_end = `V_Total_Time - `V_Bottom_Border -`V_Front_Porch - 1'b1;    parameter hpixel_end = `H_Total_Time -1 ;parameter TFT_VS_end = `V_Sync_Time-1  ;     parameter vline_end  = `V_Total_Time -1 ; reg [11:0] hcount_r;reg [11:0] vcount_r;always@(posedge Clk_33M or negedge Reset_n)if(!Reset_n)hcount_r <= 11'd0; else if(hcount_r == hpixel_end )hcount_r <= 11'd0;elsehcount_r <= hcount_r + 1'd1;always@(posedge Clk_33M or negedge Reset_n)if(!Reset_n)vcount_r <= 11'd0; else if(hcount_r == hpixel_end) if(vcount_r == vline_end )vcount_r <= 11'd0;elsevcount_r <= vcount_r + 1'd1;elsevcount_r <= vcount_r;always@(posedge Clk_33M)Data_req <= ((hcount_r >= hdat_begin) && (hcount_r < hdat_end)&&(vcount_r >= vdat_begin) && (vcount_r < vdat_end)) ? 1'b1 : 1'b0; reg [3:0]TFT_DE_r; always@(posedge Clk_33M) beginTFT_DE_r[0] <= Data_req;TFT_DE_r[3:1] <= TFT_DE_r[2:0];endassign  TFT_DE = TFT_DE_r[2];    
//    assign  TFT_DE   =  ((hcount_r >= hdat_begin) && (hcount_r < hdat_end)&&
//                         (vcount_r >= vdat_begin) && (vcount_r < vdat_end)) ? 1'b1 : 1'b0;  always@(posedge Clk_33M) beginhcount <= Data_req ? (hcount_r - hdat_begin) : 10'd0;vcount <= Data_req ? (vcount_r - vdat_begin) : vcount;end
//    assign  hcount   =   TFT_DE ? (hcount_r - hdat_begin) : 10'd0;  
//    assign  vcount   =   TFT_DE ? (vcount_r - vdat_begin) : 10'd0;  reg [3:0]TFT_HS_r; always@(posedge Clk_33M) beginTFT_HS_r[0] <= (hcount_r > TFT_HS_end)? 1'b1 :1'b0; TFT_HS_r[3:1] <= TFT_HS_r[2:0];end  assign  TFT_HS = TFT_HS_r[2];      
//    assign  TFT_HS   =  (hcount_r > TFT_HS_end)? 1'b1 :1'b0;reg [3:0]TFT_VS_r; always@(posedge Clk_33M) beginTFT_VS_r[0] <= (vcount_r > TFT_VS_end)? 1'b1 :1'b0; TFT_VS_r[3:1] <= TFT_VS_r[2:0];end  assign  TFT_VS  = TFT_VS_r[2];   
//    assign  TFT_VS   =  (vcount_r > TFT_VS_end)? 1'b1 :1'b0; always@(posedge Clk_33M) beginTFT_DATA <=  (TFT_DE) ? Data_in : 16'h0000;    end
//    assign  TFT_DATA =  (TFT_DE) ? Data_in : 24'h000000;assign  TFT_CLK  =  ~Clk_33M;assign  TFT_BL = 1;endmodule

6,頂層模塊

將以上5個小模塊設計好后,根據以下系統框圖設計頂層模塊。

代碼如下:

`timescale 1ns / 1ps
module UART_RAM_TFT(Clk, Reset_n,uart_rx,TFT_RGB,   //TFT數據輸出TFT_HS,   // TFT行同步信號TFT_VS,   //TFT場同步信號TFT_DE,   //TFT數據有效信號TFT_CLK,TFT_BL,   //TFT背光led);input  Clk; input  Reset_n;input  uart_rx;output [15:0]TFT_RGB;output TFT_HS;output TFT_VS;output TFT_DE;output TFT_CLK;output TFT_BL;output led;//    assign TFT_BL = 1;reg     [15:0]   ram_rdaddr ;wire    [15:0]   ram_rdata  ;wire    [7:0]    rx_data    ;wire             rx_done    ;wire             ram_wren   ;wire  [15:0]     ram_eraddr ;wire  [15:0]     ram_wrdata ;wire             led        ;   wire             clk_TFT    ;
//    wire             locked     ;MMCM MMCM(// Clock out ports.clk_out1(clk_TFT),     // output clk_out1// Status and control signals.reset(!Reset_n), // input reset// Clock in ports.clk_in1(Clk));  img_rx_wr img_rx_wr(.Clk       (Clk       ) ,.Reset_n   (Reset_n   ) ,.rx_data   (rx_data   ) ,.rx_done   (rx_done   ) ,.ram_wren  (ram_wren  ) ,.ram_eraddr(ram_eraddr) ,.ram_wrdata(ram_wrdata) ,.led       (led       ) );uart_byte_rx uart_byte_rx(.Clk     (Clk    )    ,.Reset_n (Reset_n)    ,.uart_rx (uart_rx)    ,.Baud_Set(2      )    ,.Data    (rx_data)    ,.Rx_done (rx_done)); RAM RAM (.clka(Clk),    // input wire clka.ena(1),      // input wire ena.wea(ram_wren),      // input wire [0 : 0] wea.addra(ram_eraddr),  // input wire [15 : 0] addra.dina(ram_wrdata),    // input wire [15 : 0] dina.clkb(clk_TFT),    // input wire clkb.enb(1),      // input wire enb.addrb(ram_rdaddr),  // input wire [15 : 0] addrb.doutb(ram_rdata )  // output wire [15 : 0] doutb); wire ram_data_en;wire Data_req;//RAM中存儲的數據時256*256的像素矩陣always@(posedge clk_TFT or negedge Reset_n)if(!Reset_n)ram_rdaddr <= 0;else if(ram_data_en)ram_rdaddr <= ram_rdaddr + 1'd1;wire [11:0]h_count,v_count;wire [15:0]dis_data;assign ram_data_en = Data_req && (h_count >= 272 && h_count < 528) && (v_count >= 112 && v_count < 368);assign dis_data = ram_data_en ? ram_rdata: 0;TFT_Ctrl TFT_Ctrl(.Clk_33M (clk_TFT)  ,.Reset_n (Reset_n)  ,.Data_in (dis_data)  ,.Data_req(Data_req)  ,.hcount  (h_count)  ,   //行掃描位置(顯示圖像行掃描地址).vcount  (v_count)  ,   //場掃描位置(顯示圖像場掃描地址).TFT_HS  (TFT_HS  )  ,   //行同步信號.TFT_VS  (TFT_VS  )  ,   //場同步信號.TFT_DE  (TFT_DE  ) ,   //有效數據輸出 .TFT_CLK (TFT_CLK )  ,   .TFT_DATA(TFT_RGB) ,     //紅綠藍三色 分別8位量化 R[7:0]G[7:0]B[7:0]  .TFT_BL  (TFT_BL  ));      
endmodule

為了仿真驗證邏輯代碼的準確性,我們可以在RAM中提前寫入一張256*256大小的圖片數據,如下圖:

然后編寫測試代碼,驗證邏輯的正確性:

測試代碼如下:

`timescale 1ns / 1ps
module UART_RAM_TFT_TB();reg   Clk; reg   Reset_n;reg   uart_rx;wire [15:0]TFT_RGB;wire TFT_HS;wire TFT_VS;wire TFT_DE;wire TFT_CLK;wire TFT_BL;wire led;UART_RAM_TFT UART_RAM_TFT(.Clk    (Clk    ) , .Reset_n(Reset_n) ,.uart_rx(uart_rx) ,.TFT_RGB(TFT_RGB) ,   //TFT數據輸出.TFT_HS (TFT_HS ) ,   // TFT行同步信號.TFT_VS (TFT_VS ) ,   //TFT場同步信號.TFT_DE (TFT_DE ) ,   //TFT數據有效信號.TFT_CLK(TFT_CLK) ,.TFT_BL (TFT_BL ) ,   //TFT背光.led    (led    ));   initial Clk = 1;always #10 Clk = ~Clk;initial beginReset_n = 0;#201;Reset_n = 1;#2000;#20000000;$stop;end
endmodule

仿真波形如下:

TFT顯示屏開始接收的數據波形圖:

TFT顯示屏最后接收的數據波形圖:

7,總結

在本博客中實現了串口接收圖像寫入RAM并讀出在TFT顯示屏上顯示的這樣一個實驗。這個實驗中使用的時FPGA中片內RAM,所以只能顯示一個256*256大小的圖片。如果能夠將存儲器的容量擴大,比如DDR4存儲器,那這個時候就可以用串口傳輸一整幅圖像,就可以將完整圖片顯示在整個顯示屏上去。再其次把串口接收到的數據改為攝像頭采集到的實時的數據流,那就可以做一個攝像采集頭圖像,存儲,實時顯示的應用。再者,對采集到的圖像數據。進行一定的各種濾波算法,檢測算法等等,就可以實現圖像處理功能。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/718120.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/718120.shtml
英文地址,請注明出處:http://en.pswp.cn/news/718120.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

kafka同步副本集及關鍵參數

上篇文章講了副本機制是什么&#xff0c;一文讀懂kafka內部怎么運行的-CSDN博客 這里深挖下同步副本集及里面的關鍵參數。副本會去leader副本拉去數據追加到自己日志中。 我們知道kafka副本的作用是提高系統的高可用。當leader副本掛了時&#xff0c;會從候選副本集中選者一個當…

java-冪等性

冪等性 1.1冪等性定義&#xff1a; 在計算機領域中&#xff0c;冪等&#xff08;Idempotence&#xff09;是指任意一個操作的多次執行總是能獲得相同的結果&#xff0c;不會對系統狀態產生額外影響。在Java后端開發中&#xff0c;冪等性的實現通常通過確保方法或服務調用的結…

設計模式(十四)中介者模式

請直接看原文: 原文鏈接:設計模式&#xff08;十四&#xff09;中介者模式_設計模式之中介模式-CSDN博客 -------------------------------------------------------------------------------------------------------------------------------- 前言 寫了很多篇設計模式的…

Ribbon實現Cloud負載均衡

安裝Zookeeper要先安裝JDK環境 解壓 tar -zxvf /usr/local/develop/jdk-8u191-linux-x64.tar.gz -C /usr/local/develop 配置JAVA_HOME vim /etc/profile export JAVA_HOME/usr/local/develop/jdk1.8.0_191 export PATH$JAVA_HOME/bin:$PATH export CLASSPATH.:$JAVA_HOM…

npm install 一直在等待sill idealTree buildDeps

最近在整vue的前端項目&#xff0c;npm install的時候一直在等待&#xff0c;記錄下處理過程。 1.檢查當前npm鏡像的地址 輸入命令&#xff1a;"npm config get registry"&#xff0c;如果結果是"https://registry.npmjs.org/"。 更換下地址&#xff0c…

Windows Server 各版本搭建文件服務器實現共享文件(03~19)

一、Windows Server 2003 打開服務器&#xff0c;點擊左下角開始?管理工具?管理您的服務器?添加或刪除角色 點擊下一步等待測試 勾選自定義配置&#xff0c;點擊下一步 選擇文件服務器&#xff0c;點擊下一步 勾選設置默認磁盤空間&#xff0c;數據自己更改&#xff0c;最…

【JavaEE】_Spring MVC 項目傳參問題

目錄 1. 傳遞單個參數 1.1 關于參數名的問題 2. 傳遞多個參數 2.1 關于參數順序的問題 2.2 關于基本類型與包裝類的問題 3. 使用對象傳參 4. 后端參數重命名問題 4.1 關于RequestPara注解 1. 傳遞單個參數 現創建Spring MVC項目&#xff0c;.java文件內容如下&#xff…

2024年3月計劃

根據規劃&#xff0c;為了要考慮把產品代碼吃透。先對于計算幾何&#xff0c;圖像處理&#xff0c;測量學基礎進行 當然&#xff0c;也要把ue繼續進行著。ue的rpg和底層渲染。收集下虛幻商城的免費資源&#xff0c;萬一以后做獨立游戲用得到。其他的可以暫時不進行。因為ue的工…

Apache Flink連載(三十七):Flink基于Kubernetes部署(7)-Kubernetes 集群搭建-3

?? 個人主頁:IT貧道-CSDN博客 ?? 私聊博主:私聊博主加WX好友,獲取更多資料哦~ ?? 博主個人B棧地址:豹哥教你學編程的個人空間-豹哥教你學編程個人主頁-嗶哩嗶哩視頻 目錄

AI-數學-高中-32-概率-樣本空間與隨機事件

原作者視頻&#xff1a;【概率】【一數辭典】1樣本空間與隨機事件_嗶哩嗶哩_bilibili 1.隨機試驗&#xff1a; 2.樣本點、樣本空間、有限樣本空間&#xff1a; 示例1 示例2 3.事件&#xff1a; 示例&#xff1a;

PAT基礎練習

本題要求你寫個程序把給定的符號打印成沙漏的形狀。例如給定17個“*”&#xff0c;要求按下列格式打印 ************ *****所謂“沙漏形狀”&#xff0c;是指每行輸出奇數個符號&#xff1b;各行符號中心對齊&#xff1b;相鄰兩行符號數差2&#xff1b;符號數先從大到小順序遞減…

自己本地模擬內存數據庫增刪改查

目錄 學習初衷準備代碼實現結果感謝閱讀 學習初衷 用于滿足自己的測試要求&#xff0c;不連接數據庫&#xff0c;也不在意數據丟失 準備 maven依賴 org.springframework.boot spring-boot-starter-test test 代碼實現 內存數據庫&#xff08;InMemoryDatabase&#xff0…

[AutoSar]BSW_Com08 CAN driver 模塊介紹及參數配置說明 (二)

目錄 關鍵詞平臺說明一、CanControllers二、CanTxProcessing三、CanFilterMask四、CanHardwareObjects五、CanGeneral 關鍵詞 嵌入式、C語言、autosar、OS、BSW 平臺說明 項目ValueOSautosar OSautosar廠商vector &#xff0c;芯片廠商TI 英飛凌編程語言C&#xff0c;C編譯器…

游戲引擎分層簡介

游戲引擎分層架構&#xff08;自上而下&#xff09; 工具層&#xff08;Tool Layer&#xff09; 在一個現代游戲引擎中&#xff0c;我們最先看到的可能不是復雜的代碼&#xff0c;而是各種各樣的編輯器&#xff0c;利用這些編輯器&#xff0c;我們可以制作設計關卡、角色、動畫…

數據類型和變量

1.數據類型 在Java中數據類型主要分為兩類&#xff1a;基本數據類型和引用數據類型。 基本數據類型有四類八種&#xff1a; 1. 四類&#xff1a;整型、浮點型、字符型以及布爾型 2.八種&#xff1a; 整形是分為如上四種 byte short int long 浮點型分為 float 和double …

Docker Compose系列--搭建halo與mysql

原文網址&#xff1a;使用Docker Compose系列--搭建halo與mysql_IT利刃出鞘的博客-CSDN博客 簡介 說明 本文介紹如何使用Docker Compose搭建halo與mysql。 官網網址 使用 Docker 部署 Halo 和 MySQL | Halo Documents Docker Compose搭建mysql 見&#xff1a;Docker Com…

【大廠AI課學習筆記NO.64】機器學習開發框架

機器學習開發框架本質上是一種編程庫或工具&#xff0c;目的是能夠讓開發人員更容易、更快速地構建機器學習模型。 機器學習開發框架封裝了大量的可重用代碼&#xff0c;可以直接調用&#xff0c;目的是避免“重復造輪子’大幅降低開發人員的開發難度&#xff0c;提高開發效率…

軟考高級:候選碼、主碼、全碼、外碼、主屬性、主鍵、主關鍵字、非主屬性概念和例題

一、AI 講解 候選碼、主碼、全碼、外碼、主屬性、主鍵、主關鍵字、非主屬性是數據庫設計和數據建模中的基本概念&#xff0c;特別是在關系數據庫模型中。下面將對這些概念進行簡單講解&#xff0c;并給出相應的例子。 概念講解 候選碼&#xff08;Candidate Key&#xff09;…

Spring框架精髓:帶你手寫IoC

個人名片&#xff1a; &#x1f43c;作者簡介&#xff1a;一名大三在校生&#xff0c;喜歡AI編程&#x1f38b; &#x1f43b;???個人主頁&#x1f947;&#xff1a;落798. &#x1f43c;個人WeChat&#xff1a;hmmwx53 &#x1f54a;?系列專欄&#xff1a;&#x1f5bc;?…

足球青訓俱樂部|基于Springboot的足球青訓俱樂部管理系統設計與實現(源碼+數據庫+文檔)

足球青訓俱樂部管理系統目錄 目錄 基于Springboot的足球青訓俱樂部管理系統設計與實現 一、前言 二、系統設計 1、系統架構設計 三、系統功能設計 1、管理員登錄界面 2、公告信息管理界面 3、學員管理界面 4、商品信息管理界面 5、課程安排管理界面 四、數據庫設計…