跳至正文

Verilog功能模块–SPI主机和从机(04)–SPI主机从机回环仿真与实测

前言

前文已经介绍了SPI的基本原理,主机和从机的设计方法。

本文设定了多个仿真条件,对SPI主机和从机进行回环仿真测试,验证了主机和从机模块都能正常工作。

一、回环测试实验设计

实验条件:

  1. 设计与仿真工具:Vivado 2024.2
  2. 模块工作时钟频率100MHz/120MHz
  3. 其它参数见以下表格

实验表格1:

实验条件fCLK = 100MHz fSCLK = 10MHz fSCLK = 50MHz
SPI MODE = 0
数据位宽 = 8
CS_EDGE_TO_SCLK_EDGE_CLK_NUM = 1
SCLK_EDGE_TO_CS_EDGE_CLK_NUM = 3
CS_KEEP_HIGH_CLK_NUM = 2
条件1 条件2
SPI MODE = 1
数据位宽 = 10
CS_EDGE_TO_SCLK_EDGE_CLK_NUM = 2
SCLK_EDGE_TO_CS_EDGE_CLK_NUM = 4
CS_KEEP_HIGH_CLK_NUM = 3
条件3 条件4

实验表格2:

实验条件fCLK = 120MHz fSCLK = 20MHz fSCLK = 30MHz
SPI MODE = 2
数据位宽 = 12
CS_EDGE_TO_SCLK_EDGE_CLK_NUM = 3
SCLK_EDGE_TO_CS_EDGE_CLK_NUM = 5
CS_KEEP_HIGH_CLK_NUM = 4
条件5 条件6
SPI MODE = 3
数据位宽 = 16
CS_EDGE_TO_SCLK_EDGE_CLK_NUM = 4
SCLK_EDGE_TO_CS_EDGE_CLK_NUM = 6
CS_KEEP_HIGH_CLK_NUM = 5
条件7 条件8

说明:

  1. SPI MODE有四种可以选择

  2. 数据位宽理论上可以取2~∞,这里选择8、10、12、16进行实验,既有8的整数倍,也有非整数倍,覆盖更多情形

  3. XXX_CLK_NUM理论上可以取1~∞,但如果满足1、2、3这三种极限情况,其它取值也不会存在问题,所以选取这几种取值进行实验

二、如何判断实验是否成功

实验以仿真信号波形图为判断依据,同一实验条件波形图会有多张,如条件1对应图1.1,1.2,1.3等。从波形图中应能看到如下的实验细节:

  1. SPI模式是否与设定相同

  2. SCLK频率是否与设定相同

  3. 单次SPI通信发送/接收的数据位宽是否与设定相同

  4. 三个时序参数是否与设定相同

  5. 从机接收的数据是否始终等于主机发送的数据

  6. 主机接收的数据是否始终等于从机发送的数据

如果一个实验同时满足以上五点,则认为实验成功;否则,实验失败。

注意:SPI模式判断,参照表:

模式 SCLK空闲值 数据采样边沿 数据更新边沿
0 0 上升沿 下降沿
1 0 下降沿 上升沿
2 1 上升沿 下降沿
3 1 下降沿 上升沿

三、SPI主从回环——功能仿真

仿真testbench部分代码:

module mySPI_4Wire_LoopBack_tb();

//++ 仿真时间尺度 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
timeunit 1ns;
timeprecision 1ps;
//-- 仿真时间尺度 ------------------------------------------------------------


//++ 被测模块实例化 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
localparam integer SPI_MODE                     = 0;   // SPI模式, 可选0, 1, 2, 3 (默认)
localparam integer DATA_WIDTH                   = 8;   // 单次通信发送或接收数据的位宽, 最小为2, 常见8/16
localparam integer SCLK_PERIOD_CLK_NUM          = 10;  // fSCLK, SCLK周期对应CLK数, 必须为偶数, 最小为2
localparam integer CS_EDGE_TO_SCLK_EDGE_CLK_NUM = 1;   // TCC, CS_N下降沿到SCLK的第一个边沿对应CLK数, 最小为1
localparam integer SCLK_EDGE_TO_CS_EDGE_CLK_NUM = 2;   // TCCH, 最后一个SCLK边沿到CS_N上升沿对应CLK数, 最小为3
localparam integer CS_KEEP_HIGH_CLK_NUM         = 3;   // TCWH, CS_N低电平后保持高电平的时间对应CLK数, 最小为2
localparam integer CLK_FREQ_MHZ                 = 100// 模块工作时钟, 常用100/120

logic clk;
logic rstn;

