简易寄存器接口SMMR---正交编码器

参考

简易寄存器接口SMMR的vio_uart桥接.csdn

Tang-Nano-1K.sipeed

TANG_FPGA_Demo_Top.v

verilog 复制代码
module TANG_FPGA_Demo_Top#(
    // 内部 SMMR 字节地址宽度。
    parameter P_ADDR_WIDTH   = 8,
    // 寄存器宽度
    parameter P_DATA_WIDTH = 32,
    // 系统时钟频率。
    parameter P_CLK_FREQ         = 27_000_000
)
(
    input CLOCK_XTAL_27MHz,
	input RESET,
	input  KEY1,
    input  RXD,
    output TXD,
    input ENCORDER_A,
    input ENCORDER_B,
    output  [2:0] LED // 110 R, 101 B, 011 G
);

    ////////////////////////////////////////////////////////////////////////////
    // vio_uart桥接模块到 SMMR 路由模块之间的信号
    ////////////////////////////////////////////////////////////////////////////
    wire                              w_reg_wr_en;
    wire [8-1:0]       w_reg_wr_addr;
    wire [8-1:0]       w_reg_rd_addr;
    wire [P_DATA_WIDTH-1:0]      w_reg_wr_data;
    wire [P_DATA_WIDTH-1:0]      w_reg_rd_data;
    wire [P_ADDR_WIDTH-1:0]      w_slot_wr_addr;
    wire [P_ADDR_WIDTH-1:0]      w_slot_rd_addr;
    // 写数据会同时送到所有 slot,真正写入哪个 slot 由对应写使能决定。
    wire [P_DATA_WIDTH-1:0]     w_slot_wr_data;
    // slot0 的写使能和读数据。
    wire                          w_slot0_wr_en;
    wire [P_DATA_WIDTH-1:0]       w_slot0_rd_data;
    // slot1 的写使能和读数据。
    wire                          w_slot1_wr_en;
    wire [P_DATA_WIDTH-1:0]       w_slot1_rd_data;



vio_uart_smmr_bridge #(
    .P_CLK_FREQ(P_CLK_FREQ),
    .P_UART_BPS(115200)
) u_vio_uart_smmr_bridge (
    .i_clk          (CLOCK_XTAL_27MHz),
    .i_rst_n        (RESET),
    .i_uart_rxd     (RXD),
    .o_uart_txd     (TXD),
    .o_reg_wr_en    (w_reg_wr_en),
    .o_reg_wr_addr  (w_reg_wr_addr),
    .o_reg_wr_data  (w_reg_wr_data),
    .o_reg_rd_addr  (w_reg_rd_addr),
    .i_reg_rd_data  (w_reg_rd_data)
);



  ////////////////////////////////////////////////////////////////////////////
    // SMMR slot 路由模块
    //
    // 该模块根据 SMMR 地址范围选择目标 slot。
    // 写操作时,它给对应 slot 产生写使能。
    // 读操作时,它把被选中 slot 的读数据返回给 AXI-Lite 桥接模块。
    //
    // 当前地址映射:
    //   slot0:寄存器地址 0 到 3
    //   slot1:寄存器地址 5 到 8
    ////////////////////////////////////////////////////////////////////////////
    smmr_slot_router u_smmr_slot_router (
        .i_clk          (CLOCK_XTAL_27MHz),
        .i_rst_n        (RESET),

        .i_reg_wr_en    (w_reg_wr_en),
        .i_reg_wr_addr  (w_reg_wr_addr),
        .i_reg_wr_data  (w_reg_wr_data),
        .i_reg_rd_addr  (w_reg_rd_addr),
        .o_reg_rd_data  (w_reg_rd_data),

        .o_slot_wr_addr (w_slot_wr_addr),
        .o_slot_wr_data (w_slot_wr_data),
        .o_slot_rd_addr (w_slot_rd_addr),

        .o_slot0_wr_en  (w_slot0_wr_en),
        .i_slot0_rd_data(w_slot0_rd_data),

        .o_slot1_wr_en  (w_slot1_wr_en),
        .i_slot1_rd_data(w_slot1_rd_data)
    );

    ////////////////////////////////////////////////////////////////////////////
    // slot0 外设
    //
    // slot0 是一个简单寄存器块。
    // 它可以作为新增 SMMR 外设的模板:只需要接入写使能、地址、写数据、
    // 读地址和读数据,就可以挂到系统中。
    ////////////////////////////////////////////////////////////////////////////
    slot0 u_slot0 (
        .i_clk          (CLOCK_XTAL_27MHz),
        .i_rst_n        (RESET),
        .i_reg_wr_en    (w_slot0_wr_en),
        .i_reg_wr_addr  (w_slot_wr_addr),
        .i_reg_wr_data  (w_slot_wr_data),
        .i_reg_rd_addr  (w_slot_rd_addr),
        .o_reg_rd_data  (w_slot0_rd_data)
    );

    ////////////////////////////////////////////////////////////////////////////
    // slot1 编码器外设
    ////////////////////////////////////////////////////////////////////////////
    encoder_slot u_slot1 (
        .i_clk          (CLOCK_XTAL_27MHz),
        .i_rst_n        (RESET),
        .i_encoder_a(ENCORDER_A),
        .i_encoder_b(ENCORDER_B),
        .i_reg_wr_en    (w_slot1_wr_en),
        .i_reg_wr_addr  (w_slot_wr_addr),
        .i_reg_wr_data  (w_slot_wr_data),
        .i_reg_rd_addr  (w_slot_rd_addr),
        .o_reg_rd_data  (w_slot1_rd_data)
    );



