目录
第一部分、搭建自己的系统时的储备知识
1、单片机芯片的组成
我相信开始学FPGA的SOPC技术,我敢赌100块,你以前一定玩过单片机(例如:51、430、32等),既然你有了这些基础那我就好解释了,SOPC技术就是你自己搭建单片机的主控芯片。而我们接触的这些单片机,它的主控芯片又是由:CPU、RAM(运行内存)、ROM(空间内存)、I/O(端口)、UART(串口)、Timer(定时器)、Interrupt(中断)所构成。其中CPU、RAM、ROM这三个最必须也是最重要。其它可以理解成片上外设。
好,既然知道了单片机的结构那把这个思维放到我们这里也一样,我们要搭建一个软核,那么我们也需要添加这些东西到我们的软核中去,只不过在这里的这些东西换了名称而已。
下面三个是我搭建系统时用到的。(注:这里面左边对应到右边不是唯一的哦,比如RAM就有好几种类型)
2、系统的时钟
当然单片机除了主控芯片这个大脑,它还有一个不可缺的就是晶振这颗心脏。说这个的原因是,因为这里面默认的时钟是50MHz,但是有时候我们还嫌弃这个心脏跳的太慢,不能满足我们的需求,所以这里我加入了PLL锁相环将系统时钟倍频到100MHz,让心脏跳到飞起的那种。(关于锁相环是啥,我们不需要知道,只需要知道这个玩意能把50MHz的时钟变成100MHz的时钟)。
第二部分、新建工程
1、注意
前面五篇文章都是基于别人的工程上面修改的,通过修改别人的软核来实现自己想要的目的。这一篇就叫你如何从零搭建属于自己的SOPC系统。
2、新建工程
第一步、新建工程QuartusII工程
第二步、选择FPGA对应的芯片型号,我用的是小梅哥家的AC620。(不吹牛,我的学长做的)
我想这里没有没有什么难点,只要芯片型号选对了,一般不会出现问题。
第三步、给自己的工程添加Verilog HDL File文件
第四步、将Verilog HDL文件保存的名称和工程名一样,如图
第三部分、搭建自己的软核
1、添加(晶振)锁相环IP核配置的详细步骤
第一步、确定自己的时钟,这里我通过锁相环将自己的时钟倍频到100Mhz,关于锁相环的配置如下图
配置锁相环的输入时钟50Mhz
输入所有选项取消勾选,只要一个时钟输入和输出
另外两个窗口默认就可以了
将输出的c0时钟配置为如图一样的参数,频率为100MHz
将输出的c1时钟配置为如图一样的参数,频率为100MHz,时钟相移为-90,别问我,问就是不知道,小梅哥是这么搞得;
注意:我询问老师的时候老师和我说,添加时钟相移是为了防止系统出错,如果时钟和这个同步的话容易出错
其他窗口全部默认就可以了
2、添加(CPU)nios II核的详细步骤
第一步、接着给系统添加CPU(Nios II Processor)
这里面Vectors要等连完线过后,再过来配置
3、添加(RAM)SDRAM核的详细步骤
第一步、接着给系统添加RAM(SDRAM Controller)
将SDRAM配置成128Mbits,位宽是16位,地址宽度位12和9,最后结果位128Mbit
4、添加(ROM)EPCS核的步骤
第一步、接着给系统添加ROM(Legacy EPCS/EPCQx1 Flash Controller),里面的参数配置为默认。
5、连接总线的步骤
第一步、进行连线,连完线锁定ram的起始地址为0x0000_0000
连线的规则为:
1、首先是时钟线(clk),这里面是Pllclk_100M的c0作为输出
2、其次是连接cpu上的复位(reset)线和复位线(clk_reset)
3、接着是连接cpu上数据总线(data_master),
4、最后就是连接cpu上命令总线(instruction_master),命令总线只需要连接ROM和RAM就可以了
注意:这里的名字我都修改了,不是默认的!
6、配置(CPU)nios II的Vectors参数步骤
第一步、接着配置CPU里面的(Reset vector memory和sdram.s1),配置结果如图
7、给软核分配地址的步骤
第一步、首先将sdram后面的地址进行锁定,让sdram的起始地址位0x0000_0000,然后进行自动地址分配assign address,分配完就只会出现4个警告了。
然后按照警告的意思解决问题,
这里注意:为什么c1要导出来,老师的说的是sdram的时钟必须导出来,在外置给sdram的时钟引脚PT10
第四部分、给自己的软核添加添加第一个片上外设(I/O口)
第一步、为了测试自己的系统,首先添加LED外设,测试自己的系统,这里面省略连线、分配地址、导出端口等步骤。
第二步、保存并生成自己的软核系统,并取个名字为mysystem_(你的名字的首字母)例如我起的名称是mysystem_dpt.qsys(dpt代表大屁桃的意思),接着等待3—5分钟生成你的软核。
第三步、将这里面所有的代码全部复制出去,作为例化模块代码
注意:如果你嫌麻烦,可以直接复制我下面的代码,但是注意名称对应。
第五部分、编写Quartus中的verilog代码
第一步、首先将生成的qsys文件添加你工程的file文件夹中,添加方法按照图中序号的顺序操作!!!
添加成功后
第二步、接着编写顶层代码,并进行预编译,注意!注意!注意:这里顶层模块的名字一定要和你的文件名一致,例化模块的名字和你软核系统的名字一致。
module myself_sopc/*注意这里的名字,你的文件名如果和我不一样要记得改*/(
/*时钟*/
input wire clk, // clk.clk
/*复位*/
input wire reset_n, // reset.reset_n
/*RAM*/
output wire sdram_clk, // sdram_clk.clk
output wire [11:0] sdram_addr, // sdram.addr
output wire [1:0] sdram_ba, // .ba
output wire sdram_cas_n, // .cas_n
output wire sdram_cke, // .cke
output wire sdram_cs_n, // .cs_n
inout wire [15:0] sdram_dq, // .dq
output wire [1:0] sdram_dqm, // .dqm
output wire sdram_ras_n, // .ras_n
output wire sdram_we_n, // .we_n
/*ROM*/
output wire epcs_rom_dclk, // epcs.dclk
output wire epcs_rom_sce, // .sce
output wire epcs_rom_sdo, // .sdo
input wire epcs_rom_data0,
/*外设*/
output wire [3:0] led
);
mysystem_dpt/*注意这里的名字,要和你软核系统的名字对应*/ u0 (
.clk_clk (clk), // clk.clk
.reset_reset_n (reset_n), // reset.reset_n
.epcs_rom_dclk (epcs_rom_dclk), // epcs_rom.dclk
.epcs_rom_sce (epcs_rom_sce), // .sce
.epcs_rom_sdo (epcs_rom_sdo), // .sdo
.epcs_rom_data0 (epcs_rom_data0), // .data0
.sdram_addr (sdram_addr), // sdram.addr
.sdram_ba (sdram_ba), // .ba
.sdram_cas_n (sdram_cas_n), // .cas_n
.sdram_cke (sdram_cke), // .cke
.sdram_cs_n (sdram_cs_n), // .cs_n
.sdram_dq (sdram_dq), // .dq
.sdram_dqm (sdram_dqm), // .dqm
.sdram_ras_n (sdram_ras_n), // .ras_n
.sdram_we_n (sdram_we_n), // .we_n
.sdram_clk_clk (sdram_clk), // sdram_clk.clk
.led_export (led) // led.export
);
endmodule
第三步、预编译完成后分配引脚,这个照着小梅哥之前的工程进行复制就可以了,或者你们前面做的工程,但是善良的我,还是把我这块小梅哥家的AC620引脚分配表放了上来,
注意:如果你的FPGA和我的一样,那你就可以直接复制。不是的话,自己慢慢搞。我赌,你的FPGA型号如果和我的不一样,你也不会看到这里!!!
当然如果你不是这个型号的单片机也没关系,按照你那个单片机的引脚功能表填写,注意引脚被搞错了,然后引脚电压是3.3VTTL。
clk | PIN_E1 |
epcs_rom_data0 | PIN_H2 |
epcs_rom_dclk | PIN_H1 |
epcs_rom_sce | PIN_D2 |
epcs_rom_sdo | PIN_C1 |
led[3] | PIN_A3 |
led[2] | PIN_A4 |
led[1] | PIN_B3 |
led[0] | PIN_A2 |
reset_n | PIN_E16 |
sdram_addr[11] | PIN_R13 |
sdram_addr[10] | PIN_M10 |
sdram_addr[9] | PIN_T14 |
sdram_addr[8] | PIN_R14 |
sdram_addr[7] | PIN_T15 |
sdram_addr[6] | PIN_L11 |
sdram_addr[5] | PIN_M11 |
sdram_addr[4] | PIN_N12 |
sdram_addr[3] | PIN_T13 |
sdram_addr[2] | PIN_P14 |
sdram_addr[1] | PIN_L10 |
sdram_addr[0] | PIN_P11 |
sdram_ba[1] | PIN_M9 |
sdram_ba[0] | PIN_T12 |
sdram_cas_n | PIN_R11 |
sdram_cke | PIN_T11 |
sdram_clk | PIN_T10 |
sdram_cs_n | PIN_R12 |
sdram_dq[15] | PIN_P9 |
sdram_dq[14] | PIN_N8 |
sdram_dq[13] | PIN_M8 |
sdram_dq[12] | PIN_L8 |
sdram_dq[11] | PIN_K8 |
sdram_dq[10] | PIN_L9 |
sdram_dq[9] | PIN_K9 |
sdram_dq[8] | PIN_R9 |
sdram_dq[7] | PIN_R8 |
sdram_dq[6] | PIN_R6 |
sdram_dq[5] | PIN_T5 |
sdram_dq[4] | PIN_R5 |
sdram_dq[3] | PIN_T4 |
sdram_dq[2] | PIN_R4 |
sdram_dq[1] | PIN_T3 |
sdram_dq[0] | PIN_R3 |
sdram_dqm[1] | PIN_R10 |
sdram_dqm[0] | PIN_T8 |
sdram_ras_n | PIN_N9 |
sdram_we_n | PIN_T9 |
第四步、注意:接着将所有引脚设置为普通I/O(use as regular i/o),然后再进行全编译。
设置的地方:assignments>device>device and pin options>dual-purpose pins
第五步、自己当前工程的文件夹下面建一个sofeware文件夹。如图,按图中序号顺序操作
第六部分、编写自己ecplise软件中的代码
1、代码功能阐述
让单片机上的4个LED大约每个0.5秒闪烁一次。
2、原码
#include <stdio.h>
#include <system.h>
#include "altera_avalon_pio_regs.h"//PIO读写头文件
#include "unistd.h" //延时函数的头文件
#include "alt_types.h" //数据类型的头文件
alt_u8 x=0;
int main()
{
while(1)
{
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0x00);
usleep(500000);
IOWR_ALTERA_AVALON_PIO_DATA(LED_BASE, 0xff);/*0x0f也可以*/
usleep(500000);
}
}
3、编译、烧录和仿真
如果你忘记了怎么操作,请看以前的文章(【NiosII学习】第一篇、如何烧录NiosII工程:https://blog.youkuaiyun.com/Learning1232/article/details/110225728)。唯一要注意的就是图中的2号哪里,因为我们没有添加JART UART,所以这里没有。
第七部分、总结
1、闲话
如果你跟着操作,而且成功点亮了你开发板上的LED了,那你肯定会很爽,但是到这里,你就要想我自己都能搭建软核了,那我岂不是想怎么玩就怎么玩了。例如我可以把之前学的(按键、串口、定时器)这些都加入到自己的系统中,然后做一个小的工程。
比如:通过按下不同的按键控制LED闪烁的时间不同(按下key0,LED亮1s灭1s,周期为2s;按下key1,LED亮3s灭3s,周期为6s),控制时间用定时器搞,同时串口还把你LED的闪烁得周期发送到串口助手上。
还有,有问题的老铁可以加群询问,没问题的可以进去交流,🐶🐶🐶!
2、结果演示
我已经拍成视频放在群文件中,你也可以先点击这个链接直接观看(https://live.youkuaiyun.com/v/120663),这里放张图片。
3、完整资料
欢乐的白嫖时光从来不会缺席!(完整工程、演示视频、参考资料下载链接:https://download.youkuaiyun.com/download/Learning1232/13686567)。