NIOS II- Dual_Port RAM IP
在NIOS II 的學習中用到FPGA—NIOS II的信息交互,最常用的方式:FIFO/RAM/Avalon-MM Pipeline Bridge。根據項目需求決定採用Dual_Port RAM進行數據交互。
由於查閱資料並沒有發現有Dual_Port RAM數據交互的詳細步驟,故將自己的步驟記錄下來,供後續研究者參考。
本設計所用芯片爲ALTERA系列中Cyclone IV E:EP4CE10F17C8
1、建立工程,寫入硬件代碼、引腳綁定並編譯。最終的硬件Verilog代碼如下(部分代碼需要在生成Qsys文件之後才能編譯通過):
module SOPC_GHRD_RAM(
input sys_clk, //晶振時鐘,50Mhz
input sys_rst_n, //按鍵復位,低電平有效
input rs232_rx, //RS232數據輸入
output rs232_tx //RS232數據輸出
);
//wire define
wire clk_50m;
wire clk_100m; //Qsys系統時鐘,100Mhz
wire clk_100m_shift;
wire pll_locked;
wire rst_n;
assign rst_n = sys_rst_n & pll_locked ;
//例化pll IP核
pll_clk u_pll(
.inclk0 (sys_clk ),
.areset (~sys_rst_n ),
.c0 (clk_50m ),
.c1 (clk_100m ), //SDRAM 時鐘
.c2 (clk_100m_shift ),
.locked (pll_locked )
);
reg [ 4 : 0] address;
reg [ 31: 0] writedata;
wire write_read;
wire [ 3 : 0] byteenable;
wire [ 31: 0] readdata;
//例化Qsys系統
system_qsys u_ram(
.clk_clk (clk_100m ),
.reset_reset_n (rst_n ),
.dual_port_ram_clk_clk (clk_100m ), // dual_port_ram_clk.clk
.dual_port_ram_reset_reset (rst_n ), // dual_port_ram_reset.reset
.dual_port_ram_reset_reset_req (1'b0 ), // dual_port_ram_s.reset_req
.dual_port_ram_s_address (address ), // dual_port_ram_s.address
.dual_port_ram_s_chipselect (1'b1 ), // dual_port_ram_s.chipselect
.dual_port_ram_s_clken (1'b1 ), // dual_port_ram_s.clken
.dual_port_ram_s_write (write_read ), // 1 write 0 read
.dual_port_ram_s_readdata (readdata ), // dual_port_ram_s.readdata
.dual_port_ram_s_writedata (writedata ), // dual_port_ram_s.writedata
.dual_port_ram_s_byteenable (4'b1111 ) // dual_port_ram_s.byteenable
);
/*---------------------Dual_Port RAM測試代碼---------------------------------*/
wire [7:0] tx_byte; //連線的wire聲明不能缺少
uart_byte_tx uart_byte_tx
(
.clk ( clk_100m ),
.rst_n ( rst_n ),
.rs232_tx ( rs232_tx ),
.tx_en ( 1 ),
.tx_done ( tx_done ),
.tx_byte ( read_data[7:0])
);
/********************************************************************/
wire [ 4:0] read_addr;
reg [31:0] read_data;
always @(posedge clk_100m or negedge rst_n)
begin
if (!rst_n)
begin // reset
writedata <= 32'h256;
address <= 5'h0;
end
else if (writedata == 32'hffff_ffff)
begin
writedata <= 32'h0;
address <= 5'h0;
end
else if (write_read) //write_read寫使能信號有效時數據跳變
begin
writedata <= writedata + 1'b1;
address <= address + 5'h1;
end
else if (!write_read)
begin
case(read_addr)
5'h03: begin address <= read_addr; read_data <= readdata;end
endcase
end
end
assign read_addr = 5'h03;
assign write_read = (writedata < (32'h256+32'h20 ));//存滿32個32bit的數據後write_read拉低
endmodule
NOTE:
有關dual_port_ram_s_byteenable 的參數配置在avalon總線相關手冊中找到:
2、創建Qsys工程,完成連接
Tools —> Qsys,分別添加
NiOS II Processor: Nios II/f
On-Chip Memory(rom): width=32 size=10240bytes
On-Chip Memory(ram): width=32 size=10240bytes
On-Chip Memory(dual_port ram)如下圖所示:
Jtag_uart: 默認
Sysid: 默認
連線,分配地址
雙擊CPU,修改Reset vector和Exception vctor
Generation -> Generate生成工程,保存爲system.qsys
3、完成硬件工程
Hierarchy -> work上右鍵settings,添加NiOS_ii.qsys文件,完成代碼並編譯。之後燒錄板子中。
4、建立軟件工程
Tools -> Nios II Software Build Tools for Eclipse,選擇軟件工作環境爲工程,進入Eclipse工作界面。
File -> New,選第一個,正常建立工程nios_ram_demo。
將hello_world.c文件重命名爲main.c,之後寫入如下代碼
#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include "unistd.h" //延遲函數頭文件
#include "system.h" //系統頭文件
#include "alt_types.h" //數據類型頭文件
int i=0,k=0;
long int data[32];
int main()
{
printf("Hello-Nios-RAM!\n");
for(i=0;i<32*4;i=i+4)
{
data[k] = IORD_32DIRECT(DUAL_PORT_RAM_BASE,i);//從地址位置爲 DUAL_PORT_RAM_BASE+0 的寄存器中直接讀取 32Bit的數據
printf("data_%d=%x\t",k,data[k]);
k = k+1;
}
IOWR_32DIRECT(DUAL_PORT_RAM_BASE, 12, 32); //往地址位置爲 DUAL_PORT_RAM_BASE+8 的寄存器中直接寫入 32Bit 的數據
return 0;
}
5、編譯軟件
在編譯工程之前可以通過配置來減少程序編譯所生成的代碼量:
我們在“Project Explorer”窗口中選中“nios_ram_demo_bsp”工程,然後點擊鼠標右鍵,在彈出的菜單欄中依次選擇【Nios II】→【BSP Editor…】,會出現“Nios II BSP Editor”界面,在界面中做如下改動即可:
最後生成bsp庫—>nios_ram_demo主文檔右鍵—>Bulid Project—>Run —>run as —> Nios II Hardware燒錄。
6、功能驗證
由第一幅圖可知FPGA中寫入的32個數據(0x00000256 ——0x00000275)已經成功傳入NIOS中;第二幅圖說明NIOS寫入的1個數據0x00000020(低八位是0x20)同樣成功傳入。