16 SPI LOOP环路实验

发布时间 2023-12-29 13:20:42作者: 米联客(milianke)

软件版本:vitis2021.1(vivado2021.1)

操作系统:WIN10 64bit

硬件平台:适用XILINX A7/K7/Z7/ZU/KU系列FPGA

登录"米联客"FPGA社区-www.uisrc.com视频课程、答疑解惑!

1 概述

在前面完成了SPI发送驱动程序、SPI接收驱动程序设计,本文对前面的SPI收发驱动做一个环路测试,通过仿真,以及在线仿真的方式验证SPI的收发应用。

本文将在前面课程的基础上完成,包括采用前面课程编写SPI发送驱动和接收驱动。

2 SPI环路程序设计

2.1 系统框图

以下给出系统框图,关于各个模块的详细描述请看前面的实验。本实验中短接SPI发送模块和接收模块的SCLK和MOSI和MISO,并且在芯片内部通过在线逻辑分析仪在线观察结果

2.2 SPI数据发送状态机

在本实验中,TX发送状态机中增加spi_ss控制,该信号用于spi接收模块的数据的启动接收和停止接收控制

/*********************SPI环路测试*********************

1. I_spi_miso接收驱动,用于接收串口数据,当spi_rvalid代表接收驱动接收到了总线的有效数据

2. O_spi_mosi发送驱动,用于发送数据,当spi_tx_req为高电平,请求发送数据环路测试中*********************************************************************/

`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)

);

 

ila_0 ila_0(

.clk(I_sysclk),

.probe0(spi_rvalid),

.probe1(spi_rdata)

);

endmodule

3 FPGA工程

fpga工程的创建过程不再重复,如有不清楚的请看前面实验

 

 

米联客的代码管理规范,在对应的FPGA工程路径下创建uisrc路径,并且创建以下文件夹

01_rtl:放用户编写的rtl代码

02_sim:仿真文件或者工程

03_ip:放使用到的ip文件

04_pin:放fpga的pin脚约束文件或者时序约束文件

05_boot:放编译好的bit或者bin文件(一般为空)

06_doc:放本一些相关文档(一般为空)

4 RTL仿真

4.1 仿真激励文件

仿真测试文件源码如下:

`timescale 1ns / 1ps//定义仿真时间刻度/精度

module master_spi_tb;

localparam      CLK_TIME   =  'd20;//时钟周期,以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 RTL功能仿真

可以放大箭头所指位置,查看接收数据和发送数据是否一致,本实验只测试CHPA=0 CPOL=0的情况。

5 上板验证

5.1 在线逻辑分析仪设置

添加在线逻辑分析仪,设置为Capture Control模式

5.2 硬件连接

(该教程为通用型教程,教程中仅展示一款示例开发板的连接方式,具体连接方式以所购买的开发板型号以及结合配套代码管脚约束为准。)

请确保下载器和开发板已经正确连接,注意跳线帽短接,并且开发板已经上电。(注意JTAG端子不支持热插拔,而USB接口支持,所以在不通电的情况下接通好JTAG后,再插入USB到电脑,之后再上电,以免造成JTAG IO损坏)

5.3 在线调试结果

在线逻辑分析仪设置成BASIC模式,设置spi_rvalid为高电平的时候触发采集:

调整数据格式为十进制,显示为SPI传输的连续的数字,符合我们工程