16路串口光纤通信FPGA项目实现指南 - 第二部分(上)

16路串口光纤通信FPGA项目实现指南 - 第二部分(上)

四、Aurora通信接口实现

4.1 Aurora顶层模块设计

文件位置uart_fiber.srcs/sources_1/new/aurora_top.v

module aurora_top(
    input           init_clk,        // 初始化时钟(通常为50MHz)
    output          user_clk_i,      // Aurora用户时钟输出
    output          CHANNEL_UP,      // Aurora通道建立状态
    input           RESET,           // 复位信号
    input           GT_RESET_IN,     // GTX收发器复位信号
    input [15:0]    uart_rx,         // 16路串口接收数据
    output [15:0]   uart_tx,         // 16路串口发送数据
    input           GTPQ0_P,         // 光纤时钟正端
    input           GTPQ0_N,         // 光纤时钟负端
    input           RXP,             // 光纤接收正端
    input           RXN,             // 光纤接收负端
    output          TXP,             // 光纤发送正端
    output          TXN              // 光纤发送负端
);
语法说明:
  • input/output:定义模块的输入输出端口。
  • [15:0]:16位总线,表示16路数据。

4.1.1 信号声明
// Aurora AXI-Stream发送接口信号
wire [15:0] tx_tdata_i;   // 发送数据
wire        tx_tvalid_i;  // 发送数据有效
wire        tx_tready_i;  // 发送数据就绪
wire  [1:0] tx_tkeep_i;   // 发送数据保持
wire        tx_tlast_i;   // 发送数据最后

// Aurora AXI-Stream接收接口信号
wire [15:0] rx_tdata_i;   // 接收数据
wire        rx_tvalid_i;  // 接收数据有效
wire  [1:0] rx_tkeep_i;   // 接收数据保持
wire        rx_tlast_i;   // 接收数据最后
语法说明:
  • wire:声明连线信号,适用于组合逻辑。
  • [15:0]:16位宽度,适合并行数据。

4.2 Aurora IP核实例化

// Aurora 8B/10B IP核实例化
// 该IP核负责底层光纤协议的收发和时钟管理
// 只需连接好接口信号即可,无需关心内部实现

aurora_8b10b_0_exdes inst_aurora_8b10b_0_exdes (
    .clk_50m(init_clk),             // 50MHz时钟输入
    .RESET(RESET),                  // 复位信号
    .GT_RESET_IN(GT_RESET_IN),      // GTX收发器复位
    .CHANNEL_UP(CHANNEL_UP),        // 通道建立状态输出
    .GTPQ0_P(GTPQ0_P),              // 光纤时钟正端
    .GTPQ0_N(GTPQ0_N),              // 光纤时钟负端
    .RXP(RXP),                      // 光纤接收正端
    .RXN(RXN),                      // 光纤接收负端
    .TXP(TXP),                      // 光纤发送正端
    .TXN(TXN),                      // 光纤发送负端
    .user_clk_i(user_clk_i),        // Aurora用户时钟输出
    .tx_tdata_i(tx_tdata_i),        // 发送数据
    .tx_tvalid_i(tx_tvalid_i),      // 发送数据有效
    .tx_tready_i(tx_tready_i),      // 发送数据就绪
    .tx_tkeep_i(tx_tkeep_i),        // 发送数据保持
    .tx_tlast_i(tx_tlast_i),        // 发送数据最后
    .rx_tdata_i(rx_tdata_i),        // 接收数据
    .rx_tvalid_i(rx_tvalid_i),      // 接收数据有效
    .rx_tkeep_i(rx_tkeep_i),        // 接收数据保持
    .rx_tlast_i(rx_tlast_i)         // 接收数据最后
);
语法说明:
  • inst_aurora_8b10b_0_exdes:IP核实例名。
  • .端口名(信号名):将模块端口与外部信号连接。

4.3 控制模块实例化

// Aurora控制模块实例化
// 负责数据缓存、状态机、FIFO、协议转换等核心控制逻辑