mySPI_4Wire_LoopBack # (
  .SPI_MODE                     (SPI_MODE                    ),
  .DATA_WIDTH                   (DATA_WIDTH                  ),
  .SCLK_PERIOD_CLK_NUM          (SCLK_PERIOD_CLK_NUM         ),
  .CS_EDGE_TO_SCLK_EDGE_CLK_NUM (CS_EDGE_TO_SCLK_EDGE_CLK_NUM),
  .SCLK_EDGE_TO_CS_EDGE_CLK_NUM (SCLK_EDGE_TO_CS_EDGE_CLK_NUM),
  .CS_KEEP_HIGH_CLK_NUM         (CS_KEEP_HIGH_CLK_NUM        ),
  .CLK_FREQ_MHZ                 (CLK_FREQ_MHZ                )
) mySPI_4Wire_LoopBack_inst (.*);
//-- 被测模块实例化 ------------------------------------------------------------


//++ 生成时钟 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
localparam CLKT = 1000 / CLK_FREQ_MHZ;
initial begin
  clk = 0;
  forever #(CLKT / 2) clk = ~clk;
end
//-- 生成时钟 ------------------------------------------------------------


//++ 测试输入 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
initial begin
  rstn = 0;
  #(CLKT * 1);
  rstn = 1;
  #(CLKT * (SCLK_PERIOD_CLK_NUM * DATA_WIDTH * 10));
  $stop;
end
//-- 测试输入 ------------------------------------------------------------


endmodule

回环测试模块部分代码如下:

//++ 回环测试控制 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
reg rstn_r1;
always @(posedge clk) begin
  rstn_r1 <= rstn;
end

assign spi_begin = rstn_r1;

always @(posedge clk) begin
  if (~rstn)
    spi_master_tx_data <= 'hAB;
  else if (spi_master_rx_data_valid)
    spi_master_tx_data <= spi_master_rx_data + 1'b1;
  else
    spi_master_tx_data <= spi_master_tx_data;
end

reg spi_slave_rx_data_valid_r1;
reg spi_slave_rx_data_valid_r2;
always @(posedge clk) begin
  spi_slave_rx_data_valid_r1 <= spi_slave_rx_data_valid;
  spi_slave_rx_data_valid_r2 <= spi_slave_rx_data_valid_r1;
end

wire spi_slave_rx_data_valid_pedge = spi_slave_rx_data_valid_r1 && ~spi_slave_rx_data_valid_r2;

always @(posedge clk) begin
  if (~rstn)
    spi_slave_tx_data <= 'hAB;
  else if (spi_slave_rx_data_valid_pedge)
    spi_slave_tx_data <= spi_slave_rx_data + 1'b1;
  else
    spi_slave_tx_data <= spi_slave_tx_data;
end
//-- 回环测试控制 ------------------------------------------------------------

第一次通信:主机发送AB,从机也发送AB,所以,主机接收到AB,从机也接收到AB;

第一次通信:主机发送AB+1,从机也发送AB+1,所以,主机接收到AB+1,从机也接收到AB+1;

以此类推。

所有实验发送数据不变,位宽变化只是使得 8’hAB 变为 10’h0AB12’h0AB16’h00AB

3.1 fCLK = 100MHz,SPI_MODE = 0,数据位宽 = 8,时序参数 = 1/3/2,fSCLK = 10MHz

图1.1-单周期整体图:

图1.2-前两个SCLK周期波形图:

图1.3-后两个SCLK周期波形:

图1.4-两周期整体图:

从波形图中可以确定以下检查项:

检查项 设定值/发送值 仿真值/发送值 是否一致
SCLK空闲值 0 0
数据采样边沿 上升沿 上升沿
数据更新边沿 下降沿 下降沿
SCLK频率 100/10 100/10
数据位宽 8 8
CS_EDGE_TO_SCLK_EDGE_CLK_NUM 1 1
SCLK_EDGE_TO_CS_EDGE_CLK_NUM 3 3
CS_KEEP_HIGH_CLK_NUM 2 2
第一个周期,主机发送数据==从机接收数据 8’AB(发送) 8’AB(接收)
第一个周期,主机接收数据=从机发送数据 8’AB(发送) 8’AB(接收)
第二个周期,主机发送数据==从机接收数据 8’AC(发送) 8’AC(接收)
第二个周期,主机接收数据=从机发送数据 8’AC(发送) 8’AC(接收)

结论:

  1. 设定值与仿真值基本相同,其中SCLK_EDGE_TO_CS_EDGE_CLK_NUM与CS_KEEP_HIGH_CLK_NUM由于主机使用时序逻辑的限制,仿真值=设定值+2,此特性不影响实际功能。
  2. 主从机回环发送与接收均正常。

3.2 fCLK = 100MHz,SPI_MODE = 0,数据位宽 = 8,时序参数 = 1/3/2,fSCLK = 50MHz

图2.1–单周期整体图:

图2.2–两周期整体图:

从波形图中可以确定以下检查项:

