参考

简易寄存器接口SMMR的vio_uart桥接.csdn
Verilog串口的寄存器访问模块–vio_uart.csdn
简易寄存器接口SMMR.csdn
高级外设总线APB.csdn
Tang-Nano-1K移植vio_uart
vio_uart的浏览器版上位机
嵌入式终端AtShell.csdn
树莓派Pico‌移植Atshell.csdn
嵌入式终端AtShell的精简版.csdn
基于rtdef.h的轻量级设备管理、终端、协程与应用管理框架设计.csdn
zynq的linux驱动版终端AtShellDrv.csdn

目的

用于实现verilog 版的print
接收命令用 按键 或 Verilog串口的寄存器访问模块–vio_uart.csdn

一个系统时钟向串口发送一个不定长的数据包
发送的内容 如下 (16进制)
每行为1个数据包,时间间隔为1个系统时钟
30 
31 
32 33
34 35 36 
37 38 39 40 
61 62 63 64 65 
66 67 68 69 70 71 
72 73 74 75 76 77 78

通用部分

axis_uart_sender.v

`timescale 1ns/1ps
module axis_uart_sender #(
    parameter P_CLK_FREQ   = 50_000_000,
    parameter P_UART_BPS   = 115200,
    parameter P_FIFO_DEPTH = 128
)(
    input               i_clk,
    input               i_rst_n,
    // AXI-Stream 输入
    input               s_axis_uart_tvalid,
    output              s_axis_uart_tready,
    input       [127:0] s_axis_uart_tdata,
    // UART TX
    output reg          o_uart_tx
);

    // 50MHz / 115200 ≈ 434
    localparam integer P_CLKS_PER_BIT = P_CLK_FREQ / P_UART_BPS;
    // UART bit 计数器宽度
    localparam integer P_CNT_WIDTH = $clog2(P_CLKS_PER_BIT + 1);

    // FIFO 地址宽度
    localparam integer P_FIFO_AW =$clog2(P_FIFO_DEPTH);


    // =========================================================================
    // FIFO
    // =========================================================================
    reg [7:0] r_fifo_mem [0:P_FIFO_DEPTH-1];
    // 写指针
    reg [P_FIFO_AW:0] r_fifo_wr_ptr;
    // 读指针
    reg [P_FIFO_AW:0] r_fifo_rd_ptr;
    // FIFO 数据数量
    wire [P_FIFO_AW:0] w_fifo_count;
    assign w_fifo_count = r_fifo_wr_ptr - r_fifo_rd_ptr;

    // FIFO 空
    wire w_fifo_empty;
    assign w_fifo_empty = (r_fifo_wr_ptr == r_fifo_rd_ptr);
    // FIFO 满
    wire w_fifo_full;
    assign w_fifo_full =(w_fifo_count >= P_FIFO_DEPTH);
    // =========================================================================
    // 写 FIFO 状态机
    // =========================================================================

    localparam [1:0]
        S_WR_IDLE = 2'd0,
        S_WR_DATA = 2'd1;
    reg [1:0] r_wr_state;

    // 整包数据寄存器
    reg [127:0] r_packet_data;
    // 当前包长度
    reg [4:0] r_packet_len;
    // 当前写第几个 byte
    reg [4:0] r_packet_index;

    // =========================================================================
    // AXIS READY
    // =========================================================================
    assign s_axis_uart_tready =(r_wr_state == S_WR_IDLE) && !w_fifo_full;
    // 当前需要写入 FIFO 的 byte
    reg [7:0] w_current_byte;

    always @(*) begin
        case (r_packet_index)
            5'd0:  w_current_byte = r_packet_data[119:112];
            5'd1:  w_current_byte = r_packet_data[111:104];
            5'd2:  w_current_byte = r_packet_data[103:96];
            5'd3:  w_current_byte = r_packet_data[95:88];
            5'd4:  w_current_byte = r_packet_data[87:80];
            5'd5:  w_current_byte = r_packet_data[79:72];
            5'd6:  w_current_byte = r_packet_data[71:64];
            5'd7:  w_current_byte = r_packet_data[63:56];
            5'd8:  w_current_byte = r_packet_data[55:48];
            5'd9:  w_current_byte = r_packet_data[47:40];
            5'd10: w_current_byte = r_packet_data[39:32];
            5'd11: w_current_byte = r_packet_data[31:24];
            5'd12: w_current_byte = r_packet_data[23:16];
            5'd13: w_current_byte = r_packet_data[15:8];
            5'd14: w_current_byte = r_packet_data[7:0];
            default: w_current_byte = 8'h00;
        endcase
    end


    //  FIFO 写入状态机
    always @(posedge i_clk or negedge i_rst_n) begin

        if (!i_rst_n) begin
            // 状态机
            r_wr_state <= S_WR_IDLE;
            // 整包数据
            r_packet_data <= 128'd0;
            // 数据长度
            r_packet_len <= 5'd0;
            // 当前 byte index
            r_packet_index <= 5'd0;
            // FIFO 写指针
            r_fifo_wr_ptr <= {(P_FIFO_AW + 1){1'b0}};
        end
        else begin
            case (r_wr_state)
                S_WR_IDLE: begin
                    // 等待 AXIS 数据
                    if (s_axis_uart_tvalid && s_axis_uart_tready) begin
                        // 锁存整个 128bit 数据
                        r_packet_data <= s_axis_uart_tdata;
                        // 锁存长度
                        r_packet_len <= s_axis_uart_tdata[127:120];
                        r_packet_index <= 5'd0;
                        // 判断长度
                        if ((s_axis_uart_tdata[127:120] != 8'd0) &&(s_axis_uart_tdata[127:120] <= 8'd15)) begin
                            r_wr_state <= S_WR_DATA;
                        end
                        else begin
                            // 无效长度,不写 FIFO
                            r_wr_state <= S_WR_IDLE;
                        end
                    end
                end
                // 拆包写 FIFO
                S_WR_DATA: begin
                    if (!w_fifo_full) begin
                        // 写入当前 byte
                        r_fifo_mem[ r_fifo_wr_ptr[P_FIFO_AW-1:0]] <= w_current_byte;
                        // FIFO 写指针 +1
                        r_fifo_wr_ptr <= r_fifo_wr_ptr + 1'b1;
                        // 判断是否已经写完这一包
                        if (r_packet_index ==(r_packet_len - 1'b1)) begin
                            // 当前包发送完毕
                            r_packet_index <= 5'd0;
                            r_wr_state <= S_WR_IDLE;
                        end
                        else begin
                            // 下一个 byte
                            r_packet_index <= r_packet_index + 1'b1;
                        end
                    end
                end
                default: begin
                    r_wr_state <= S_WR_IDLE;
                end
            endcase
        end
    end


    // =========================================================================
    // UART TX 状态机
    // =========================================================================

    localparam [2:0]
        S_TX_IDLE  = 3'd0,
        S_TX_START = 3'd1,
        S_TX_DATA  = 3'd2,
        S_TX_STOP  = 3'd3;

    // UART 状态
    reg [2:0] r_tx_state;
    // UART bit 计数器
    reg [P_CNT_WIDTH-1:0] r_tx_cnt;
    // 当前发送 bit
    reg [2:0] r_tx_bit_idx;
    // 当前 UART byte
    reg [7:0] r_tx_shift;
    // FIFO 读使能
    reg r_fifo_rd_en;


    // =========================================================================
    // FIFO 读指针
    // =========================================================================
    always @(posedge i_clk or negedge i_rst_n) begin
        if (!i_rst_n) begin
            r_fifo_rd_ptr <={(P_FIFO_AW + 1){1'b0}};
        end
        else begin
            if (r_fifo_rd_en) begin
                r_fifo_rd_ptr <= r_fifo_rd_ptr + 1'b1;
            end
        end
    end


    // =========================================================================
    // UART TX
    // =========================================================================

    always @(posedge i_clk or negedge i_rst_n) begin
        if (!i_rst_n) begin
            r_tx_state <= S_TX_IDLE;
            r_tx_cnt <={(P_CNT_WIDTH){1'b0}};
            r_tx_bit_idx <= 3'd0;
            r_tx_shift <= 8'h00;
            r_fifo_rd_en <= 1'b0;
            o_uart_tx <= 1'b1;
        end
        else begin
            // 默认不读 FIFO
            r_fifo_rd_en <= 1'b0;
            case (r_tx_state)
                S_TX_IDLE: begin
                    // UART 空闲为高
                    o_uart_tx <= 1'b1;
                    if (!w_fifo_empty) begin
                        //  取出 FIFO 当前 byte
                        r_tx_shift <=r_fifo_mem[r_fifo_rd_ptr[P_FIFO_AW-1:0]];
                        //FIFO 读指针前进
                        r_fifo_rd_en <= 1'b1;
                        r_tx_cnt <= {(P_CNT_WIDTH){1'b0}};
                        r_tx_state <= S_TX_START;
                    end
                end
                S_TX_START: begin
                    // START bit = 0
                    o_uart_tx <= 1'b0;
                    if (r_tx_cnt == P_CLKS_PER_BIT - 1) begin
                        r_tx_cnt <={(P_CNT_WIDTH){1'b0}};
                        r_tx_bit_idx <= 3'd0;
                        r_tx_state <= S_TX_DATA;
                    end
                    else begin
                        r_tx_cnt <= r_tx_cnt + 1'b1;
                    end

                end
                S_TX_DATA: begin
                    // UART LSB First
                    o_uart_tx <= r_tx_shift[r_tx_bit_idx];
                    if (r_tx_cnt == P_CLKS_PER_BIT - 1) begin
                        r_tx_cnt <= {(P_CNT_WIDTH){1'b0}};
                        if (r_tx_bit_idx == 3'd7) begin
                            // 8bit 数据发送完毕
                            r_tx_state <= S_TX_STOP;
                        end
                        else begin
                            // 下一个 bit
                            r_tx_bit_idx <= r_tx_bit_idx + 1'b1;
                        end
                    end
                    else begin
                        r_tx_cnt <= r_tx_cnt + 1'b1;
                    end
                end
                S_TX_STOP: begin
                    // STOP bit = 1
                    o_uart_tx <= 1'b1;
                    if (r_tx_cnt == P_CLKS_PER_BIT - 1) begin
                        r_tx_cnt <={(P_CNT_WIDTH){1'b0}};
                        // 当前 byte 发送完成
                        r_tx_state <= S_TX_IDLE;
                    end
                    else begin
                        r_tx_cnt <=r_tx_cnt + 1'b1;
                    end
                end
                //  异常恢复
                default: begin
                    r_tx_state <= S_TX_IDLE;
                    o_uart_tx <= 1'b1;
                end
            endcase
        end
    end
endmodule

key_debounce.v

module  key_debounce
#(
    parameter P_CLK_FREQ_MHZ = 50,  // 时钟频率,单位MHz,默认50MHz
    parameter P_DEBOUNCE_MS  = 20,   // 消抖时间,单位ms,默认20ms
    parameter L_CNT_WIDTH    = 32  // 需要外部计算后传入
)
(
    input   wire    i_clk     ,    //系统时钟50Mhz
    input   wire    i_rst_n   ,    //全局复位
    input   wire    i_key      ,   //按键输入信号
    output  reg     o_key_pulse    //消抖后的脉冲信号
);

// 根据时钟频率和消抖时间计算需要计数的最大值
localparam L_MAX_CNT = P_CLK_FREQ_MHZ * 1000 * P_DEBOUNCE_MS;
reg     [L_CNT_WIDTH-1:0]  r_cnt  ;

// ==================================================
//  r_cnt :记录按键按键的时间
// ==================================================
always@(posedge i_clk or negedge i_rst_n)
    if(i_rst_n == 1'b0)
        r_cnt <= {(L_CNT_WIDTH+1){1'b0}};
     //按键松开,计数器清零
    else if(i_key == 1)
        r_cnt <= {(L_CNT_WIDTH+1){1'b0}};
     //按键按下时,计数器计数
    else if(i_key == 1'b0 && r_cnt < L_MAX_CNT-1)
        r_cnt <= r_cnt + 1'b1;
    else
    //如果按键一直不释放,则r_cnt维持最大值,防止多次触发
        r_cnt <= r_cnt;

// ==================================================
//  o_key_pulse :输出脉冲信号,当按键稳定按下超过设定时间,输出一个时钟周期的脉冲
// ==================================================
always@(posedge i_clk or negedge i_rst_n)
    if(i_rst_n == 1'b0)
        o_key_pulse <= 1'b0;
     //计数快满时,产生一个时钟周期的脉冲,因为按住不松手时,计数器会维持在L_MAX_CNT-1
    else if(r_cnt ==  L_MAX_CNT-3)
        o_key_pulse <= 1'b1;
    else
        o_key_pulse <= 1'b0;
endmodule

不同板子

黑金AX301的 HC_FPGA_Demo_Top.v

`timescale 1ns/1ps