endmodule

encoder_slot .v

verilog 复制代码
`timescale 1ns / 1ps

module encoder_slot #(
    parameter P_ADDR_WIDTH = 8,
    parameter P_DATA_WIDTH = 32,
    parameter [P_ADDR_WIDTH-1:0] P_SLOT_BASE = 4,
    parameter P_REG_COUNT = 1
)(
    input  wire                    i_clk,
    input  wire                    i_rst_n,

    // SMMR
    input  wire                    i_reg_wr_en,
    input  wire [P_ADDR_WIDTH-1:0] i_reg_wr_addr,
    input  wire [P_DATA_WIDTH-1:0] i_reg_wr_data,

    input  wire [P_ADDR_WIDTH-1:0] i_reg_rd_addr,
    output reg  [P_DATA_WIDTH-1:0] o_reg_rd_data,

    // Encoder
    input  wire                    i_encoder_a,
    input  wire                    i_encoder_b
);

    ////////////////////////////////////////////////////////////////////////////
    // 内部寄存器
    ////////////////////////////////////////////////////////////////////////////

    reg signed [15:0] r_encoder_value;

    reg [1:0] r_old_code;
    reg [1:0] r_encoder_sync1;
    reg [1:0] r_encoder_sync2;

    ////////////////////////////////////////////////////////////////////////////
    // 输入同步
    ////////////////////////////////////////////////////////////////////////////

    always @(posedge i_clk or negedge i_rst_n) begin
        if (!i_rst_n) begin
            r_encoder_sync1 <= 2'b00;
            r_encoder_sync2 <= 2'b00;
        end
        else begin
            // A = bit0
            // B = bit1
            r_encoder_sync1 <= {i_encoder_b, i_encoder_a};
            r_encoder_sync2 <= r_encoder_sync1;
        end
    end

    ////////////////////////////////////////////////////////////////////////////
    // 编码器解码
    ////////////////////////////////////////////////////////////////////////////

    always @(posedge i_clk or negedge i_rst_n) begin
        if (!i_rst_n) begin
            r_old_code      <= 2'b00;
            r_encoder_value <= 16'd0;
        end
        else if (r_encoder_sync2 != r_old_code) begin

            case (r_encoder_sync2)

                2'b00: begin
                    if (r_old_code == 2'b10)
                        r_encoder_value <= r_encoder_value + 16'd1;
                    else if (r_old_code == 2'b01)
                        r_encoder_value <= r_encoder_value - 16'd1;
                end

                2'b01: begin
                    if (r_old_code == 2'b00)
                        r_encoder_value <= r_encoder_value + 16'd1;
                    else if (r_old_code == 2'b11)
                        r_encoder_value <= r_encoder_value - 16'd1;
                end

                2'b11: begin
                    if (r_old_code == 2'b01)
                        r_encoder_value <= r_encoder_value + 16'd1;
                    else if (r_old_code == 2'b10)
                        r_encoder_value <= r_encoder_value - 16'd1;
                end

                2'b10: begin
                    if (r_old_code == 2'b11)
                        r_encoder_value <= r_encoder_value + 16'd1;
                    else if (r_old_code == 2'b00)
                        r_encoder_value <= r_encoder_value - 16'd1;
                end

            endcase

            r_old_code <= r_encoder_sync2;

        end
    end

    ////////////////////////////////////////////////////////////////////////////
    // SMMR Read
    ////////////////////////////////////////////////////////////////////////////

    always @(*) begin

        if ((i_reg_rd_addr >= P_SLOT_BASE) &&
            (i_reg_rd_addr < (P_SLOT_BASE + P_REG_COUNT))) begin

            // 符号扩展到32位
            o_reg_rd_data = {{16{r_encoder_value[15]}}, r_encoder_value};

        end
        else begin
            o_reg_rd_data = {P_DATA_WIDTH{1'b0}};
        end

    end

endmodule

ReadMe.md

verolog 复制代码
set src_dir "D:/workspace/gitee/0/ming_tang_nano_1k/vio_uart/src"
set rtl_dir "D:/workspace/gitee/0/ming_tang_nano_1k/vio_uart/src/rtl"
add_file  $rtl_dir/TANG_FPGA_Demo_Top.v
add_file  $rtl_dir/uart_rx.v
add_file  $rtl_dir/uart_tx.v
add_file  $rtl_dir/vio_uart_smmr_bridge.v
add_file  $rtl_dir/smmr_slot_router.v
add_file  $rtl_dir/slot0.v
add_file  $rtl_dir/encoder_slot.v
add_file  $src_dir/vio_uart_prj.cst
add_file  $src_dir/vio_uart_prj.sdc

vio_uart_prj.cst

bash 复制代码
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 "RXD" 41;
IO_PORT "RXD" IO_TYPE=LVCMOS33 PULL_MODE=UP;
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;

IO_LOC "ENCORDER_A" 38;
IO_PORT "ENCORDER_A" IO_TYPE=LVCMOS33 PULL_MODE=UP;

IO_LOC "ENCORDER_B" 39;
IO_PORT "ENCORDER_B" IO_TYPE=LVCMOS33 PULL_MODE=UP;

测试

bash 复制代码
# 查编码器值
> 00 04 00 00 00 00
# 返回编码器值是16
< 00 04 10 00 00 00 
相关推荐
xiaojiaohuazi15 小时前
国产安陆EG4S20 FPGA实现千兆以太网TCP/IP:AD7606C 8通道1 MSPS采集、SDRAM缓存与Python上位机
tcp/ip·缓存·fpga开发
尤老师FPGA15 小时前
HDMI数据的接收发送实验(二十四)
fpga开发
MDYFPGA16 小时前
明德扬 Kintex-7 FPGA核心板及多接口扩展底板介绍
fpga开发·fpga
I'm a winner16 小时前
【源码】一文读懂 TDOA 无源时差定位原理
fpga开发
FPGA小迷弟17 小时前
FPGA复位策略深度解析:异步复位、同步释放与设计最佳实践
fpga开发·fpga
MDYFPGA17 小时前
Arria 10 10AX027 核心板适合哪些高速数据处理项目
fpga开发·fpga
Terasic友晶科技1 天前
【教程】Agilex 5 SOC FPGA的HPS端如何响应FPGA端中断(一)——GIC控制器介绍
fpga开发·hps·agilex 5·gic控制器
芯路行者2 天前
4.4 HDLBits —— 更多时序逻辑电路
fpga开发·verilog·fpga·hdlbits
HUSTCH20213 天前
有符号数无符号数加法器逻辑
fpga开发
LCMICRO-133108477463 天前
国产长芯微LP4807完全P2P替代ADA4807,1mA、300MHz 增益带宽、电压反馈运算放大器
arm开发·嵌入式硬件·fpga开发·硬件工程·运算放大器·ada4807