这里会显示出您选择的修订版和当前版本之间的差别。
后一修订版 | 前一修订版 | ||
icore3_fpga_19 [2019/12/23 17:45] zhangzheng 创建 |
icore3_fpga_19 [2022/03/18 15:45] (当前版本) sean |
||
---|---|---|---|
行 1: | 行 1: | ||
- | [[http://www.cnblogs.com/xiaomagee/p/5642334.html]] | + | | **银杏科技有限公司旗下技术文档发布平台** |||| |
+ | |技术支持电话|**0379-69926675-801**||| | ||
+ | |技术支持邮件|Gingko@vip.163.com||| | ||
+ | ^ 版本 ^ 日期 ^ 作者 ^ 修改内容 ^ | ||
+ | | V1.0 | 2020-02-27 | gingko | 初次建立 | | ||
+ | |||
+ | ===== 实验十九:基于双口 RAM 的 ARM+FPGA 数据存取实验 ===== | ||
+ | |||
+ | ==== 一、 实验目的与意义 ==== | ||
+ | |||
+ | - 了解双口 RAM 读写的工作原理。 | ||
+ | - 掌握双口 RAM 使用方法。 | ||
+ | - 掌握 QuartusII 集成开发环境使用方法。 | ||
+ | 二、 实验设备及平台 | ||
+ | - iCore3 双核心板。[[https://item.taobao.com/item.htm?id=524229438677|点击购买]] | ||
+ | - Blaster(或相同功能)仿真器和 USB 线缆。[[https://item.taobao.com/item.htm?id=554869837940|点击购买]] | ||
+ | - Micro USB 线缆。 | ||
+ | - QuartusII 开发平台。 | ||
+ | - Keil MDK 开发平台。 | ||
+ | - 装有 WIN XP(及更高版本)系统的计算机。 | ||
+ | ==== 三、 实验原理 ==== | ||
+ | |||
+ | * 由于双口RAM有两条相互独立的地址线、数据线和控制线,能实现数据共享,本实验针对双口 RAM 的工作特点进行实验验证。实验中通过 FPGA 对 RAM 的 A 端口进行读写操作,RAM的A端口先向RAM中写入0到255的数据,然后再读出来,如此循环操作。同时,通过 Commix 向 STM32 发送读命令,STM32收到命令后,通过STM32F407的 FSMC总线实现与FPGA通信,对RAM的 B 端口进行读控制,发送一次读命令RAM的 B 端口把相应地址里面的数据发送至 ARM,再发送至 Commix 显示出来以验证实验的成功性。 在本实验中实现了双口 RAM 的两种工作模式:1、双口 RAM 一个端口写操作,另一个端口 读操作;2、双口 RAM 两个端口同时读操作。实验的原理如下图 1 所示。 | ||
+ | {{ :icore3:icore3_fpga_19_1.png?direct |实验原理图}} | ||
+ | |||
+ | ==== 四、 Quartus 内部双口 RAM 块调用 ==== | ||
+ | |||
+ | 1、 打开 Tools——MegaWizard Plug-In Manager. | ||
+ | {{ :icore3:icore3_fpga_19_2.png?direct |图1}} | ||
+ | 2、创建IP核,点击next。 | ||
+ | {{ :icore3:icore3_fpga_19_3.png?direct |图2}} | ||
+ | 3、在弹出界面1存储器列表里选择2双口RAM。3处选择FPGA类型。4处选择输出文件语言类型。5处设置文件存储位置和命名。点击6处next进行下一项设置。 | ||
+ | {{ :icore3:icore3_fpga_19_4.png?direct |图3}} | ||
+ | 4、设置如下 | ||
+ | {{ :icore3:icore3_fpga_19_5.png?direct |图4}} | ||
+ | 5、设置存储器深度为256,输出总线宽度16bit,使用FPGA逻辑资源类型选择自动分配。点击next。 | ||
+ | {{ :icore3:icore3_fpga_19_6.png?direct |图5}} | ||
+ | 6、配置端口时钟和读使能信号。 | ||
+ | {{ :icore3:icore3_fpga_19_7.png?direct |图6}} | ||
+ | 7、注意红框中不打勾,点击Next, | ||
+ | {{ :icore3:icore3_fpga_19_8.png?direct |图7}} | ||
+ | 8、后面几项保持默认设置,直接点击Next,最后点击Finish,双口RAM就构建好了。注意:在存储内容初始化选项设置里选择保持空白,因为本实验是要向双口RAM中写入数据再读出数据并进行对比的操作,不需要在存储器内预装数据。 | ||
+ | {{ :icore3:icore3_fpga_19_9.png?direct |图8}} | ||
+ | {{ :icore3:icore3_fpga_19_10.png?direct |图9}} | ||
+ | {{ :icore3:icore3_fpga_19_11.png?direct |图10}} | ||
+ | {{ :icore3:icore3_fpga_19_12.png?direct |图11}} | ||
+ | ==== 五、代码讲解 ==== | ||
+ | * 构建工程并添加好双口RAM核后,就可以进行逻辑功能的编写了。本实验要实现双口RAM的两种工作模式,这里分别讲一下两种工作模式的实现流程和方法。 | ||
+ | * 模式1:由FPGA控制,先通过A端口向RAM中写入256个数据,然后读出来,循环操作。这是对A端口的独立读写操作。 | ||
+ | * 为了进行数据的对比操作,存储的数据值跟其地址一样,通过计数生成存储数据,并将数据存入与其地址一样的存储单元。计数器以记满512个数为一个周期,前256个时钟周期内向RAM中顺序写入数据,后256个时钟周期内从RAM中顺序读取数据。代码如下: | ||
+ | <code verilog> | ||
+ | always @ (posedge a_clk or negedge rst_n) | ||
+ | begin | ||
+ | if(!rst_n) | ||
+ | begin | ||
+ | a_wren <= 1'd0; | ||
+ | a_rden <= 1'd0; | ||
+ | a_datain <= 10'd0; | ||
+ | a_addr <= 10'd0; | ||
+ | end | ||
+ | else if(cnt >= 10'd0 && cnt <=10'd255) | ||
+ | begin | ||
+ | a_wren <= 1'd1; //写使能信号拉高 | ||
+ | a_addr <= cnt; //写地址 | ||
+ | a_datain <= cnt; //写入数据 | ||
+ | a_rden <= 1'd0; //读使能信号拉低 | ||
+ | end | ||
+ | else if(cnt >= 10'd256 && cnt <= 10'd511) | ||
+ | begin | ||
+ | a_rden <= 1'd1; //读使能信号拉高 | ||
+ | a_addr <= cnt - 10'd256; //读地址 | ||
+ | a_wren <= 1'd0; //写使能信号拉低 | ||
+ | end | ||
+ | end | ||
+ | </code> | ||
+ | * FPGA读取数据之后,对读取器数据和其存储地址进行比对,并根据对比结果产生错误提示信号,再以此信号控制FPGA_LED的显示颜色。 | ||
+ | * 模式2:在FPGA对RAM进行读写操作的同时,STM32通过FSMC总线对RAM的B端口进行读操作。实现对RAM的双端口读操作。 | ||
+ | * 当STM32从RAM中读取数据时,相当于STM32通过FSMC总线对外部存储器进行操作,因此,检测FSMC传递至FPGA的读信号,并将RAM的值从B端口输出至FSMC总线,实现STM32对RAM的读功能。代码如下: | ||
+ | <code verilog> | ||
+ | //--------------------------ram_b_rd---------------------------// | ||
+ | /*控制ram_b端口的读取功能,当读信号来临时,读取相应的数据发送至fsmc总线*/ | ||
+ | wire rd = (CS0 | RD); //提取读信号 | ||
+ | wire wr = (CS0 | WR); //提取写信号 | ||
+ | |||
+ | reg wr_clk1,wr_clk2; | ||
+ | always @(posedge PLL_100M or negedge rst_n) | ||
+ | begin | ||
+ | if(!rst_n) | ||
+ | begin | ||
+ | wr_clk1 <= 1'd1; | ||
+ | wr_clk2 <= 1'd1; | ||
+ | end | ||
+ | else | ||
+ | {wr_clk2,wr_clk1} <= {wr_clk1,wr}; | ||
+ | end | ||
+ | |||
+ | wire b_clk = (!wr_clk2 | !rd); //提取ram_b端口的时钟 | ||
+ | assign DB = !rd ? b_dataout : 16'hzzzz; //读信号来临,读取ram_b端口数据 | ||
+ | </code> | ||
+ | * 在代码中,对时钟做了延迟处理,以保证时钟的触发沿位于数据的稳定期,具体实现可以参考例程代码。 | ||
+ | |||
+ | ==== 六、 实验步骤 ==== | ||
+ | |||
+ | - 把仿真器与 iCore3 的 SWD 调试口连接(直接相连或者通过转换器相连); | ||
+ | - 将 USB-Blaster 与 iCore3 的 JTAG 调试口相连; | ||
+ | - 将跳线帽插在 USB UART; | ||
+ | - 把 iCore3(USB_UART)通过 Micro USB 线与计算机连接,为 iCore3 供电; | ||
+ | - 打开 Commix 串口精灵,找到对应的 COM 端口打开; | ||
+ | - 打开 Quartus II 开发环境,并打开实验工程; | ||
+ | - 烧写 FPGA 程序到 iCore3 上; | ||
+ | - 打开 Keil MDK 开发环境,并打开实验工程; | ||
+ | - 烧写 ARM 程序到 iCore3 上; | ||
+ | - 输入串口命令,观察实验现象。 | ||
+ | ==== 七、 实验现象 ==== | ||
+ | * 一方面,观察 FPGA_LED 的颜色,FPGA向RAM 中先写如数据,然后再读出来,读出数据与其地址相等,绿灯长亮。否则,红灯亮。 | ||
+ | * 另一方面,通过 Commix 发送读命令读取 RAM 地址中的数据,对比写入数据与读取的数据,可以知道写入与读取的数据相同。 | ||
+ | * **命令格式**: 读命令:ram+空格+read+空格+address+\cr\lf | ||
+ | * 例如:ram read 123\cr\lf | ||
+ | * 解析:读取 ram 的第 123 地址的数据。 | ||
+ |