FC2カウンター FPGAの部屋 Zybot のモーターの回転数と回転方向を取得する1
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Zybot のモーターの回転数と回転方向を取得する1

以前、Zybot を作成したのだが、モーター回転数を取得する部分はいい加減だった。

Digilent のZYBOt Tutorial
FPGAの部屋のブログのZybot カテゴリ


今回、Zybot のFPGA ボードをUltra96 に変更するにあって、ギアボックス付きモーター回転数と回転方向を取得したい。
以前、Vivado HLS で作ったのだが、いまいち精度が出ていない気がするので、HDL で作り直すことにした。
なお、SA, SB のタイミングチャートは、”Project 10: Frequency Measurement Using Input Capture”の 13 ページの”Figure 2. Screen capture of the seven monitored signals.”に載っている。

どうHDL で書くかを考えながら、いろいろとツィッターに書いていたところ、@izumitomonori さんにHDL のサンプルコードを教えていただいて、積分するんだよ。。。という貴重なご意見をいただいた。サンプルコードそのままでも良いのだが、私のアレンジ(悪くなっているかも知れないが。。。)を加えた久しぶりのVerilog HDL コードを書いてみた。ありがとうございました。

motor_count.v をここに載せるが、まだ全く検証していないので、バグはあると思う。これから検証していこう。
なお、@izumitomonori さんの名誉のために書いておきますが、元のコードはとってもシンプルな素晴らしいコードです。私がコードの切れ味をだいぶ鈍らせてしまった気がするが、どうもこんなふうに書かないと気がすまないもので。。。すみません。。。

// motor_count.v
// 2019/06/14 by marsee
// このファイルは、立命館大学の泉先生のVerilogコードを元に作成しました。泉先生ありがとうございました。
//

`default_nettype none

module moter_count #(
    parameter integer BW =32
)
(
   input  wire          sa,
   input  wire          sb,
   output wire [BW-1:0] count,
   input  wire          clk,
   input  wire          rst,
   input  wire          cnt_clr
);

    reg sa1b=1'b0, sa2b=1'b0;
    reg sb1b=1'b0, sb2b=1'b0;
    wire [1:0] sasb_state;
    reg [BW-1:0] count_r=0;
    
    parameter [3:0]     NOR_STATE_00 = 4'b0001,
                        NOR_STATE_10 = 4'b0010,
                        NOR_STATE_11 = 4'b0100,
                        NOR_STATE_01 = 4'b1000;

    reg [3:0] rev_rot, rev_rot_1b;
    parameter [3:0]     REV_STATE_00 = 4'b0001,
                        REV_STATE_01 = 4'b0010,
                        REV_STATE_11 = 4'b0100,
                        REV_STATE_10 = 4'b1000;
    reg [3:0] nor_rot=NOR_STATE_00, nor_rot_1b=REV_STATE_00;
    
    assign count = count_r;
    
    always @(posedge clk) begin
        sa1b <= sa;
        sb1b <= sb;
        sa2b <= sa1b;
        sb2b <= sb1b;

        nor_rot_1b <= nor_rot;
        rev_rot_1b <= rev_rot;
    end
    
    always @(posedge clk) begin
        if(rst)
            count_r <= 0;
        else if(cnt_clr)
            count_r <= 0;
        else begin
            if(nor_rot==NOR_STATE_00 && nor_rot_1b==NOR_STATE_01) begin
                if(rev_rot==REV_STATE_00 && rev_rot_1b==REV_STATE_10) begin
                    count_r <= count_r;
                end else begin
                    count_r <= count_r + 1;
                end
            end else begin
                if(rev_rot==REV_STATE_00 && rev_rot_1b==REV_STATE_10) begin
                    count_r <= count_r - 1;
                end else begin
                    count_r <= count_r;
                end
            end
        end
    end
    
    assign sasb_state = {sa2b, sb2b};
    
    // nor_rot state machine
    always @(posedge clk) begin
        if(rst)
            nor_rot <= NOR_STATE_00;
        else begin
            case(nor_rot)
                NOR_STATE_00:
                    if(sasb_state==2'b10)
                        nor_rot <= NOR_STATE_10;
                NOR_STATE_10:
                    if(sasb_state == 2'b11)
                        nor_rot <= NOR_STATE_11;
                NOR_STATE_11:
                    if(sasb_state == 2'b01)
                        nor_rot <= NOR_STATE_01;
                NOR_STATE_01:
                    if(sasb_state == 2'b00)
                        nor_rot <= NOR_STATE_00;
            endcase
        end
    end
    
    // rev_rot state machine
    always @(posedge clk) begin
        if(rst)
            rev_rot <= REV_STATE_00;
        else begin
            case(rev_rot)
                REV_STATE_00:
                    if(sasb_state==2'b01)
                        nor_rot <= NOR_STATE_01;
                REV_STATE_01:
                    if(sasb_state == 2'b11)
                        nor_rot <= NOR_STATE_11;
                REV_STATE_11:
                    if(sasb_state == 2'b10)
                        nor_rot <= NOR_STATE_10;
                REV_STATE_10:
                    if(sasb_state == 2'b00)
                        nor_rot <= NOR_STATE_00;
            endcase
        end
    end
endmodule

`default_nettype wire


とても久しぶりにVerilog HDL のコードを書いた。いろいろと忘れている。。。大丈夫かな?あとで修正します。
次は、検証用の回路をVivado HLS で作っていくことにする。
  1. 2019年06月17日 23:17 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/4556-d2814589
この記事にトラックバックする(FC2ブログユーザー)