aurora_ctrl_mod inst_aurora_ctrl_mod (
    .proc_clk(init_clk),            // 处理时钟
    .user_clk_i(user_clk_i),        // Aurora用户时钟
    .rst(RESET),                    // 复位信号
    .CHANNEL_UP(CHANNEL_UP),        // 通道建立状态
    .uart_rx(uart_rx),              // 16路串口接收
    .uart_tx(uart_tx),              // 16路串口发送
    .tx_tdata_i(tx_tdata_i),        // 发送数据
    .tx_tvalid_i(tx_tvalid_i),      // 发送数据有效
    .tx_tkeep_i(tx_tkeep_i),        // 发送数据保持
    .tx_tlast_i(tx_tlast_i),        // 发送数据最后
    .tx_tready_i(tx_tready_i),      // 发送数据就绪
    .rx_tdata_i(rx_tdata_i),        // 接收数据
    .rx_tvalid_i(rx_tvalid_i),      // 接收数据有效
    .rx_tkeep_i(rx_tkeep_i),        // 接收数据保持
    .rx_tlast_i(rx_tlast_i)         // 接收数据最后
);
语法说明:
  • 控制模块负责数据流的缓存、同步、协议转换和状态管理。
  • 通过AXI-Stream接口与Aurora IP核通信。

五、核心控制逻辑实现(发送部分)

5.1 控制模块接口定义

文件位置uart_fiber.srcs/sources_1/new/aurora_ctrl_mod.v

module aurora_ctrl_mod #(
    parameter D_WIDTH = 16          // 数据宽度参数,默认16位
) (
    // 系统接口
    input proc_clk,                 // 处理时钟(如50MHz)
    input user_clk_i,               // Aurora用户时钟
    input CHANNEL_UP,               // 通道建立状态
    input rst,                      // 复位信号
    // 串口接口
    input [15:0] uart_rx,           // 16路串口接收
    output reg [15:0] uart_tx,      // 16路串口发送
    // Aurora发送接口
    output [D_WIDTH-1:0] tx_tdata_i,    // 发送数据
    output tx_tvalid_i,                 // 发送数据有效
    output [1:0] tx_tkeep_i,            // 发送数据保持
    output tx_tlast_i,                  // 发送数据最后
    input tx_tready_i,                  // 发送数据就绪
    // Aurora接收接口
    input [D_WIDTH-1:0] rx_tdata_i,     // 接收数据
    input rx_tvalid_i,                  // 接收数据有效
    input [1:0] rx_tkeep_i,             // 接收数据保持
    input rx_tlast_i                    // 接收数据最后
);
语法说明:
  • parameter:参数化模块,便于扩展。
  • output reg:可赋值的输出端口。

5.2 数据寄存与时钟域同步

// 串口接收数据寄存器
reg [15:0] uart_rx_reg;
always@(posedge proc_clk) begin
    uart_rx_reg <= uart_rx; // 将输入串口数据寄存,防止亚稳态
end

