在工业应用中传输信息可能具有挑战性。在这个项目中,让我们看看我们如何使用 FPGA 和 RS485 做到这一点。
项目背景:
许多 FPGA 部署在工业环境中,用于控制流程、驱动器、执行器和传感器。
用于与这些传感器、执行器和驱动器接口的协议非常多样化,尽管时间敏感网络正在改变这一点。虽然有许多不同的协议,例如 Modbus、Profibus 和 EtherCat。其中许多协议都基于常见的物理层,例如 EIA/RS485、EIA/RS422 和以太网。
许多接口的关键要求之一是能够在嘈杂的工业环境中以物理层中的低链路误码率运行。EIA/RS485 和 EIA/RS422 都是差分物理层,它们提供强大的多点接口,能够进行双向 (EIA/RS485) 或单向 (EIA/RS422) 通信。
有许多应用层协议可以使用这些物理层来实现。在这个项目中,我们将研究使用 RS485 Pmod 和定制的应用层协议将两个 MiniZed 连接在一起。
硬件部件
安富利 MiniZed× 1
Digilent Pmod RS485× 2
软件应用程序和在线服务
AMD-Xilinx Vivado 设计套件
AMD-Xilinx Vitis 统一软件平台
应用层
实现的自定义通信协议将使主 MiniZed 能够从从 MiniZed 内的 16 位地址空间读取或写入 32 位字。对于这个项目,我们将从从站中的 BRAM 读取和写入。然而,这个 BRAM 可能被从 MiniZed 上收集数据的传感器填充。
数据将使用 UART 通过 RS485 链路发送,数据包包含多个 UART 传输
写入的格式是
从机将以单字节 ACK 或 NACK 响应写入
读取的格式是
MiniZed 从站的读取响应将是
SOH、STX、ENQ、ACK 和 NACK 在ASCII 表中定义
当然,这个协议可以在像 ZYNQ 这样的处理器中使用 UART 来实现,以使协议具有可扩展性。我为 UART、Protocol Master 和 Protocol Slave 创建了自定义 RTL 模块。
由于 RS485 在同一双绞线上是定向的,因此协议必须仅在准备好发送时启用 RS485 发送器,以减少多个发送器尝试同时发送时总线上的争用可能性。
MiniZed Master
MiniZed Master 设计将使用 PS 内核通过 RS485 接口发送和接收数据。这将使链路能够被测试,因为数据应该能够通过链路写入,然后以不同的顺序从 MiniZed 从站中的块 RAM 中读回。
该设计使用连接到协议主模块的 AXI GPIO 模块来驱动协议主模块的接口要求。这包括地址、数据和读或写操作。结果提供了从中读取的地址和读取的数据。
为了能够调试应用程序,我还包括了几个 ILA,帮助理解系统行为。
在 Minized Master 上运行的软件应用程序是
#include
#include "platform.h"
#include "xil_printf.h"
#include "xgpio.h"
#define DATA_ADDR XPAR_GPIO_0_DEVICE_ID
#define VALID_RW XPAR_GPIO_1_DEVICE_ID
#define DATA_BCK XPAR_GPIO_2_DEVICE_ID
#define DATA_VALID_CH 1
#define ADDR_RW_CH 2
XGpio Gpio1;
XGpio Gpio2;
XGpio Gpio3;
int count = 0;
int main()
{
init_platform();
XGpio_Initialize(&Gpio1, DATA_ADDR);
XGpio_Initialize(&Gpio2, VALID_RW);
XGpio_Initialize(&Gpio3, VALID_RW);
while(1){
u32 rd_data, rd_addr;
//write
XGpio_DiscreteWrite(&Gpio1, DATA_VALID_CH, count );
XGpio_DiscreteWrite(&Gpio1, ADDR_RW_CH, 0x5001);
XGpio_DiscreteWrite(&Gpio2, ADDR_RW_CH, 0x0);
XGpio_DiscreteWrite(&Gpio2, DATA_VALID_CH, 0x1);
XGpio_DiscreteWrite(&Gpio2, DATA_VALID_CH, 0x0);
usleep(1000);
//read
XGpio_DiscreteWrite(&Gpio1, ADDR_RW_CH, 0x5001);
XGpio_DiscreteWrite(&Gpio2, ADDR_RW_CH, 0x1);
XGpio_DiscreteWrite(&Gpio2, DATA_VALID_CH, 0x1);
XGpio_DiscreteWrite(&Gpio2, DATA_VALID_CH, 0x0);
usleep(10000);
rd_data = XGpio_GetDataDirection(&Gpio3, 1);
rd_data = XGpio_DiscreteRead(&Gpio3, 1);
rd_addr = XGpio_DiscreteRead(&Gpio3, 2);
if(rd_data != count){
printf("read back not correct %d, %d \n\r", rd_data, count);
}
usleep(1000000);
count++;
}
cleanup_platform();
return 0;
}
MiniZed Slave
MiniZed Slave 使用 PS 模块为逻辑设计提供时钟。协议从站连接一个 BRAM,该 BRAM 存储通过通信链路提供的数据。
MiniZed Slave 的这个实现不需要软件,只需要 Protocol Slave、UART 和 BRAM。与 MiniZed Master 一样,PS 为模块提供时钟。
普通 XDC
MiniZed Master 和 Slave 都使用 MiniZed 上的 Pmod 1 连接到 RS485 Pmod。因此,两者的 XDC 文件是相同的。
set_property IOSTANDARD LVCMOS33 [get_ports {re[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports de]
set_property IOSTANDARD LVCMOS33 [get_ports rx]
set_property IOSTANDARD LVCMOS33 [get_ports tx]
set_property PACKAGE_PIN L15 [get_ports {re[0]}]
set_property PACKAGE_PIN M14 [get_ports de]
set_property PACKAGE_PIN L14 [get_ports rx]
set_property PACKAGE_PIN M15 [get_ports tx]
为 RS485 总线接线
RS484 总线非常简单,但我们确实需要正确连接 Pmod,如 Digilent PmodRS485 参考指南中所示。
RS485 端子的两端需要用一个电阻端接,在 PmodRS485 上可以使用跳线安装或不安装。对于此应用,需要安装两个电阻器。
接线时,请小心为 Pmod 上的接收器连接回路。
硬件测试
使用在 MiniZed 主机上运行的软件应用程序,我们可以读取和写入 MiniZed 从机中的 BRAM 内存。然而,要了解它是如何工作的,我们最好通过查看总线上的波形来学习
逻辑 TX 引脚上来自主机的写入传输如下所示
相应的总线端如下所示 - 请注意末尾的 0x06 是确认。
主机上的逻辑 RX 信号上的 RX 引脚显示写入和写入确认。MiniZed Master 和 Slave 的设计都永久启用了 RX
从 MiniZed Slave 读取的数据如下所示,其中数据表示由 MiniZed Master 写入的递增计数。
在下面的波形中,可以在读取响应之前在总线侧观察到读取请求。
TX 启用相对于 TX 数据的时序如下所示,请注意我们如何在预期回复时禁用 TX 路径。
探测 MiniZed Master 和 Slave 上的不同 TX 使能显示了
结论
FPGA 为许多工业应用提供了很好的解决方案,该项目展示了使用常用工业接口连接不同板和传输数据是多么容易。在这个应用程序中,数据速率为 1Mb/s,可以实现高达 16Mb/s 或更快的线速率!
* 以上内容翻译自网络,原作者:亚当泰勒,如涉及侵权可联系删除。
本文转载自:电路城