本帖最后由 FPGA课程 于 2024-9-19 17:19 编辑
软件版本:Anlogic -TD5.9.1-DR1_ES1.1
操作系统:WIN10 64bit
硬件平台:适用安路(Anlogic)FPGA
实验平台:米联客-MLKPAI-SF01-DR1M90M开发板
板卡获取平台:https://milianke.tmall.com/
登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑!
1概述在前面完成了SPI发送驱动程序、SPI接收驱动程序设计,本文对前面的SPI收发驱动做一个环路测试,通过仿真,以及在线仿真的方式验证SPI的收发应用。 本文将在前面课程的基础上完成,包括采用前面课程编写SPI发送驱动和接收驱动。 在完成本实验前,请确保已经完成前面的实验,包括已经掌握以下能力: 1:完成了TD软件安装 2:完成了modelsim安装以及TD库的编译 3:掌握了TD仿真环境的设置 4:掌握了modesim通过do文件启动仿 实验目的: 1:实现SPI LOOP环路的设计 2:实用modelsim完成仿真验证 1.1SPI收发环路简介主机在通过MOSI数据线发送数据的同时,从机也会通过 MISO 将数据传输给主机(收发同时进行)。数据通常先移出最高位,传输可能会持续任意数量的时钟周期。传输完成后,主设备拉高SS片选信号并停止传输信号。
1.2硬件电路分析CEP(camera expand peripheral),接口供电可自行选择 3V3 或 5V0,默认 3V3。进行SPI通信时,短接SPI发送模块和接收模块的SCLK,短接SPI发送模块的MOSI和接收模块的MISO,形成一条通路。
2SPI环路程序设计2.1系统框图本次实验包含三个模块,SPI发送驱动模块、SPI接收驱动模块、顶层模块。以下给出系统框图,关于接收和发送模块的详细描述请看前面的实验,我们主要看顶层模块关于发送状态机的部分。芯片内部接收驱动接收到的有效信号通过在线逻辑分析仪在线观察结果。
发送状态机; 在所有模块开始运行之前先进行复位延时,计数结束后再进入到发送状态机部分。延时完成后进入状态0,spi总线不忙时拉高ss片选信号,spi_ss_i信号用于控制spi接收模块的数据的启动接收和停止接收,并进入状态1;拉低ss片选信号,启动SPI接收模块,进入状态2;拉高req信号,启动SPI发送模块,发送第一个测试数据spi_tx_data=1,此时SPI接收模块同时接收SPI发送驱动发送的数据O_spi_mosi,并进入状态3;如果spi总线忙,清除spi_tx_req,并重新进入状态0等待spi总线不忙时开启下一次的传输;如果总线不忙,进入状态0开启下一次传输。
2.2驱动源码在本实验中,TX发送状态机中增加spi_ss控制,该信号用于spi接收模块的数据的启动接收和停止接收控制 - `timescale 1ns / 1ps//仿真时钟刻度和精度
- module spi_master#
- (
- parameter CLK_DIV = 10
- )
- (
- input I_sysclk, //系统时钟
- input I_rstn, //全局复位
- output O_spi_sclk, //SPI MASTER输出时钟
- input I_spi_sclk, //SPI Slave 输入时钟
- output O_spi_mosi, //SPI MASTER输出数据
- input I_spi_miso //SPI Slave 输入数据
- );
- wire spi_busy;
- reg spi_tx_req;
- reg [7:0] spi_tx_data;
- reg [1:0] M_S;
- reg spi_ss_i;/*synthesis keep*/
- wire spi_rvalid;/*synthesis keep*/
- wire[7:0] spi_rdata;/*synthesis keep*/
- reg [10:0] delay_cnt;
- wire delay_done;
- assign delay_done = delay_cnt[10]; //复位延时计数
- always @(posedge I_sysclk or negedge I_rstn) begin //异步复位
- if(!I_rstn)
- delay_cnt <=0; //复位来的是,时钟清零
- else if(delay_cnt[10] == 1'b0) //当delay_cnt[10]等于1时,计数清零,不满足就自+1
- delay_cnt <= delay_cnt + 1'b1;
- else
- delay_cnt <= 0; //达到预期值,计数清零
- end
- always @(posedge I_sysclk or negedge I_rstn) begin //spi发送状态机
- if(!I_rstn) begin
- spi_ss_i <= 1'b1;
- spi_tx_req <= 1'b0;
- spi_tx_data <= 8'd0;
- M_S <= 2'd0;
- end
- else begin
- case(M_S)
- 0:if(delay_done&&(!spi_busy))begin //延时完成且SPI传输非忙
- spi_ss_i <= 1'b1; //拉高spi_ss_i信号,启动spi接收模块的数据的接收
- M_S <= 2'd1; //从初始状态转入状态1
- end
- 1:if(delay_done&&(!spi_busy))begin
- spi_ss_i <= 1'b0; //启动后,将 spi_ss_i信号复原
- M_S <= 2'd2;
- end
- 2:if(delay_done&&(!spi_busy))begin //总线不忙启动传输
- spi_tx_req <= 1'b1; //req信号拉高,准备发送
- spi_tx_data <= spi_tx_data + 1'b1; //测试数据
- M_S <= 2'd3;
- end
- 3:if(spi_busy)begin //如果spi总线忙,清除spi_tx_req
- spi_tx_req <= 1'b0;
- M_S <= 2'd0;
- end
- default:M_S <= 2'd0;
- endcase
- end
- end
- //spi master tx控制器例化
- uimspi_tx#
- (
- .CLK_DIV(CLK_DIV),
- .CPOL(1'b0),
- .CPHA(1'b0)
- )
- uimspi_tx_inst(
- .I_clk(I_sysclk),
- .I_rstn(I_rstn),
- .O_spi_mosi(O_spi_mosi),
- .O_spi_sclk(O_spi_sclk),
- .I_spi_tx_req(spi_tx_req),
- .I_spi_tx_data(spi_tx_data),
- .O_spi_busy(spi_busy)
- );
- //spi rx控制器例化
- uispi_rx#
- (
- .BITS_LEN(8),
- .CPOL(1'b0),
- .CPHA(1'b0)
- )
- uispi_rx_inst(
- .I_clk(I_sysclk),
- .I_rstn(I_rstn),
- .I_spi_clk(I_spi_sclk),
- .I_spi_rx(I_spi_miso),
- .I_spi_ss(spi_ss_i),
- .O_spi_rvalid(spi_rvalid),
- .O_spi_rdata(spi_rdata)
- );
- endmodule
复制代码 3FPGA工程fpga工程的创建过程不再重复,如有不清楚的请看前面实验,具体的FPGA型号以对应的开发板上芯片为准
米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹 01_rtl:放用户编写的rtl代码 02_sim:仿真文件或者工程 03_ip:放使用到的ip文件 04_pin:放fpga的pin脚约束文件或者时序约束文件 05_boot:放编译好的bit或者bin文件(一般为空) 06_doc:放本一些相关文档(一般为空)
4Modelsim仿真4.1准备工作Modelsim仿真的创建过程不再重复,如有不清楚的请看前面实验 仿真测试文件源码如下: - `timescale 1ns / 1ps//定义仿真时间刻度/精度
- module master_spi_tb;
- localparam CLK_TIME = 'd40;//时钟周期,以ns为单位
- reg I_sysclk;
- reg I_rstn;
- wire O_spi_sclk;
- wire I_spi_sclk;
- wire O_spi_mosi;
- wire I_spi_miso;
- assign I_spi_miso = O_spi_mosi;//模拟数据回环
- assign I_spi_sclk = O_spi_sclk;//模拟时钟回环
- //例化顶层模块
- spi_master#
- (
- .CLK_DIV(100)
- )
- spi_master_inst(
- .I_sysclk(I_sysclk),
- .I_rstn(I_rstn),
- .O_spi_sclk(O_spi_sclk),
- .O_spi_mosi(O_spi_mosi),
- .I_spi_sclk(I_spi_sclk),
- .I_spi_miso(I_spi_miso)
- );
- initial begin
- //初始化REG寄存器
- I_sysclk= 1'b0;//系统时钟
- I_rstn = 1'b0;//复位
- #100;
- I_rstn = 1'b1;
- end
- always #(CLK_TIME/2) I_sysclk = ~I_sysclk; //产生主时钟
- endmodule
复制代码 4.2启动modelsim仿真启动后,右击需要观察的信号,添加到波形窗口 以下启动modelsim仿真,可以放大箭头所指位置,查看接收数据和发送数据是否一致,本实验只测试CHPA=0 CPOL=0的情况。
5上板验证 5.1chipwatcher设置关于chipwatcher的设置,可以参考前面的实验,这里只做关键内容介绍。为了在线逻辑分析仪不去优化一些信号可以实用: - reg spi_ss_i;/*synthesis keep*/
- wire spi_rvalid;/*synthesis keep*/
- wire[7:0] spi_rdata;/*synthesis keep*/
复制代码
设置好后需要保持,然后重新编译
5.2硬件连接(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。) 请确保下载器和开发板已经正确连接,并且开发板已经上电(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏) 外部环路需要实用跳线帽,CEP-GPIO接口中的IO可以用于完成本实验
5.3在线调试结果Chipwatcher的如果调用这里不再重复,如果有不清楚的可以阅读前面文章中的实验。 需要观察的信号如下,设置spi_valid为高电平的时候触发采集:
可以看到接收到的数据和发送的数据一致
|