// 通道状态时钟域同步FIFO
wire channel_up_reg;
fifo_onebit inst_fifo_channelup (
    .wr_clk(user_clk_i),    // 写时钟(Aurora时钟域)
    .rd_clk(proc_clk),      // 读时钟(处理时钟域)
    .din(CHANNEL_UP),       // 通道状态数据
    .wr_en(1'b1),           // 写使能,始终有效
    .rd_en(1'b1),           // 读使能,始终有效
    .dout(channel_up_reg),  // 同步后的通道状态
    .full(),                // 未用
    .empty()                // 未用
);
语法说明:
  • always@(posedge clk):时序逻辑,时钟上升沿触发。
  • fifo_onebit:单比特FIFO,用于跨时钟域同步。

5.3 数据发送控制逻辑

5.3.1 写计数器与数据有效信号
reg [15:0] proc_wr_cnt;
always@(posedge proc_clk or posedge rst) begin
    if(rst)
        proc_wr_cnt <= 'b0; // 复位时清零
    else if(channel_up_reg) begin
        if(proc_wr_cnt == 16'hffff)
            proc_wr_cnt <= proc_wr_cnt; // 保持最大值
        else
            proc_wr_cnt <= proc_wr_cnt + 1'b1; // 递增
    end else 
        proc_wr_cnt <= 'b0; // 通道未建立时清零
end
assign rs422_in_valid = (proc_wr_cnt == 16'hffff) ? 1'b1 : 1'b0; // 计数器满时产生数据有效信号
语法说明:
  • assign:组合逻辑赋值。
  • 16'hffff:16位全1,最大值。

5.3.2 发送FIFO实例化
// 发送FIFO用于缓存串口数据,实现跨时钟域传输
aurora_tx_rs422_fifo inst_rs422_fifo (
    .rst(rst),
    .wr_clk(proc_clk),
    .rd_clk(user_clk_i),
    .din(uart_rx_reg),
    .wr_en(rs422_in_valid),
    .rd_en(rs422_tx_fifo_rden),
    .dout(rs422_tx_fifo_dout),
    .full(rs422_tx_fifo_full),
    .empty(rs422_tx_fifo_empty),
    .prog_empty(rs422_tx_fifo_prog_empty)
);
语法说明:
  • .wr_clk/.rd_clk:写/读时钟,实现跨时钟域。
  • .din/.dout:数据输入/输出。
  • .wr_en/.rd_en:写/读使能。

5.3.3 发送状态机
reg [1:0] state;      // 状态机状态
reg [15:0] rd_count;  // 读计数器
reg rd_valid_enable;  // 读有效使能

always @ (posedge user_clk_i or posedge rst) begin
    if(rst) begin
        state <= 'b0;
        rd_valid_enable <= 'b0;
        rd_count <= 2'd0;
    end else if(CHANNEL_UP) begin
        case(state)
            2'd0 : begin // 等待FIFO有数据
                if((!rs422_tx_fifo_prog_empty)) begin
                    state <= 2'd1;
                    rd_valid_enable <= 1'b0;
                    rd_count <= 'b0;
                end else begin
                    state <= 'b0;
                    rd_valid_enable <= 1'b0;
                    rd_count <= 'b0;
                end
            end        
            2'd1 : begin // 发送数据
                if(rs422_tx_fifo_rden) begin
                    if(rd_count == 16'd511) begin
                        state <= 2'd0;
                        rd_valid_enable <= 1'b0;
                        rd_count <= 'b0;
                    end else begin
                        state <= 2'd1;
                        rd_valid_enable <= 1'b1;
                        rd_count <= rd_count + rs422_tx_fifo_rden;
                    end
                end else begin
                    state <= 2'd1;
                    rd_valid_enable <= 1'b1;
                    rd_count <= rd_count + rs422_tx_fifo_rden;
                end                        
            end                
        endcase                              
    end else begin
        state <= 'b0;
        rd_valid_enable <= 'b0;
        rd_count <= 2'd0;
    end
end
语法说明:
  • case:多路分支,状态机常用。
  • 2'd0/2'd1:2位二进制数。
  • rd_valid_enable:控制FIFO读使能。

5.3.4 发送接口信号赋值
assign tx_tlast_i = ((rs422_tx_fifo_rden && rd_count == 511) ? 1 : 0);  // 最后一个数据包标志
assign rs422_tx_fifo_rden = tx_tready_i && (!rs422_tx_fifo_empty) && rd_valid_enable;  // FIFO读使能条件
assign tx_tvalid_i = rs422_tx_fifo_rden;             // 发送数据有效信号
assign tx_tdata_i = rs422_tx_fifo_dout;              // 发送数据
assign tx_tkeep_i = 2'h3;                            // 发送数据保持信号(全有效)
语法说明:
  • tx_tlast_i:AXI-Stream协议最后数据包标志。
  • tx_tkeep_i:数据字节有效掩码,2位全1表示16位全有效。

请查看“项目实现指南-第二部分-下.md”继续阅读:包括数据接收控制、调试功能、项目总结与技术亮点。

你可能感兴趣的:(FPGA,fpga开发)