FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议

在某些应用场景下,有时候需要 SPI 的参数可配置,例如 SPI 的时钟频率、时钟极性和相位以及 SPI 数据位宽等参数可配置,以兼容更多的应用。这里就以 FPGA 为例简单介绍一下实现原理。

一、测试平台

  • Quartus II 13.1 + Keil 5.3
  • iCore4

二、可配置的 SPI 通信协议实现原理

2.1 SPI 时钟频率可配置

SPI 时钟频率可配置,主要是通过任意分频器来实现,具体可以参考如下文章:

FPGA实现任意分频系数和占空比的时钟频率输出

FPGA实现任意分频系数和占空比的时钟频率输出

分频在 fpga 的设计中一直都担任着很重要的角色,而说到分频,我相信很多人都已经想到了利用计算器来计算达到想要的时钟频率,但问题是仅仅利用计数器来分频,只可以实现偶数分频,而如果…

2.2 SPI 时钟极性相位可配置

关于时钟极性和相位的基础知识可参考之前的文章:

SPI通信协议介绍及调试方法

SPI通信协议介绍及调试方法

SPI 通信作为电子电气领域较为常见的通信方式之一,具有广泛的用途。本文简要介绍一下 SPI 通信协议及调试方法与注意事项。 一、SPI 简介 SPI(Serial Periphe…

接下来直接给出 FPGA 端的代码分析和仿真流程:

(1)testbench 产生触发信号 start 和数据 SSPI_data_in,DUT 将数据存入 FIFO 中,同时通过跨时钟域处理,将 start 信号转换成 FIFO 读使能信号 spi_valid,不过这里需要延迟一个周期生成 spi_valid_r1,用于读取 FIFO(数据为 SSPI_data_in_q),再延迟一个周期 spi_valid_r2 待数据读出后用于使能 spi 状态机。

(2)根据 SSPI_CPOL_CPHA 的配置信息,执行不同的状态机;需要说明一点,spi 时钟在 CPOL=’1’下,如果用 sys_clk 下降沿采样,最后会额外产生一个毛刺,同样,spi 时钟在 CPOL=’0’下,如果用 sys_clk 上升沿采样,也会产生一个毛刺,所以这部分也根据 SSPI_CPOL_CPHA 的配置,执行不同的状态机。

(3)tb_received_spi_data 为 testbench 收到 DUT 发送过来的 SPI 数据,可以发现和原始信号 SSPI_data_in 相同;tb_send_spi_data 为 testbench 反馈的 SPI 数据,经状态机后,DUT 收到数据 SSPI_data_out,同样,两个数据相同。

下面分别是 4 种 SSPI_CPOL_CPHA 配置下的仿真波形。

FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 1 CPOL = 0, CPHA = 0 仿真波形
FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 2 CPOL = 0, CPHA = 1 仿真波形
FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 3 CPOL = 1, CPHA = 0 仿真波形
FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 4 CPOL = 1, CPHA = 1 仿真波形

2.3 SPI 数据位宽的设置

FPGA 设定的 SPI 数据位宽为 32 位,对应的寄存器也是 32 位,对于小于 32 位的应用,可通过控制状态机的执行过程来实现相应数据位宽的收发。例如 24 位的 SPI 数据位宽,状态机执行到 6’d23 即回归 6’d0 状态,此时 32 位数据中的高 24 位数据发送出去了(即来自 testbench 的数据输入 SSPI_data_in 高 24 位有效),同时接收低 24 位有效。

FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 5 配置 24 位 SPI 数据仿真波形

为了方便操作,使 testbench 的数据输入也变成相应的低 8/16/24 位有效,FPGA 对要发送的数据做一下处理。

assign SSPI_data_in_q = 32'hbbccddeeff;

//--------------------------shift bits according to data width configuration----------//
reg [31:0] SSPI_data_in_temp;

always@(posedge clk_150m or negedge rst_n)
	if(!rst_n)
		SSPI_data_in_temp <= 32'b0;
	else if(SSPI_valid_r2)
	begin
		if(SSPI_DATA_WIDTH == 2'b00)
			SSPI_data_in_temp <= SSPI_data_in_q << 24;
		else if(SSPI_DATA_WIDTH == 2'b01)
			SSPI_data_in_temp <= SSPI_data_in_q << 16;
		else if(SSPI_DATA_WIDTH == 2'b10)
			SSPI_data_in_temp <= SSPI_data_in_q << 8;
		else if(SSPI_DATA_WIDTH == 2'b11)
			SSPI_data_in_temp <= SSPI_data_in_q;			
		else 
			SSPI_data_in_temp <= 32'b0;
	end

如此,在实际应用中,testbench 或者控制器只需要发送对应位的有效数据即可,例如,24 位的 SPI 通信,发送 32’h00aabbcc 即可(低 24 位有效),FPGA 会将 24’haabbcc 数据配置从机,从机反馈的 SPI 数据假如为 24’hddeeff,FPGA 发给 testbench 或者控制器为 32’h00ddeeff(低 24 位有效)。

三、平台实测

由于这里使用的平台包含了 FPGA 和 ARM 两个控制器,因此就以 FPGA 为 SPI 主机、ARM 为 SPI 从机做简单的分析。这里的 ARM 仅使用了 SPI 从机和 UART 功能,所以 FPGA 的 SPI 时钟配置信息采用手动更改,重点验证各种配置模式下的 SPI 时序正确与否。实际使用时,ARM 一般作为主控芯片通过总线配置 FPGA 的 SPI 时钟参数,FPGA 再发出相应的 SPI 波形,与下游通信。

ARM 为 STM32,采用 Cube 库函数生成相应的代码。先分析一下生成的函数关于 SPI 时钟极性和相位的配置:

  hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;

对应 SPI 时钟空闲状态低电平,在第一个跳变沿采样,也就是上升沿采样,下降沿发出数据,对应 CPOL = 0, CPHA = 0。

  hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;

对应 SPI 时钟空闲状态低电平,在第二个跳变沿采样,也就是下降沿采样,上升沿发出数据,对应 CPOL = 0, CPHA = 1。

  hspi4.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;

对应 SPI 时钟空闲状态高电平,在第二个跳变沿采样,也就是上升沿采样,下降沿发出数据,对应 CPOL = 1, CPHA = 0。

  hspi4.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;

对应 SPI 时钟空闲状态高电平,在第一个跳变沿采样,也就是下降沿采样,上升沿发出数据,对应 CPOL = 1, CPHA = 1。

根据 STM32 的 SPI 时钟极性相位和数据位宽配置信息,相应的修改 FPGA 端的配置代码:

SSPI_CPOL_CPHA = 2'b11;
SSPI_DATA_WIDTH = 2'b01;

以 16 位数据为例,分别测试 SPI 时钟极性和相位 4 种配置情况下的波形。

FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 6 CPOL = 0, CPHA = 0 实测波形
FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 7 CPOL = 0, CPHA = 1 实测波形
FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 8 CPOL = 1, CPHA = 0 实测波形
FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 9 CPOL = 1, CPHA = 1 实测波形

测试流程:SPI 主机(FPGA)发送 16’heeff,STM32 收到之后传输到 PC;同时 SPI 从机(STM32)反馈 16 位数据 0x0a, 0x0b,SPI 主机收到该数据存入寄存器,并通过串口返回给 STM32,STM32 传输到 PC。如下图所示是串口助手收到的数据。

FPGA实现SPI时钟频率、极性相位和数据位宽可配置的SPI通信协议
图 10 串口测试 SPI 收发数据

0xff, 0xee 为 SPI 主机传输过来的 SPI 数据,0x00, 0x00, 0x0b, 0x0a 为 SPI 主机接收到的 SPI 数据并通过串口回传到 PC 的数据(取低 16 位)。

注意一点:串口助手收到的数据与 SPI 主机发送过来的是反的,但是实测波形是与 SPI 主机发送的数据一致,这可能与 STM32 收发 SPI 数据采用的指针型数组有关,待查。

后续可将位宽的功能处理的更完善一些。

附件仅博主测试所用,暂不提供下载

扫码关注尚为网微信公众号

尚为网微信公众号
每天学习电路设计嵌入式系统的专业知识,关注一波,没准就用上了。

原创文章,作者:sunev,如若转载,请注明出处:https://www.sunev.cn/embedded/926.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2021年2月20日 15:06
下一篇 2021年3月8日 15:58

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注