edu网站开发,哪些h5网站比较好,网站开发质保,wordpress主题底部功能简介 串行通信接口常常用于在计算机和低速外部设备之间传输数据。串口通信存在多种标准#xff0c;以RS422为例#xff0c;它将数据分成多个位#xff0c;采用异步通信方式进行传输。 本文基于Xilinx VCU128 FPGA开发板#xff0c;对RS422串口通信进行学习。 根…功能简介 串行通信接口常常用于在计算机和低速外部设备之间传输数据。串口通信存在多种标准以RS422为例它将数据分成多个位采用异步通信方式进行传输。 本文基于Xilinx VCU128 FPGA开发板对RS422串口通信进行学习。 根据用户手册ug1302128中采用了一款来自未来科技(Future Technology Devices International Ltd.的USB转UART的芯片FT4232HL芯片手册。 FT4232HL芯片能够将USB接口转化为4个串口通道并支持配置4个串口通道为不同类型的串口协议根据FT4232HL芯片手册P10可以看到在配置为RS422模式下串口通道各引脚功能如下 在实际使用中Xilinx配置芯片的通道A为JTAG模式用于JTAG调试链通道B与通道C用于UART串口通信通道D用于SYSCTLR。其中通道B、C仅引出了TXD、RXD、RTS_n、CTS_n四根引脚。其中通道C的TXD、RXD的引脚位置可通过如下约束获取
set_property BOARD_PART_PIN USB_UART1_TX [get_ports channel_tx]
set_property BOARD_PART_PIN USB_UART1_RX [get_ports channel_rx]SystemVerilog实现ft4232hl_uart.sv 根据422协议规定编写串口接收代码如下主要功能包括
采用偶校验、1停止位、8数据位。采样采用mmcm产生的400MHz时钟800MHz时ila存在时序违例采样串口接收到的数据时采取多次采样方式即总样本里超过75%为1则为1少于25%为1则为0。vio用于将采样次数适配到串口波特率由于采样时钟为400MHz当需要波特率为115200bps时需要vio设置采样次数为3472。ila用于抓取串口接收到的字节数据、以及是否存在错误无停止位错误、校验位错误、采样结果不确定错误。
timescale 1ns / 1ps
//
// Company:
// Engineer: wjh776a68
//
// Create Date: 03/15/2024 07:45:09 PM
// Design Name:
// Module Name: ft4232hl_uart
// Project Name:
// Target Devices: XCVU37P
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
////
//
// https://ftdichip.com/wp-content/uploads/2020/08/DS_FT4232H.pdf
// P15 signals difinition
//
// module ft4232hl_uart(input logic default_clk_p ,input logic default_clk_n ,input logic reset ,input logic channel_rx ,output logic channel_tx
// input logic channel_rts_n ,
// output logic channel_cts_n
);// assign channel_cts_n 1;logic clk_100MHz;IBUFDS #(.DIFF_TERM(FALSE), // Differential Termination.IBUF_LOW_PWR(TRUE), // Low powerTRUE, Highest performanceFALSE .IOSTANDARD(DEFAULT) // Specify the input I/O standard) IBUFDS_inst (.O(clk_100MHz), // Buffer output.I(default_clk_p), // Diff_p buffer input (connect directly to top-level port).IB(default_clk_n) // Diff_n buffer input (connect directly to top-level port));logic mmcm_fbclk_s;logic mmcm_locked_s;logic clk_800MHz;MMCME4_BASE #(.BANDWIDTH(OPTIMIZED), // Jitter programming.CLKFBOUT_MULT_F(8.0), // Multiply value for all CLKOUT.CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB.CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution (i.e., 33.333 is 30 MHz)..CLKOUT0_DIVIDE_F(2.0), // Divide amount for CLKOUT0.CLKOUT0_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT0.CLKOUT0_PHASE(0.0), // Phase offset for CLKOUT0.CLKOUT1_DIVIDE(1), // Divide amount for CLKOUT (1-128).CLKOUT1_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT1_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000)..CLKOUT2_DIVIDE(1), // Divide amount for CLKOUT (1-128).CLKOUT2_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT2_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000)..CLKOUT3_DIVIDE(1), // Divide amount for CLKOUT (1-128).CLKOUT3_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT3_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000)..CLKOUT4_CASCADE(FALSE), // Divide amount for CLKOUT (1-128).CLKOUT4_DIVIDE(1), // Divide amount for CLKOUT (1-128).CLKOUT4_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT4_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000)..CLKOUT5_DIVIDE(1), // Divide amount for CLKOUT (1-128).CLKOUT5_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT5_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000)..CLKOUT6_DIVIDE(1), // Divide amount for CLKOUT (1-128).CLKOUT6_DUTY_CYCLE(0.5), // Duty cycle for CLKOUT outputs (0.001-0.999)..CLKOUT6_PHASE(0.0), // Phase offset for CLKOUT outputs (-360.000-360.000)..DIVCLK_DIVIDE(1), // Master division value.IS_CLKFBIN_INVERTED(1b0), // Optional inversion for CLKFBIN.IS_CLKIN1_INVERTED(1b0), // Optional inversion for CLKIN1.IS_PWRDWN_INVERTED(1b0), // Optional inversion for PWRDWN.IS_RST_INVERTED(1b0), // Optional inversion for RST.REF_JITTER1(0.0), // Reference input jitter in UI (0.000-0.999)..STARTUP_WAIT(FALSE) // Delays DONE until MMCM is locked)MMCME4_BASE_inst (.CLKFBOUT(mmcm_fbclk_s), // 1-bit output: Feedback clock pin to the MMCM.CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT.CLKOUT0(clk_800MHz), // 1-bit output: CLKOUT0.CLKOUT0B(), // 1-bit output: Inverted CLKOUT0.CLKOUT1(), // 1-bit output: CLKOUT1.CLKOUT1B(), // 1-bit output: Inverted CLKOUT1.CLKOUT2(), // 1-bit output: CLKOUT2.CLKOUT2B(), // 1-bit output: Inverted CLKOUT2.CLKOUT3(), // 1-bit output: CLKOUT3.CLKOUT3B(), // 1-bit output: Inverted CLKOUT3.CLKOUT4(), // 1-bit output: CLKOUT4.CLKOUT5(), // 1-bit output: CLKOUT5.CLKOUT6(), // 1-bit output: CLKOUT6.LOCKED(mmcm_locked_s), // 1-bit output: LOCK.CLKFBIN(mmcm_fbclk_s), // 1-bit input: Feedback clock pin to the MMCM.CLKIN1(clk_100MHz), // 1-bit input: Primary clock.PWRDWN(1b0), // 1-bit input: Power-down.RST(reset) // 1-bit input: Reset);// clk_800MHzlogic channel_rx_d1_r 0, channel_rx_d2_r 0, channel_rx_d3_r 0;always_ff (posedge clk_800MHz) beginchannel_rx_d3_r channel_rx_d2_r;channel_rx_d2_r channel_rx_d1_r;channel_rx_d1_r channel_rx;endlogic [31:0] cfg_datarate_i; logic cfg_datafresh_i; logic [31:0] cfg_datarate_r 0; logic [31:0] cfg_datarate_sub1_r 0; logic [31:0] cfg_datarate_sub2_r 0; logic [31:0] cfg_datarate_m3d4_r 0; logic [31:0] cfg_datarate_m1d4_r 0; logic cfg_datafresh_r 0; vio_0 vio_0_inst (.clk(clk_800MHz), // input wire clk.probe_out0(cfg_datafresh_i), // output wire [0 : 0] probe_out0.probe_out1(cfg_datarate_i) // output wire [31 : 0] probe_out1);logic startbit_detected_s;assign startbit_detected_s channel_rx_d3_r ~channel_rx_d2_r;ila_0 ila_uartio_inst (.clk(clk_800MHz), // input wire clk.probe0(channel_rx_d3_r), // input wire [0:0] probe0 .probe1(state_r), // input wire [7:0] probe1 .probe2(channel_tx) // input wire [0:0] probe2);enum logic[5:0] {RESET ,IDLE ,GET_STARTBIT ,GET_DATA ,GET_PARITY ,GET_STOPBIT } state_r, state_s;logic [2:0] rx_getdata_cnt_r;logic [7:0] rx_data_r;logic rx_valid_r;logic rx_error_flag_s;logic parity_error_flag_r;logic undetect_error_flag_r;logic nostop_error_flag_r;assign rx_error_flag_s parity_error_flag_r | undetect_error_flag_r | nostop_error_flag_r;always_ff (posedge clk_800MHz) beginif (reset)state_r RESET;elsestate_r state_s;endlogic next_state_flag_r;logic capture_value_r;always_comb begincase (state_r)RESET: state_s IDLE;IDLE: beginif (startbit_detected_s)state_s GET_STARTBIT;elsestate_s IDLE;endGET_STARTBIT: beginif (next_state_flag_r) beginif (~capture_value_r)state_s GET_DATA;elsestate_s IDLE;end else beginstate_s GET_STARTBIT;endendGET_DATA: beginif (next_state_flag_r rx_getdata_cnt_r 0) state_s GET_PARITY;elsestate_s GET_DATA;endGET_PARITY: beginif (next_state_flag_r)state_s GET_STOPBIT;elsestate_s GET_PARITY;endGET_STOPBIT: beginif (next_state_flag_r)if (startbit_detected_s)state_s GET_STARTBIT;elsestate_s IDLE;elsestate_s GET_STOPBIT;enddefault: state_s IDLE;endcaseendlogic [31:0] capture_asserted_cnt_r d0;logic [31:0] capture_total_cnt_r d0;logic cnt_fresh_s;assign cnt_fresh_s (capture_total_cnt_r cfg_datarate_sub1_r) ? 1b1 : 1b0;always_ff (posedge clk_800MHz) begincase (state_s)IDLE: begincapture_asserted_cnt_r d0;enddefault: beginif (cnt_fresh_s)capture_asserted_cnt_r d0;else if (channel_rx_d3_r)capture_asserted_cnt_r capture_asserted_cnt_r d1;endendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)IDLE: begincapture_total_cnt_r d0;enddefault: beginif (cnt_fresh_s)capture_total_cnt_r d0;else capture_total_cnt_r capture_total_cnt_r d1;endendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)RESET, IDLE: beginrx_valid_r 1b0;end GET_STOPBIT: beginif (capture_total_cnt_r cfg_datarate_sub1_r) beginrx_valid_r 1b1;endendendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)RESET, IDLE: beginnostop_error_flag_r 1b0;end GET_STOPBIT: beginif (capture_total_cnt_r cfg_datarate_sub1_r) beginif (~capture_value_r) beginnostop_error_flag_r 1b1;endendendendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)RESET, IDLE: beginundetect_error_flag_r 1b0;end GET_STARTBIT, GET_DATA, GET_PARITY, GET_STOPBIT: beginif (capture_total_cnt_r cfg_datarate_sub1_r) beginif (capture_asserted_cnt_r cfg_datarate_m3d4_r) begin// undetect_error_flag_r 1b0;end else if (capture_asserted_cnt_r cfg_datarate_m1d4_r) begin// undetect_error_flag_r 1b0;end else beginundetect_error_flag_r 1b1;endendendendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)RESET: beginparity_error_flag_r 1b0;endGET_PARITY: beginif (capture_total_cnt_r cfg_datarate_sub1_r) beginif (capture_value_r ^rx_data_r[7:0]) beginparity_error_flag_r 1b0;end else beginparity_error_flag_r 1b1;endendendendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)IDLE: beginnext_state_flag_r 1b0;end default: beginif (capture_total_cnt_r cfg_datarate_sub1_r) beginnext_state_flag_r 1b1;end else if (capture_total_cnt_r 0) beginnext_state_flag_r 1b0;endendendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)IDLE: begincapture_value_r 1b0;end default: beginif (capture_total_cnt_r cfg_datarate_sub2_r) beginif (capture_asserted_cnt_r cfg_datarate_m3d4_r) begincapture_value_r 1b1;end else if (capture_asserted_cnt_r cfg_datarate_m1d4_r) begincapture_value_r 1b0;endendendendcaseendalways_ff (posedge clk_800MHz) begincase (state_s)GET_DATA: beginif (capture_total_cnt_r cfg_datarate_sub1_r) beginrx_getdata_cnt_r rx_getdata_cnt_r d1;rx_data_r[rx_getdata_cnt_r] capture_value_r;endend default: beginrx_getdata_cnt_r 3d0;endendcaseendila_0 ila_0_inst (.clk(clk_800MHz), // input wire clk.probe0(rx_valid_r), // input wire [0:0] probe0 .probe1(rx_data_r), // input wire [7:0] probe1 .probe2(rx_error_flag_s) // input wire [0:0] probe2); 串口发送模块的代码如下它将收到的未检测出错误的数据转发给主机。
enum logic [5:0] {TX_RESET ,TX_IDLE ,TX_SEND_STARTBIT ,TX_SEND_DATABIT ,TX_SEND_PARITYBIT ,TX_SEND_STOPBIT} send_state_r, send_state_s;always_ff (posedge clk_800MHz) beginif (reset) beginsend_state_r TX_RESET;end else beginsend_state_r send_state_s;endendlogic send_nextstate_r;logic [2:0] tx_senddata_cnt_r;logic [7:0] tx_data_r;logic tx_valid_r;always_comb begincase (send_state_r)TX_RESET: send_state_s TX_IDLE;TX_IDLE: beginif (tx_valid_r) send_state_s TX_SEND_STARTBIT;elsesend_state_s TX_IDLE;endTX_SEND_STARTBIT: beginif (send_nextstate_r) beginsend_state_s TX_SEND_DATABIT;end else beginsend_state_s TX_SEND_STARTBIT;endendTX_SEND_DATABIT: beginif (send_nextstate_r tx_senddata_cnt_r 3d0) beginsend_state_s TX_SEND_PARITYBIT;end else beginsend_state_s TX_SEND_DATABIT;endendTX_SEND_PARITYBIT: beginif (send_nextstate_r) beginsend_state_s TX_SEND_STOPBIT;end else beginsend_state_s TX_SEND_PARITYBIT;endendTX_SEND_STOPBIT: beginif (send_nextstate_r) beginif (tx_valid_r) beginsend_state_s TX_SEND_STARTBIT;end else beginsend_state_s TX_IDLE;endend else beginsend_state_s TX_SEND_STOPBIT;endenddefault: send_state_s TX_RESET;endcaseendalways_ff (posedge clk_800MHz) begincase (send_state_s)TX_IDLE, TX_SEND_STOPBIT: beginif (rx_valid_r ~rx_error_flag_s) begintx_valid_r rx_valid_r;tx_data_r rx_data_r;end else if (~rx_valid_r tx_valid_r) begintx_valid_r 1b0;endendendcaseendalways_ff (posedge clk_800MHz) begincase (send_state_s)TX_IDLE, TX_SEND_STOPBIT: beginif (~rx_valid_r) begincfg_datafresh_r cfg_datafresh_i;if (cfg_datafresh_i) begincfg_datarate_r cfg_datarate_i;cfg_datarate_sub1_r cfg_datarate_i - 1;cfg_datarate_sub2_r cfg_datarate_i - 2;cfg_datarate_m3d4_r (cfg_datarate_i 1) (cfg_datarate_i 2);cfg_datarate_m1d4_r (cfg_datarate_i 2);endendendendcaseendlogic [31:0] sent_total_cnt_r;always_ff (posedge clk_800MHz) begincase (send_state_s)default: beginif (sent_total_cnt_r cfg_datarate_sub1_r) beginsend_nextstate_r 1b1;end else beginsend_nextstate_r 1b0;endendTX_IDLE: beginendendcaseendalways_ff (posedge clk_800MHz) begincase (send_state_s)default: beginif (sent_total_cnt_r cfg_datarate_sub1_r) beginsent_total_cnt_r d0;end else beginsent_total_cnt_r sent_total_cnt_r 1;endendTX_IDLE: sent_total_cnt_r d0;endcaseendalways_ff (posedge clk_800MHz) begincase (send_state_s)TX_RESET, TX_IDLE, TX_SEND_STOPBIT: channel_tx 1b1;TX_SEND_STARTBIT: channel_tx 1b0;TX_SEND_DATABIT: channel_tx tx_data_r[tx_senddata_cnt_r];TX_SEND_PARITYBIT: channel_tx ^tx_data_r[7:0];endcaseendalways_ff (posedge clk_800MHz) begincase (send_state_s)TX_SEND_STARTBIT: begintx_senddata_cnt_r 3d0;endTX_SEND_DATABIT: beginif (sent_total_cnt_r cfg_datarate_sub1_r) begintx_senddata_cnt_r tx_senddata_cnt_r 1;endendendcaseend
endmodule约束文件实现ft4232hl_uart.xdc 对应约束文件如下
set_property BOARD_PART_PIN default_100mhz_clk_p [get_ports default_clk_p]
set_property BOARD_PART_PIN default_100mhz_clk_n [get_ports default_clk_n]
set_property BOARD_PART_PIN CPU_RESET [get_ports reset]
set_property BOARD_PART_PIN USB_UART1_TX [get_ports channel_tx]
set_property BOARD_PART_PIN USB_UART1_RX [get_ports channel_rx]
set_property BOARD_PART_PIN USB_UART1_CTS [get_ports channel_cts]
set_property BOARD_PART_PIN USB_UART1_RTS [get_ports channel_rts]# auto generate
set_property IOSTANDARD DIFF_SSTL12 [get_ports default_clk_p]
set_property IOSTANDARD DIFF_SSTL12 [get_ports default_clk_n]
set_property PACKAGE_PIN BH51 [get_ports default_clk_p]
set_property PACKAGE_PIN BJ51 [get_ports default_clk_n]
set_property IOSTANDARD LVCMOS12 [get_ports reset]
set_property PACKAGE_PIN BM29 [get_ports reset]
set_property IOSTANDARD LVCMOS18 [get_ports channel_tx]
set_property PACKAGE_PIN BN26 [get_ports channel_tx]
set_property IOSTANDARD LVCMOS18 [get_ports channel_rx]
set_property PACKAGE_PIN BP26 [get_ports channel_rx]# STA constraint
create_clock -period 10.000 -waveform {0.000 5.000} [get_ports default_clk_p]
create_generated_clock -source [get_ports default_clk_p] -divide_by 1 [get_pins IBUFDS_inst/O]
# create_clock -period 2.500 -waveform {0.000 1.250} [get_pins MMCME4_BASE_inst/CLKOUT0]set_property C_CLK_INPUT_FREQ_HZ 300000000 [get_debug_cores dbg_hub]
set_property C_ENABLE_CLK_DIVIDER false [get_debug_cores dbg_hub]
set_property C_USER_SCAN_CHAIN 1 [get_debug_cores dbg_hub]
connect_debug_port dbg_hub/clk [get_nets clk_800MHz_BUFG]仿真文件实现ft4232hl_uart_tb.sv
timescale 1ns / 1ps
//
// Company:
// Engineer: wjh776a68
//
// Create Date: 03/15/2024 10:35:44 PM
// Design Name:
// Module Name: ft4232hl_uart_tb
// Project Name:
// Target Devices: XCVU37P
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//module ft4232hl_uart_tb();bit clk_100MHz ;logic reset ;bit channel_rx 1b0;logic channel_tx ;always #5 clk_100MHz ~clk_100MHz;ft4232hl_uart ft4232hl_uart_inst(.default_clk_p (clk_100MHz),.default_clk_n (~clk_100MHz),.reset (reset ),.channel_rx (channel_rx),.channel_tx (channel_tx));initial beginft4232hl_uart_inst.cfg_datafresh_i 1b0;ft4232hl_uart_inst.cfg_datarate_i 0;(posedge ft4232hl_uart_inst.mmcm_locked_s);ft4232hl_uart_inst.cfg_datafresh_i 1b1;ft4232hl_uart_inst.cfg_datarate_i 217;(posedge clk_100MHz);ft4232hl_uart_inst.cfg_datafresh_i 1b0;ft4232hl_uart_inst.cfg_datarate_i 0;endbit clk_1_8432MHz ;bit [2:0] cnt;always #(500 / 1.8432) clk_1_8432MHz ~clk_1_8432MHz;initial beginreset 1b1;(posedge clk_1_8432MHz);reset 1b0;endenum logic [3:0] {IDLE 4d0 ,START_BIT 4d1 ,DATA_BIT 4d2 ,PARITY_BIT 4d3 ,STOP_BIT 4d4 } state_r, state_s;always_ff (posedge clk_1_8432MHz) beginif (reset) beginstate_r IDLE;end else beginstate_r state_s;endendlogic [4:0] idle_cnt;always_comb begincase (state_r)IDLE: beginif (idle_cnt 20) beginstate_s START_BIT;end else beginstate_s IDLE;endendSTART_BIT: state_s DATA_BIT;DATA_BIT: beginif (cnt 0)state_s PARITY_BIT;elsestate_s DATA_BIT;endPARITY_BIT: state_s STOP_BIT;STOP_BIT: beginstate_s START_BIT;// state_s IDLE;endendcaseendlogic [7:0] data_tosend 8h35;always_ff (posedge clk_1_8432MHz) begincase (state_s)IDLE: channel_rx 1b1;START_BIT: begincnt d0;channel_rx 1b0;endDATA_BIT: begincnt cnt 1;channel_rx data_tosend[cnt];endPARITY_BIT: beginchannel_rx ^data_tosend[7:0];endSTOP_BIT: beginchannel_rx 1b1;endendcaseendalways_ff (posedge clk_1_8432MHz) begincase (state_s)IDLE: idle_cnt idle_cnt 1;default: idle_cnt 0;endcaseendendmodule实机测试 由于是未来科技制造的芯片需要使用来自未来科技编写的VCP驱动程序将一个USB设备拓展为4个串口设备方能进行串口通信。 官方提供了多平台的驱动程序然而其中仅Windows驱动存在近期更新故本文串口通信测试在Windows虚拟机上进行。 参考链接
串口通讯UART/RS232/RS485/RS-422笔记俺也学不会FPGA的博客