ZYNQ基於DMA的串口傳圖

来源:https://www.cnblogs.com/Lclone/archive/2023/03/17/17226244.html
-Advertisement-
Play Games

小梅哥的這個ZYNQ開發板上的DDR3位於PS側,PL側想要使用DDR3作為緩存的話,得通過HP介面來與PS側的DDR3控制進行通信。 本次實驗在小梅哥OV5640工程的基礎上,通過修改VDMA的S2MM端的模塊而來的。 將VMDA的幀緩存區設為1,關閉幀同步的功能後,其實和DMA差不多。 一、需要 ...


小梅哥的這個ZYNQ開發板上的DDR3位於PS側,PL側想要使用DDR3作為緩存的話,得通過HP介面來與PS側的DDR3控制進行通信。
image
本次實驗在小梅哥OV5640工程的基礎上,通過修改VDMA的S2MM端的模塊而來的。
將VMDA的幀緩存區設為1,關閉幀同步的功能後,其實和DMA差不多。

一、需要自定義的ip核

這裡列出的為自己寫的IP核。小梅哥的工程里還用到了其它的自定義的IP核,這裡就不列出了。

1、串口接收圖像數據模塊

該模塊調用了之前寫的串口8位接收模塊,詳情可點擊查看。
此外,本模塊還調用16位寬、深度為1024的帶數據計數的普通FIFO核
該模塊主要的思想就是將接收到的兩個8位的數據拼接位1個16位的數據並存入FIFO中,
當存入的數據達到LINE_LENGTH(800)的時候,在收到從介面的準備信號時一次性寫入VMDA中,再通過VMDA將數據寫到DDR3中。
此外該模塊在應用的時候要封裝成帶AXI4_Stream 介面的IP核,具體封裝過程可網上找教程。

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: GDUT
// Engineer: Lclone
// 
// Create Date: 2023/02/07 20:38:34
// Design Name: 
// Module Name: Img_Rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module Img_Rx
#   (parameter RX_BAUD = 115200,
     parameter CLK_FQC = 50_000_000,
     parameter LINE_LENGTH = 800)
    (
     input             Uart_Rx,
     //---------------------------
     input             m_clk,
     input             m_axis_aresetn,
     output     [15:0] m_axis_tdata,
     output reg        m_axis_tlast,
     input             m_axis_tready,
     output reg        m_axis_tvalid
    );
    
    wire [7:0]  Uart_Data;
    wire        Rx_done;
    reg         Rx_done_r;
    reg         Rx_done_cnt;
    
    reg  [15:0] Uart_Data_16;
    
    wire [9:0]  fifo_data_count;
    reg  [9:0]  out_data_count;
    
    reg         m_axis_tvalid_r;
    reg  [18:0] cnt_1ms;
    
    always @(posedge m_clk) Rx_done_r <= Rx_done;
    always @(posedge m_clk) m_axis_tvalid <= m_axis_tvalid_r;
    
    always @(posedge m_clk or negedge m_axis_aresetn) begin
        if(m_axis_aresetn == 0)
            Uart_Data_16 <= 0;
        else if(Rx_done == 1)
            Uart_Data_16 <= {Uart_Data_16[7:0],Uart_Data};
    end
    
    always @(posedge m_clk or negedge m_axis_aresetn) begin
        if(m_axis_aresetn == 0)
            Rx_done_cnt <= 0;
        else if(Rx_done == 1)
            Rx_done_cnt <= Rx_done_cnt + 1'b1;
        else
            Rx_done_cnt <= Rx_done_cnt;
    end
    
    always @(posedge m_clk or negedge m_axis_aresetn) begin
        if(m_axis_aresetn == 0)
            m_axis_tvalid_r <= 0;
        else if(m_axis_tready == 1 & fifo_data_count >= LINE_LENGTH)
            m_axis_tvalid_r <= 1'b1;
        else if(fifo_data_count <= 1)
            m_axis_tvalid_r <= 0;
        else
            m_axis_tvalid_r <= m_axis_tvalid_r;
    end
    
    always @(posedge m_clk or negedge m_axis_aresetn) begin
        if(m_axis_aresetn == 0)
            out_data_count <= 0;
        else if(out_data_count == LINE_LENGTH - 1)
            out_data_count <= 0;
        else if(m_axis_tvalid_r & m_axis_tready)
            out_data_count <= out_data_count + 1'b1;
        else
            out_data_count <= out_data_count;
    end
    
    always @(posedge m_clk or negedge m_axis_aresetn) begin
        if(m_axis_aresetn == 0)
            m_axis_tlast <= 0;
        else if(out_data_count == LINE_LENGTH - 1)
            m_axis_tlast <= 1;
        else
            m_axis_tlast <= 0;
    end
    
   always @(posedge m_clk or negedge m_axis_aresetn) begin
        if(m_axis_aresetn == 0)
            cnt_1ms <= 0;
        else if(cnt_1ms == 500000 - 1)
            cnt_1ms <= 0;
        else
            cnt_1ms <= cnt_1ms + 1'b1;
    end 
    
    uart_byte_rx 
  # (
        .RX_BAUD   (RX_BAUD),
        .CLK_FQC   (CLK_FQC))
    uart_byte_rx_inst
    (
        .Clk        (m_clk),
        .Rst_n      (m_axis_aresetn),
        .Uart_rx    (Uart_Rx),
        .Data       (Uart_Data),
        .Rx_done    (Rx_done)
    );
    
    fifo_generator_0  fifo_generator_0_inst (
        .clk(m_clk),                             // input wire clk
        .srst(~m_axis_aresetn),                  // input wire srst
        .din(Uart_Data_16),                      // input wire [15 : 0] din
        .wr_en(~Rx_done_cnt & Rx_done_r),        // input wire wr_en
        .rd_en(m_axis_tvalid_r & m_axis_tready), // input wire rd_en
        .dout(m_axis_tdata),                     // output wire [15 : 0] dout
        .full(),                                 // output wire full
        .empty(),                                // output wire empty
        .data_count(fifo_data_count)             // output wire [9 : 0] data_count
);
endmodule

