简易寄存器接口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 
相关推荐
神电测控6 小时前
新品发布:32通道50MS/s同步并行14位采集模块PG-FMC9249(支持任意FPGA/ZYNQ,兼容LabVIEW FPGA软件开发)
fpga开发·labview·ni·神电测控·王电令·ad9249·32通道
Drgfd8 小时前
半导体国产替代进入“深水区”:决战设备、材料、IP三大高地
网络·fpga开发
国产HT1621B9 小时前
YL1650 LED驱动芯片详解:从原理到实战应用(附51单片机驱动代码)
stm32·单片机·嵌入式硬件·mcu·fpga开发·lcd驱动
szxinmai主板定制专家11 小时前
驱控一体新范式:RK3576+FPGA+CODESYS工业实时AI控制架构全解
人工智能·嵌入式硬件·计算机视觉·fpga开发·架构·工业ai·驱控一体
国科安芯12 小时前
ASC0101S自动双向电平转换原理深剖
单片机·嵌入式硬件·fpga开发·云计算·信息与通信
落chen13 小时前
7 Series FPGAs Clocking Resources
fpga开发
落chen1 天前
基于FPGA的IIC协议通信-强化篇
fpga开发
梦开始的地方 �1 天前
实例化和句柄
fpga开发
lf2824814311 天前
11 FM调制与解调的仿真
fpga开发