检查项 设定值/发送值 仿真值/发送值 是否一致
SCLK空闲值 0 0
数据采样边沿 上升沿 上升沿
数据更新边沿 下降沿 下降沿
SCLK频率 100/2 100/2
数据位宽 8 8
CS_EDGE_TO_SCLK_EDGE_CLK_NUM 1 1
SCLK_EDGE_TO_CS_EDGE_CLK_NUM 3 3
CS_KEEP_HIGH_CLK_NUM 2 2

结论:回环测试正常。

3.3 fCLK = 100MHz,SPI_MODE = 1,数据位宽 = 10,时序参数 = 2/4/3,fSCLK = 10MHz

图3.1–单周期整体图:

图3.2–前两个SCLK周期:

图3.3–后两个SCLK周期:

图3.4–两周期整体图:

从波形图中可以确定以下检查项:

检查项 设定值/发送值 仿真值/发送值 是否一致
SCLK空闲值 0 0
数据采样边沿 下降沿 下降沿
数据更新边沿 上升沿 上升沿
SCLK频率 100/10 100/10
数据位宽 10 10
CS_EDGE_TO_SCLK_EDGE_CLK_NUM 2 2
SCLK_EDGE_TO_CS_EDGE_CLK_NUM 4 4
CS_KEEP_HIGH_CLK_NUM 3 3

结论:回环测试正常。

3.4 fCLK = 100MHz,SPI_MODE = 1,数据位宽 = 10,时序参数 = 2/4/3,fSCLK = 50MHz

4.1–单周期整体图:

4.2–两周期整体图:

其余略。

3.5 fCLK = 120MHz,SPI_MODE = 2,数据位宽 = 12,时序参数 = 3/5/4,fSCLK = 20MHz

5.1–单周期整体图:

5.2–前两个SCLK波形图:

5.3–后两个SCLK波形图:

5.4–两周期整体图:

从波形图中可以确定以下检查项:

检查项 设定值/发送值 仿真值/发送值 是否一致
SCLK空闲值 1 1
数据采样边沿 下降沿 下降沿
数据更新边沿 上升沿 上升沿
SCLK频率 120/6 120/6
数据位宽 12 12
CS_EDGE_TO_SCLK_EDGE_CLK_NUM 3 3
SCLK_EDGE_TO_CS_EDGE_CLK_NUM 5 5
CS_KEEP_HIGH_CLK_NUM 4 4

结论:回环测试正常。

3.6 fCLK = 120MHz,SPI_MODE = 2,数据位宽 = 12,时序参数 = 3/5/4,fSCLK = 30MHz

6.1–后两个SCLK波形图:

9.2–两周期整体图:

其余略。

3.7 fCLK = 120MHz,SPI_MODE = 3,数据位宽 = 16,时序参数 = 4/5/6,fSCLK = 20MHz

7.1–单周期整体图:

7.2–前两个SCLK波形图:

7.3–后两个SCLK波形图:

7.4–两周期整体图:

从波形图中可以确定以下检查项:

检查项 设定值/发送值 仿真值/发送值 是否一致
SCLK空闲值 1 1
数据采样边沿 上升沿 上升沿
数据更新边沿 下降沿 下降沿
SCLK频率 120/6 120/6
数据位宽 16 16
CS_EDGE_TO_SCLK_EDGE_CLK_NUM 4 4
SCLK_EDGE_TO_CS_EDGE_CLK_NUM 5 5
CS_KEEP_HIGH_CLK_NUM 6 6

结论:回环测试正常。

3.8 fCLK = 120MHz,SPI_MODE = 3,数据位宽 = 16,时序参数 = 4/5/6,fSCLK = 30MHz

8.1–后两个SCLK周期:

8.2-两周期整体图:

其余略。

四、结论

此SPI主从模块功能正常,且具有广泛的适用性:

  1. 可适配4种SPI模式
  2. 可选择任何SCLK频率(CLK频率的偶次分频)
  3. 可灵活配置多个时序参数
  4. 可灵活配置数据位宽

五、分享

源码在Gitee与Github开源,两平台同步。与上篇文章是:

Gitee:Verilog功能模块–SPI主机和从机: Verilog功能模块–SPI主机和从机 https://gitee.com/xuxiaokang/verilog-function-module–SPI-Master-Slave

Github:zhengzhideakang/Verilog–SPI-Master-Slave: verilog-function-module–SPI-Master-Slave https://github.com/zhengzhideakang/Verilog–SPI-Master-Slave

仿真的Vivado工程通过网盘分享。

欢迎大家关注我的微信公众号:徐晓康的博客,回复以下6位数字获取网盘链接。

451078

建议复制过去不会码错字!


如果本文对你有所帮助,欢迎点赞、转发、收藏、评论让更多人看到,赞赏支持就更好了。

如果对文章内容有疑问,请务必清楚描述问题,留言评论或私信告知我,我看到会回复。


徐晓康的博客持续分享高质量硬件、FPGA与嵌入式知识,软件,工具等内容,欢迎大家关注。

0 0 投票数
文章评分
订阅评论
提醒
0 评论
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x