该实现由两个组件组成:在 LabVIEW FPGA 中实现的 SPI 协议以及用于从主机 PC 或实时控制器与 FPGA 进行通信的 LabVIEW 主机接口。该架构允许从单个主机程序控制多个 SPI 端口,同时仍然允许定制 FPGA VI 以进行其他数据采集和处理。该实现不使用任何DMA(直接内存访问)通道,允许使用NI扫描引擎和RIO扫描接口以及FPGA和主机之间的其他高速/大容量数据传输。
1.SPI协议介绍
SPI 是一种以全双工方式运行的同步串行数据链路。也就是说,携带数据的信号同时在两个方向上传播。设备使用主/从协议进行通信,其中主设备启动数据帧。当主设备生成时钟然后选择从设备时,数据可以同时在一个或两个方向上传输。由主设备和从设备决定接收到的字节是否有意义。这可能需要设备丢弃“仅发送”帧中接收到的字节或为“仅接收”帧生成虚拟字节。
四种典型的 SPI 信号包括:
- 时钟 (SCLK) - 该信号由主机生成。传输中的其他信号根据该时钟的边沿时序而变化。
- 主数据输出,从数据输入(MOSI) ——该线是从主设备到从设备的输出。与主时钟边沿同步地逐位传输。
- 主数据输入,从数据输出 (MISO) - 该线是所有连接的从设备的输出。从与主时钟边沿同步的从器件逐位传输。
- 片选 (CS) 或从机选择 (SS) - 这是一组信号,其中每条线都连接到系统中的各个从机。一次断言一根线以启用与相应从机的通信。片选通常被置为低电平。
2.FPGA实现
本文档中的 SPI 总线是使用LabVIEW FPGA 实现的,以执行总线主控和时钟信号。单周期定时循环 (SCTL) 用于执行 SPI 主设备 ( LabVIEW FPGA VI) 与每个端口最多 8 个从设备之间通信的每一步。可以使用相同的 FPGA VI 和主机程序接口创建多个端口。
该总线封装在更高级别的 LabVIEW FPGA VI 中,该 VI 利用状态机在每个 SPI 端口和主机接口之间执行中间通信。该VI同步主机接口和SPI端口,并将从主机发送到指定端口的数据复用。
3.总线实现
状态机用于执行特定操作,然后确定要转换到哪个状态。由于 SPI 具有总线转换发生的特定顺序,因此状态机是实现该协议的不错选择。每个状态完成通信的一部分,然后按顺序转换到下一步。
当 FPGA 上的 SPI 引擎收到命令时,一个通信周期开始。每个字节均从 VI 范围 FIFO 中读取,数据从多路复用器传递并作为布尔数组存储在 FPGA 上。
接收到要发送到 SPI 总线的数据后,指定要写入的器件的片选 (CS) 线被置位。当器件的片选线被置位时,它就准备好一次一位地接收和发送数据。在执行过程中的任何时刻只能有一条片选线处于活动状态。CS 线作为写入 FPGA 硬件上数字 I/O 端口的整数来实现。每个 CS 端口可以寻址 8 个单独的从站。
每个器件都需要由 FPGA 主器件生成时钟信号 (SCLK)。对于端口上的所有设备,该时钟的速率可能不一致,因此可以在每个数据传输周期之前设置时钟速率。一旦片选被置位,主机和从机都准备好进行数据传输。状态机转换到等待状态并保持在该状态足够长的时间以考虑所选的时钟速率。
当延迟完成时,应生成第一个时钟信号以开始数据传输。SPI 设备可能需要四种时钟模式之一进行传输。这些模式取决于时钟极性 (CPOL) 和时钟相位 (CPHA)。CPOL 指定时钟的空闲状态是逻辑低还是逻辑高(分别为 0 或 1)。CPHA 指定数据是在第一个边沿还是第二个边沿(分别为 0 或 1)记入/记出。
当时钟被设置时,它从空闲状态转换到活动状态。如果 CPHA 为 0,则在此转换期间也会对数据进行计时。如果 CPHA 为 1,则当 SCLK 从活动复位为空闲时对数据进行计时。在设置和重置 SCLK 之间,会出现另一个等待状态,以确保正确的时钟速率。对于必须发送的每个位,这些状态都会按顺序重复。
每个字节传输完毕后,VI从从设备接收到的数据会被放入另一个VI范围的FIFO中,以便传输回主机。如果发送到状态机的所有数据都已发送完毕,则片选线复位为无效状态,程序等待下一个命令。如果数据多于一个字节,则会转换回设置时钟状态,并传输其余数据。
除了SPI协议之外,每个端口的VI还具有配置状态。当主机发送的命令为配置时,SCLK 速率、CPOL、CPHA 和端口号将被读取并用于下一个数据传输序列。
4.FPGA多路复用器
为了允许以最少的配置实例化多个端口,使用中间FPGA VI在SPI端口VI和主机VI之间进行通信。该VI由一个状态机组成,管理主机/FPGA握手以及将数据复用到正确的端口。
主机负责传达多路复用器应执行的状态。多路复用器处于空闲状态,等待来自主机的启动命令。当接收到启动命令时,多路复用器将数据指定的端口写入每个端口可访问的全局变量中。在开始执行之前,每个端口VI都会检查它是否是指定端口。
设置端口信息后,复用器检查主机发送的命令。如果命令是Configure,则将CPOL、CPHA、CS和总字节数写入全局变量,为下一次数据传输做准备。如果命令是读/写 SPI,则从主机接收的数据将传递到每个端口可访问的目标范围 FIFO。该数据从目标范围的 FIFO 传输到目标端口的 VI 范围的 FIFO,以在写入和读取状态下传递到 SPI 总线。
由于多路复用器设置了数据的目的地,因此即使有多个端口可用,一次也只能有一个端口传输数据。一旦一个端口的所有数据都已传输,下一个端口就可以开始其传输序列。
5.主机接口
创建了 SPI 通信状态机的 LabVIEW 接口,以方便主机 PC 或实时控制器与 FPGA 多路复用器之间的简单数据传输。借助此高级 API,多个 SPI 端口可以与应用程序所需的任何其他LabVIEW FPGA代码一起实例化。
该API由两个VI组成:FPGA SPI_Configure和FPGA SPI_Read Write。FPGA SPI_Configure 设置 SCLK 速率、CPOL、CPHA、CS 和要使用的端口。该信息通过配置命令传递到 FPGA 多路复用器,并存储在 FPGA 全局变量中。
FPGA SPI_Read Write 需要传输的总位数以及指定该数据的端口。U8字节数组被传递到VI并返回相同大小的数组。主机和 FPGA 之间的所有握手和数据传输都封装在这些 VI 中。
如果其他 FPGA 代码要与 SPI 总线一起使用,来自 FPGA 多路复用器的 SPI 通信循环和所有前面板控件将需要出现在顶层 VI 中。如果没有这些,则需要修改主机 API 以使用正确的标签与前面板控件进行通信。使用Open FPGA Reference VI创建的FPGA参考还需要绑定到API使用的FPGA Reference.ctl typedef。
FPGA 内核和主机 API 附带的示例程序展示了如何从多个端口写入和读取数据。每次按下 Write 按钮时,Write Data 中的数据会发送到 FPGA,而 Read Data 则会从 SPI 总线返回。在写入之间,可以更改端口和配置数据。
6.添加多个SPI端口
向 FPGA 添加多个 SPI 端口相对简单。在项目中,必须为新端口的 SCLK、MOSI、MISO 和 CS 添加新的 FPGA I/O。不需要其他项目配置。
在 FPGA SPI_FPGA Top Level VI 中,所需要做的就是添加 FPGA SPI_SPI Port VI 的另一个实例,并添加端口号的输入以及用于 SCLK、MOSI、MISO 和 CS 的 FPGA I/O。多路复用器VI中的SPI通信循环处理与新端口之间的数据传递。
7.更改FPGA目标
如果需要在不同的目标上编译和运行该示例,则应将主机VI和FPGA参考复制到新目标的非FPGA部分。对于CompactRIO和 Single-Board RIO,这将是 RT 控制器。如果移动到R系列智能DAQ目标,主机VI应移动到项目中的“我的电脑”目标。
项目的 FPGA 部分中必须复制的项目是顶层 FPGA VI 和目标范围的 FPGA FIFO。需要将新的 FPGA I/O 添加到项目中,以便为 SPI 端口创建参考,以便在正确的线路上进行通信。如果FPGA I/O名称与示例中的名称不同,则需要更改端口VI的FPGA I/O常量输入以匹配新项目的FPGA I/O。
要使用主机API,当在主机VI中调用Open FPGA VI Reference时,该引用应绑定到项目中的FPGA Reference控件。这会将目标信息传播到主机 API 的子 VI。