本次設計源碼地址:http://download.csdn.net/detail/noticeable/9914173
實驗現象:通過串口將數據發送到FPGA 中,通過quartus II 提供的in system memory content editor 工具查看RAM中接收到的數據,當需要是,按下按鍵KEY0,將FPGA 的RAM 中存儲的數據通過串口發送出去。
知識點:
(1)存儲器IP核的使用(2)in system memory content editor 內存查看工具的使用
系統結構框圖如下,如何繪制在http://www.cnblogs.com/noticeable/p/7248404.html可以進行查看
設計過程:復制之前寫的uart工程,打開,添加menmoryIP核
然后直接next,直到finish,此時就可以將IP核添加完畢了。
直接將IP核生成的文件設置為頂層文件,編寫testbench文件對其進行仿真
`timescale 1ns/1ns `define clock_period 20 module dua_ram_tb; reg clock; reg [7:0]data; reg [7:0]rdaddress; reg [7:0]wraddress; reg wren; wire [7:0]q; integer i; dua_ram dua_ram0( .clock(clock), .data(data), .rdaddress(rdaddress), .wraddress(wraddress), .wren(wren), .q(q) );//端口連接 initial clock=1; always#(`clock_period/2)clock=~clock; initial begin data=0; rdaddress=0; wraddress=0; wren=0; #(`clock_period*20+1); for(i=0;i<=15;i=i+1)begin // 寫操作 wren=1; data=255-i; wraddress=i; #(`clock_period); end wren=0; #(`clock_period*20+1);//延遲一段時間后進行讀操作 for(i=0;i<=15;i=i+1)begin // 讀操作 rdaddress=i; #(`clock_period); end #5000; $stop; end endmodule
設置仿真腳本,點擊仿真,進行前仿
仿真完了,可以對雙口RAM有一個基本了解了,下面就將其添加到之前寫的uart工程中
新建一個uart_dpram.v文件,並設置其為頂層文件,代碼按照結構圖進行編輯如下:
module uart_dpram( clk, rst_n, key_in, rs232_rx, rs232_tx); input clk; input rst_n; input key_in; input rs232_rx; //串口讀取端口 output rs232_tx; //串口寫出端口 wire key_flag; //按鍵檢測標志 wire key_state; //按鍵狀態標志 wire rx_done; //讀取完成標志 wire tx_done; //寫出完成標志 wire send_en; //寫出使能 wire [7:0]rdaddress,wraddress; //讀地址和寫地址 wire wren; //寫入使能 wire [7:0]rx_data,tx_data; //待讀取數據與發送數據 uart_tx uart_tx_a( .clk(clk), .rst_n(rst_n), .send_en(send_en), .baud_set(3'd0), .tx_done(tx_done), .rs232_tx(rs232_tx), .data_byte(tx_data), .uart_state() ); uart_rx uart_rx_a( .clk(clk), .rs232_rx(rs232_rx), .baud_set(3'd0), .rst_n(rst_n), .data_byte(rx_data), .rx_done(rx_done) ); key_filter key_filter_a( .clk(clk), .rst_n(rst_n), .key_in(key_in), .key_flag(key_flag), .key_state(key_state) ); dua_ram dua_ram_a( .clock(clk), .data(rx_data), //存儲器入口是讀取的數據 .rdaddress(rdaddress), .wraddress(wraddress), .wren(wren), .q(tx_data) //存儲器的出口是要寫出的數據 );//端口連接 ctrl ctrl_a( .clk(clk), .rst_n(rst_n), .key_flag(key_flag), .key_state(key_state), .rx_done(rx_done), .tx_done(tx_done), .rdaddress(rdaddress), .wraddress(wraddress), .wren(wren), .send_en(send_en) ); endmodule
如代碼中所說,ctrl模塊沒有定義,編譯肯定是會報錯的,下面繼續編寫ctrl 模塊,新建一個ctrl.v文件,編輯如下:
module ctrl( clk, rst_n, key_flag, key_state, rx_done, tx_done, rdaddress, wraddress, wren, send_en );//控制模塊 input clk; input rst_n; input key_flag; input key_state; input rx_done; input tx_done; output reg[7:0]rdaddress; output reg[7:0]wraddress; output wren; //寫入使能信號 output reg send_en; //發送使能 assign wren=rx_done; //讀取完成的信號即可以寫入了 reg do_send; //發送標志 reg r0_send_done,r1_send_done; //發送緩沖寄存器 always@(posedge clk or negedge rst_n)//寫地址 if(!rst_n) wraddress<=8'd0; else if(rx_done) //每讀取完一次,寫入地址+1 wraddress<=wraddress+8'd1; else wraddress<=wraddress; always@(posedge clk or negedge rst_n) if(!rst_n) do_send<=0; else if(key_flag&&!key_state) //如果按鍵按下一次,發送狀態改變一次 do_send<=~do_send; always@(posedge clk or negedge rst_n)//讀地址 if(!rst_n) rdaddress<=8'd0; else if(do_send&&tx_done) //發送狀態為發送,且1byte數據已經發送完成了,則讀地址+1 rdaddress<=rdaddress+8'd1; always@(posedge clk or negedge rst_n)///ram讀有兩拍的延遲,所以加兩級寄存器對發送使能進行緩存 if(!rst_n) begin r0_send_done<=1'b0; r1_send_done<=1'b0; end else begin r0_send_done<=(do_send&&tx_done); r1_send_done<=r0_send_done; end always@(posedge clk or negedge rst_n)//發送使能 if(!rst_n) send_en<=0; else if(key_flag&&!key_state) send_en<=1'b1; else if(r1_send_done) send_en<=1; else send_en<=0; endmodule
編寫testbench文件進行仿真,將test9中的keymodule 復制到本工程的testbench文件夾下,並添加到工程中
`timescale 1ns/1ns `define clock_period 20 module uart_dpram_tb; reg clk; reg rst_n; wire key_in; wire rs232_rx; wire rs232_tx; wire tx_done; reg [7:0]data_byte_t; reg send_en; wire [2:0]baud_set; reg press; assign baud_set = 3'd0; uart_dpram uart_dpram_1( .clk(clk), .rst_n(rst_n), .key_in(rst_n), .rs232_rx(rs232_rx), .rs232_tx(rs232_tx)); uart_tx uart_tx1( .clk(clk), .rst_n(rst_n), .send_en(send_en), .baud_set(baud_set), .tx_done(tx_done), .rs232_tx(rs232_rx), .data_byte(data_byte_t), .uart_state() ); key_module key_module1( .press(press), .key(key_in) ); initial clk=1; always#(`clock_period/2) clk=~clk; //發送數據 initial begin rst_n = 1'b0; press = 0; data_byte_t = 8'd0; send_en = 1'd0; #(`clock_period*20+1) rst_n=1'b1; #(`clock_period*50+1) data_byte_t<=8'haa; send_en<=1'd1; #(`clock_period) send_en<=1'd0; @(posedge tx_done)//等待傳輸完成的上升沿 #(`clock_period*500)//重新發送 data_byte_t<=8'h55; send_en<=1'd1; #(`clock_period) send_en<=1'd0; @(posedge tx_done)//等待傳輸完成的上升沿 #(`clock_period*500)//重新發送 data_byte_t<=8'hcc; send_en<=1'd1; #(`clock_period) send_en<=1'd0; @(posedge tx_done)//等待傳輸完成的上升沿 #(`clock_period*500)//重新發送 data_byte_t<=8'hff; send_en<=1'd1; #(`clock_period) send_en<=1'd0; //按下按鍵讀取發送出去的內容 @(posedge tx_done) #(`clock_period*5000); press = 1; #(`clock_period*3) press = 0; #(`clock_period*500000); end endmodule
添加路徑如下:
點擊仿真,仿真結果如下
引腳配置,燒寫程序,進行扳級驗證,這里GPIO0_D0連接到USB_TTL的TXD,GPIO0_D1連接到USB_TTL 的RXD即可。
打開串口調試軟件,連接USB-TTL模塊,發送數據,按下按鍵KEY_1,FPGA不斷把剛才發到ram中的數據讀取出來,再按一下,停止發送,效果圖如下所示