module HC_FPGA_Demo_Top
(
    input               CLOCK_XTAL_50MHz,
    input               RESET,
    input               KEY2,
    input               RXD,
    output              TXD
);

    // ============================================================
    // 参数
    // ============================================================

    localparam P_CLK_FREQ = 50_000_000;
    localparam P_UART_BPS = 115200;

    // ============================================================
    // 状态机
    // ============================================================
    localparam [2:0]
        S0 = 3'd0,
        S1 = 3'd1,
        S2 = 3'd2,
        S3 = 3'd3,
        S4 = 3'd4,
        S5 = 3'd5,
        S6 = 3'd6,
        S7 = 3'd7;

    // ============================================================
    // 内部信号
    // ============================================================
    wire         w_start;
    wire         m_axis_uart_tready;
    reg          m_axis_uart_tvalid;
    reg  [127:0] m_axis_uart_tdata;
    wire         w_uart_tx;
    reg  [2:0]   r_cur_state;


    // ============================================================
    // 按键消抖
    // ============================================================

    key_debounce u_key_debounce(
        .i_clk       (CLOCK_XTAL_50MHz),
        .i_rst_n     (RESET),
        .i_key       (KEY2),
        .o_key_pulse (w_start)
    );


    // ============================================================
    // UART Sender
    // ============================================================
    axis_uart_sender #(
        .P_CLK_FREQ   (P_CLK_FREQ),
        .P_UART_BPS   (P_UART_BPS),
        .P_FIFO_DEPTH (64)
    )
    u_axis_uart_sender
    (
        .i_clk       (CLOCK_XTAL_50MHz),
        .i_rst_n     (RESET),
        .s_axis_uart_tvalid    (m_axis_uart_tvalid),
        .s_axis_uart_tready    (m_axis_uart_tready),
        .s_axis_uart_tdata     (m_axis_uart_tdata),
        .o_uart_tx   (w_uart_tx)
    );

    assign TXD = w_uart_tx;

    // ============================================================
    // UART 发送一个字符
    // ============================================================
    task uart_put_char;
        input [7:0] char_data;
        begin
            m_axis_uart_tdata <= {
                8'd1,       // 长度 = 1
                char_data,  // 字符
                112'd0
            };
            m_axis_uart_tvalid <= 1'b1;
        end
    endtask

    // ============================================================
    // AXIS 数据发送状态机
    // ============================================================

    always @(posedge CLOCK_XTAL_50MHz or negedge RESET) begin

        if (!RESET) begin
            r_cur_state <= S0;
            m_axis_uart_tvalid    <= 1'b0;
            m_axis_uart_tdata     <= 128'd0;
        end
        else begin
            // ========================================================
            // m_axis_uart_tvalid 只有在握手完成之后才清零
            if (m_axis_uart_tvalid) begin
                if (m_axis_uart_tready) begin
                    // 当前数据已经被 uart_sender 接收
                    m_axis_uart_tvalid <= 1'b0;
                end
            end
            else begin
                // ====================================================
                // 当前没有待发送的数据
                // 如果按键按下:
                // 开始发送第一包
                // ====================================================
                case (r_cur_state)

                    // ------------------------------------------------
                    // 第一包
                    // 30
                    // ------------------------------------------------
                    S0: begin

                        if (w_start) begin
                            uart_put_char(8'h30);
                            r_cur_state <= S1;
                        end
                    end
                    // ------------------------------------------------
                    // 第二包
                    // 31
                    // ------------------------------------------------
                    S1: begin
                        uart_put_char(8'h31);
                        r_cur_state <= S2;
                    end
                    // ------------------------------------------------
                    // 第三包
                    // 32 33
                    // ------------------------------------------------
                    S2: begin
                        m_axis_uart_tdata <= {8'd2, 8'h32,8'h33,104'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S3;
                    end
                    // ------------------------------------------------
                    // 第四包
                    // 34 35 36
                    // ------------------------------------------------
                    S3: begin
                        m_axis_uart_tdata <= {8'd3,8'h34,8'h35,8'h36,96'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S4;
                    end


                    // ------------------------------------------------
                    // 第五包
                    // 37 38 39 40
                    // ------------------------------------------------
                    S4: begin
                        m_axis_uart_tdata <= { 8'd4, 8'h37, 8'h38, 8'h39,8'h40,88'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S5;
                    end
                    // ------------------------------------------------
                    // 第六包
                    // 61 62 63 64 65
                    // ------------------------------------------------
                    S5: begin
                        m_axis_uart_tdata <= {8'd5, 8'h61,8'h62,8'h63,8'h64,8'h65, 80'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S6;

                    end
                    // ------------------------------------------------
                    // 第七包
                    // 66 67 68 69 70 71
                    // ------------------------------------------------
                    S6: begin
                        m_axis_uart_tdata <= { 8'd6, 8'h66,8'h67,8'h68,8'h69,8'h70,8'h71, 72'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S7;
                    end
                    // ------------------------------------------------
                    // 第八包
                    // 72 73 74 75 76 77 78
                    // ------------------------------------------------
                    S7: begin
                        m_axis_uart_tdata <= { 8'd7,8'h72,8'h73,8'h74,8'h75,8'h76,8'h77,8'h78, 64'd0 };
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S0;
                    end
                    default: begin
                        r_cur_state <= S0;
                    end
                endcase
            end
        end
    end
endmodule

Tang-Nano-1K 的 TANG_FPGA_Demo_Top.v

module TANG_FPGA_Demo_Top
(
    input CLOCK_XTAL_27MHz,
	input RESET,
	input  KEY1,
    output TXD,
    output  [2:0] LED // 110 R, 101 B, 011 G
);

    reg[2:0] r_led;
    assign LED=r_led;
    localparam P_CLK_FREQ = 27_000_000;
    localparam P_UART_BPS = 115200;
    
    // ============================================================
    // 状态机
    // ============================================================
    localparam [2:0]
        S0 = 3'd0,
        S1 = 3'd1,
        S2 = 3'd2,
        S3 = 3'd3,
        S4 = 3'd4,
        S5 = 3'd5,
        S6 = 3'd6,
        S7 = 3'd7;

  
    // ============================================================
    // 内部信号
    // ============================================================
    wire         w_start;
    wire         m_axis_uart_tready;
    reg          m_axis_uart_tvalid;
    reg  [127:0] m_axis_uart_tdata;
    wire         w_uart_tx;
    reg  [2:0]   r_cur_state;


    // ============================================================
    // 按键消抖
    // ============================================================

    key_debounce#(
        .P_CLK_FREQ_MHZ(27)
    ) u_key_debounce(
        .i_clk       (CLOCK_XTAL_27MHz),
        .i_rst_n     (RESET),
        .i_key       (KEY1),
        .o_key_pulse (w_start)
    );


    // ============================================================
    // UART Sender
    // ============================================================
    axis_uart_sender #(
        .P_CLK_FREQ   (P_CLK_FREQ),
        .P_UART_BPS   (P_UART_BPS),
        .P_FIFO_DEPTH (64)
    )
    u_axis_uart_sender
    (
        .i_clk       (CLOCK_XTAL_27MHz),
        .i_rst_n     (RESET),
        .s_axis_uart_tvalid    (m_axis_uart_tvalid),
        .s_axis_uart_tready    (m_axis_uart_tready),
        .s_axis_uart_tdata     (m_axis_uart_tdata),
        .o_uart_tx   (w_uart_tx)
    );

    assign TXD = w_uart_tx;

    // ============================================================
    // UART 发送一个字符
    // ============================================================
    task uart_put_char;
        input [7:0] char_data;
        begin
            m_axis_uart_tdata <= {
                8'd1,       // 长度 = 1
                char_data,  // 字符
                112'd0
            };
            m_axis_uart_tvalid <= 1'b1;
        end
    endtask

    // ============================================================
    // AXIS 数据发送状态机
    // ============================================================

    always @(posedge CLOCK_XTAL_27MHz or negedge RESET) begin

        if (!RESET) begin
            r_led<=0;
            r_cur_state <= S0;
            m_axis_uart_tvalid    <= 1'b0;
            m_axis_uart_tdata     <= 128'd0;
        end
        else begin
            // ========================================================
            // m_axis_uart_tvalid 只有在握手完成之后才清零
            if (m_axis_uart_tvalid) begin
                if (m_axis_uart_tready) begin
                    // 当前数据已经被 uart_sender 接收
                    m_axis_uart_tvalid <= 1'b0;
                end
            end
            else begin
                // ====================================================
                // 当前没有待发送的数据
                // 如果按键按下:
                // 开始发送第一包
                // ====================================================
                case (r_cur_state)

                    // ------------------------------------------------
                    // 第一包
                    // 30
                    // ------------------------------------------------
                    S0: begin

                        if (w_start) begin
                            r_led<=~r_led;
                            uart_put_char(8'h30);
                            r_cur_state <= S1;
                        end
                    end
                    // ------------------------------------------------
                    // 第二包
                    // 31
                    // ------------------------------------------------
                    S1: begin
                        uart_put_char(8'h31);
                        r_cur_state <= S2;
                    end
                    // ------------------------------------------------
                    // 第三包
                    // 32 33
                    // ------------------------------------------------
                    S2: begin
                        m_axis_uart_tdata <= {8'd2, 8'h32,8'h33,104'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S3;
                    end
                    // ------------------------------------------------
                    // 第四包
                    // 34 35 36
                    // ------------------------------------------------
                    S3: begin
                        m_axis_uart_tdata <= {8'd3,8'h34,8'h35,8'h36,96'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S4;
                    end


                    // ------------------------------------------------
                    // 第五包
                    // 37 38 39 40
                    // ------------------------------------------------
                    S4: begin
                        m_axis_uart_tdata <= { 8'd4, 8'h37, 8'h38, 8'h39,8'h40,88'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S5;
                    end
                    // ------------------------------------------------
                    // 第六包
                    // 61 62 63 64 65
                    // ------------------------------------------------
                    S5: begin
                        m_axis_uart_tdata <= {8'd5, 8'h61,8'h62,8'h63,8'h64,8'h65, 80'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S6;

                    end
                    // ------------------------------------------------
                    // 第七包
                    // 66 67 68 69 70 71
                    // ------------------------------------------------
                    S6: begin
                        m_axis_uart_tdata <= { 8'd6, 8'h66,8'h67,8'h68,8'h69,8'h70,8'h71, 72'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S7;
                    end
                    // ------------------------------------------------
                    // 第八包
                    // 72 73 74 75 76 77 78
                    // ------------------------------------------------
                    S7: begin
                        m_axis_uart_tdata <= { 8'd7,8'h72,8'h73,8'h74,8'h75,8'h76,8'h77,8'h78, 64'd0 };
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S0;
                    end
                    default: begin
                        r_cur_state <= S0;
                    end
                endcase
            end
        end
    end


endmodule


IO_LOC "CLOCK_XTAL_27MHz" 47;
IO_PORT "CLOCK_XTAL_27MHz" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "RESET" 13;
IO_PORT "RESET" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "KEY1" 44;
IO_PORT "KEY1" IO_TYPE=LVCMOS33 PULL_MODE=UP;
IO_LOC "TXD" 40;
IO_PORT "TXD" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "LED[2]" 11;
IO_PORT "LED[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "LED[1]" 10;
IO_PORT "LED[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;
IO_LOC "LED[0]" 9;
IO_PORT "LED[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8;

正点原子领航者 ATK_FPGA_Demo_Top.v

`timescale 1ns/1ps

module ATK_FPGA_Demo_Top
(
    input               CLOCK_XTAL_50MHz,
    input               RESET,
    input               KEY,
    input               RXD,
    output              TXD
);

    // ============================================================
    // 参数
    // ============================================================

    localparam P_CLK_FREQ = 50_000_000;
    localparam P_UART_BPS = 115200;

    // ============================================================
    // 状态机
    // ============================================================
    localparam [2:0]
        S0 = 3'd0,
        S1 = 3'd1,
        S2 = 3'd2,
        S3 = 3'd3,
        S4 = 3'd4,
        S5 = 3'd5,
        S6 = 3'd6,
        S7 = 3'd7;

    // ============================================================
    // 内部信号
    // ============================================================
    wire         w_start;
    wire         m_axis_uart_tready;
    reg          m_axis_uart_tvalid;
    reg  [127:0] m_axis_uart_tdata;
    wire         w_uart_tx;
    reg  [2:0]   r_cur_state;


    // ============================================================
    // 按键消抖
    // ============================================================

    key_debounce u_key_debounce(
        .i_clk       (CLOCK_XTAL_50MHz),
        .i_rst_n     (RESET),
        .i_key       (KEY),
        .o_key_pulse (w_start)
    );


    // ============================================================
    // UART Sender
    // ============================================================
    axis_uart_sender #(
        .P_CLK_FREQ   (P_CLK_FREQ),
        .P_UART_BPS   (P_UART_BPS),
        .P_FIFO_DEPTH (64)
    )
    u_axis_uart_sender
    (
        .i_clk       (CLOCK_XTAL_50MHz),
        .i_rst_n     (RESET),
        .s_axis_uart_tvalid    (m_axis_uart_tvalid),
        .s_axis_uart_tready    (m_axis_uart_tready),
        .s_axis_uart_tdata     (m_axis_uart_tdata),
        .o_uart_tx   (w_uart_tx)
    );

    assign TXD = w_uart_tx;

    // ============================================================
    // UART 发送一个字符
    // ============================================================
    task uart_put_char;
        input [7:0] char_data;
        begin
            m_axis_uart_tdata <= {
                8'd1,       // 长度 = 1
                char_data,  // 字符
                112'd0
            };
            m_axis_uart_tvalid <= 1'b1;
        end
    endtask

    // ============================================================
    // AXIS 数据发送状态机
    // ============================================================

    always @(posedge CLOCK_XTAL_50MHz or negedge RESET) begin

        if (!RESET) begin
            r_cur_state <= S0;
            m_axis_uart_tvalid    <= 1'b0;
            m_axis_uart_tdata     <= 128'd0;
        end
        else begin
            // ========================================================
            // m_axis_uart_tvalid 只有在握手完成之后才清零
            if (m_axis_uart_tvalid) begin
                if (m_axis_uart_tready) begin
                    // 当前数据已经被 uart_sender 接收
                    m_axis_uart_tvalid <= 1'b0;
                end
            end
            else begin
                // ====================================================
                // 当前没有待发送的数据
                // 如果按键按下:
                // 开始发送第一包
                // ====================================================
                case (r_cur_state)

                    // ------------------------------------------------
                    // 第一包
                    // 30
                    // ------------------------------------------------
                    S0: begin

                        if (w_start) begin
                            uart_put_char(8'h30);
                            r_cur_state <= S1;
                        end
                    end
                    // ------------------------------------------------
                    // 第二包
                    // 31
                    // ------------------------------------------------
                    S1: begin
                        uart_put_char(8'h31);
                        r_cur_state <= S2;
                    end
                    // ------------------------------------------------
                    // 第三包
                    // 32 33
                    // ------------------------------------------------
                    S2: begin
                        m_axis_uart_tdata <= {8'd2, 8'h32,8'h33,104'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S3;
                    end
                    // ------------------------------------------------
                    // 第四包
                    // 34 35 36
                    // ------------------------------------------------
                    S3: begin
                        m_axis_uart_tdata <= {8'd3,8'h34,8'h35,8'h36,96'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S4;
                    end


                    // ------------------------------------------------
                    // 第五包
                    // 37 38 39 40
                    // ------------------------------------------------
                    S4: begin
                        m_axis_uart_tdata <= { 8'd4, 8'h37, 8'h38, 8'h39,8'h40,88'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S5;
                    end
                    // ------------------------------------------------
                    // 第六包
                    // 61 62 63 64 65
                    // ------------------------------------------------
                    S5: begin
                        m_axis_uart_tdata <= {8'd5, 8'h61,8'h62,8'h63,8'h64,8'h65, 80'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S6;

                    end
                    // ------------------------------------------------
                    // 第七包
                    // 66 67 68 69 70 71
                    // ------------------------------------------------
                    S6: begin
                        m_axis_uart_tdata <= { 8'd6, 8'h66,8'h67,8'h68,8'h69,8'h70,8'h71, 72'd0};
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S7;
                    end
                    // ------------------------------------------------
                    // 第八包
                    // 72 73 74 75 76 77 78
                    // ------------------------------------------------
                    S7: begin
                        m_axis_uart_tdata <= { 8'd7,8'h72,8'h73,8'h74,8'h75,8'h76,8'h77,8'h78, 64'd0 };
                        m_axis_uart_tvalid <= 1'b1;
                        r_cur_state <= S0;
                    end
                    default: begin
                        r_cur_state <= S0;
                    end
                endcase
            end
        end
    end
endmodule

pin.xdc

create_clock -period 20.000 -name CLOCK_XTAL_50MHz [get_ports CLOCK_XTAL_50MHz] 
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports CLOCK_XTAL_50MHz]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports RESET]
set_property -dict {PACKAGE_PIN L14 IOSTANDARD LVCMOS33} [get_ports KEY]
set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports RXD]
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports TXD]

测试

[18:18:43.172]收←◆30 31 32 33 34 35 36 37 38 39 40 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 
[18:18:43.424]收←◆30 31 32 33 34 35 36 37 38 39 40 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