2、模塊模擬

(1)模擬激勵

`timescale 1ns / 1ps

module rx_img_test();
    
reg clk_50m;
initial clk_50m <= 1;
always #10 clk_50m <= ~clk_50m;

reg rst_n;
initial begin
    rst_n <= 0;
    #200
    rst_n <= 1;
end
   
wire [15:0] m_axis_tdata;
wire        m_axis_tlast;
wire        m_axis_tready;
wire        m_axis_tvalid;

wire [15:0] out_axis_tdata;
wire        out_axis_tlast;
wire        out_axis_tready;
wire        out_axis_tvalid;

reg         Uart_Rx;
reg  [ 7:0] Uart_Data;

Img_Rx #(
    .RX_BAUD(2_000_000),
    .CLK_FQC(100_000_000),
    .LINE_LENGTH(16)
) 
Img_Rx_inst (
  .Uart_Rx(Uart_Rx),                // input wire Uart_Rx
  .m_clk(clk_50m),                    // input wire m_clk
  .m_axis_aresetn(rst_n),  // input wire m_axis_aresetn
  .m_axis_tdata(m_axis_tdata),      // output wire [15 : 0] m_axis_tdata
  .m_axis_tlast(m_axis_tlast),      // output wire m_axis_tlast
  .m_axis_tready(m_axis_tready),    // input wire m_axis_tready
  .m_axis_tvalid(m_axis_tvalid)    // output wire m_axis_tvalid
);
    
axis_data_fifo_0 axis_data_fifo_0_inst (
  .s_axis_aresetn(rst_n),  // input wire s_axis_aresetn
  .s_axis_aclk(clk_50m),        // input wire s_axis_aclk
  .s_axis_tvalid(m_axis_tvalid),    // input wire s_axis_tvalid
  .s_axis_tready(m_axis_tready),    // output wire s_axis_tready
  .s_axis_tdata(m_axis_tdata),      // input wire [15 : 0] s_axis_tdata
  .s_axis_tlast(m_axis_tlast),      // input wire s_axis_tlast
  .m_axis_tvalid(out_axis_tvalid),    // output wire m_axis_tvalid
  .m_axis_tready(out_axis_tready),    // input wire m_axis_tready
  .m_axis_tdata(out_axis_tdata),      // output wire [15 : 0] m_axis_tdata
  .m_axis_tlast(out_axis_tlast)      // output wire m_axis_tlast
);

initial begin
    Uart_Rx <= 1;
    Uart_Data <= 0;
    #200
    repeat (256) begin
        data_deliver(Uart_Data);
        Uart_Data = Uart_Data + 1;
    end
    $stop;
end

task data_deliver;
        input [7:0]	test_data;
        begin
            Uart_Rx <= 1'b0;
            #1000             
            Uart_Rx <= test_data[0];
            #1000             
            Uart_Rx <= test_data[1];
            #1000           
            Uart_Rx <= test_data[2];
            #1000          
            Uart_Rx <= test_data[3];
            #1000         
            Uart_Rx <= test_data[4];
            #1000          
            Uart_Rx <= test_data[5];
            #1000         
            Uart_Rx <= test_data[6];
            #1000         
            Uart_Rx <= test_data[7];
            #1000           
            Uart_Rx <= 1'b1;
            #1000;
        end
endtask

assign out_axis_tready = 1;

endmodule

(2)模擬結果

image
可見該模塊能夠正確地將16個兩位元組的數據正確的輸出,併在最後一個數據的位置基於一個tlast信號。

二、工程修改

 
打開小梅哥的ACZ7020的OV5640_LCD工程,然後將紅框部分的模塊刪除,加入自定義的串口接收圖像數據模塊。
image
image
 
並修改下列IP核的參數
將頻率修改為如下:
image
 
將幀緩存區設為1
image
 
Fsync Options選擇None,關掉幀同步功能
image
 
在約束文件中,加入串口的管腳約束
image
 
在SDK中,將OV5640的初始化函數刪除,將PS_IIC和OV5640庫刪除
image
 
同時也將PS_IIC和OV5640庫的路徑刪除掉
image
然後就可以下載程式到開發板上了

三、上板驗證

將程式下載進開發板,然後打開img2lcd軟體,讀取一個800*480大小的BMP文件,並按如下設置:
image
然後在輸出的文件中進行修改
刪除首行
image
刪除末尾符號
image
使用軟體的查找替換功能,將所有的0X刪掉,並將","換為空格符,然後使用行操作裡面的行合併去除掉每一行末尾的回車符。最後就得到傳輸的圖像數據:
image
 
打開友善串口調試助手,將圖像數據複製進去,打開串口埠,設置好波特率,然後發送,確保TX發送了768000個位元組,否則圖像會錯位;確保底下綠色的字顯示的波特率為115200,否則數據無法正確傳輸。
image
 
傳輸數據後,發現圖像能夠正確顯示在LCD上
image
實驗成功。
本隨筆還有許多小細節沒有給出,如果遇到問題,可以評論詢問。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 報錯信息 如題, cn.hutool.core.io.IORuntimeException: Not a file.... 報錯位置 FileReader reader = new FileReader(path); 初步分析 檢查下來發現,path實際對應的是一個文件夾,而不是文件。 文件來源關鍵 ...
  • 環境ThinkPHP+Redis 1.IP保存文件,文件名自定義,與後文對應 2.獲取IP信息腳本.sh文件 #!/bin/bash #variables ip_txt_path=/www/wwwroot/checkip/china_ip.txt; ip_url='http://ftp.apnic. ...
  • 需求:爬取豆瓣電影短評評論文本內容 目標:將爬取的文本存入 excel 中 爬蟲步驟: 1.拼接分頁網址,迴圈請求分頁數據,獲取HTML代碼 2.分析獲取到的HTML代碼,解析出所需要的數據,提取內容 3.存儲爬取到的數據 準備工作: 1.開發工具 pycharm 2.模塊 requests、bs4 ...
  • 類載入器 類載入的過程 類載入器的功能 將.class文件【物理文件:在硬碟中】載入到Java虛擬機的記憶體中【搬用工】。 類載入的時機情況分析: //1,當創建Fu對象的時候【Fu.class會被載入到Java虛擬機】 Fu f = new Fu(); //2,調用類的靜態方法【Fu.class會被 ...
  • 本文介紹在Anaconda環境下,安裝Python中的一個高級地理空間數據分析庫whitebox的方法。 首先,我們打開“Anaconda Prompt (Anaconda)”軟體。 隨後,將彈出如下所示的命令輸入視窗。 在上述彈出的命令輸入視窗中,輸入以下代碼: conda install -c ...
  • tar 備忘清單 IT寶庫網整理的關於 tar 常用命令的快速參考備忘單。入門,為開發人員分享快速參考備忘單。 開發速查表大綱 入門 介紹 選項 創建一個 tar 格式的壓縮文件 創建壓縮後的 tar.gz 存檔文件 生成壓縮率更高的 tar.bz2 文件 解壓縮 tar 文件 解壓縮 tar.gz ...
  • 前言 互動直播是實現很多熱門場景的基礎,例如直播帶貨、秀場直播,還有類似抖音的直播 PK等。本文是由聲網社區的開發者“小猿”撰寫的Flutter基礎教程系列中的第二篇,他將帶著大家用一個小時,利用聲網 Flutter SDK 實現視頻直播、發評論、送禮物等基礎功能。 開發一個跨平臺的的直播的功能需要 ...
  • 前後端分離下EasyExcel的使用 項目環境:SpringBoot+Vue 依賴導入 <!--easyexcel--> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...