在NIOS II 的学习中用到FPGA—NIOS II的信息交互,最常用的方式:FIFO/RAM/Avalon-MM Pipeline Bridge。根据项目需求决定采用Dual_Port RAM进行数据交互。
由于查阅资料并没有发现有Dual_Port RAM数据交互的详细步骤,故将自己的步骤记录下来,供后续研究者参考。
本设计所用芯片为ALTERA系列中Cyclone IV E:EP4CE10F17C8
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总线相关手册中找到:
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
Hierarchy -> work上右键settings,添加NiOS_ii.qsys文件,完成代码并编译。之后烧录板子中。
Tools -> Nios II Software Build Tools for Eclipse,选择软件工作环境为工程,进入Eclipse工作界面。
File -> New,选第一个,正常建立工程nios_ram_demo。
将hello_world.c文件重命名为main.c,之后写入如下代码
#include
#include
#include
#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;
}
在编译工程之前可以通过配置来减少程序编译所生成的代码量:
我们在“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烧录。
由第一幅图可知FPGA中写入的32个数据(0x00000256 ——0x00000275)已经成功传入NIOS中;第二幅图说明NIOS写入的1个数据0x00000020(低八位是0x20)同样成功传入。