FC2カウンター FPGAの部屋 PmodHB5 のセンサー・フィードバック処理IP を作ってみた3

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

FPGAの部屋

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

PmodHB5 のセンサー・フィードバック処理IP を作ってみた3

PmodHB5 のセンサー・フィードバック処理IP を作ってみた2”の続き。

どうもセンサー・フィードバックの値が安定しないと思ったら、アルゴリズムを間違っていた。SA の値が最初に 0 の途中のときに値が少なくなってしまう。そこで修正を行った。今回は最初に値を保存してから、反転しているとスタートするようにした。
さらに、100MHz クロックでキャプチャすると速すぎるのではないか?と思った。1MHzくらいでサンプルしたい。
HDL だと 100MHz の 100 回に 1 回のイネーブルを出すことで、1MHz サンプルにできるが、C で書くとどうしたらよいか考えた。そこで、100 回足し算して、50 以上だった 1 と、50 未満だったら 0 と判定することにした。
書き直した motor_monitor.cpp を貼っておく。

// motor_monitor.cpp
// 2016/06/15 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>

#include "motor_monitor.h"

#define SUM_COUNT    100

// sa と sb の値を SUM_COUNT 分だけ積算して 1 か 0 かを決定する
void sum_sa_sb(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
        ap_uint_1 & sa_val, ap_uint_1 & sb_val){

    ap_uint_1 sad;
    ap_uint_1 sbd;
    unsigned int sum_sa=0, sum_sb=0;

    for (int i=0; i<SUM_COUNT; i++){
#pragma HLS PIPELINE II=1
        sa >> sad;
        sb >> sbd;
        sum_sa += (unsigned int)sad;
        sum_sb += (unsigned int)sbd;
    }
    if (sum_sa >= SUM_COUNT/2)
        sa_val = 1;
    else
        sa_val = 0;

    if (sum_sb >= SUM_COUNT/2)
        sb_val = 1;
    else
        sb_val = 0;
}

int motor_monitor(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
        ap_uint<32> & sa_count, ap_uint_1 & sb_level, int & sum_count){
#pragma HLS INTERFACE ap_stable port=sum_count
#pragma HLS INTERFACE s_axilite port=sum_count
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=sb_level
#pragma HLS INTERFACE s_axilite port=sa_count
#pragma HLS INTERFACE ap_hs port=sa
#pragma HLS INTERFACE ap_hs port=sb

    ap_uint_1 sad, sa_val, next_sa;
    ap_uint_1 sbd, next_sb;
    ap_uint<32> sac;
    ap_uint_1 sble;

    sum_count = SUM_COUNT+4// sum_sa_sb() の呼び出しWaitを加算した
    // 最初の値を保存する
    sum_sa_sb(sa, sb, sa_val, next_sb);

    for (sac=0; sac!=0xffffffff; sac++){ // saの値が変わらない間はループ
        sum_sa_sb(sa, sb, next_sa, next_sb);
        if (sa_val != next_sa)
            break;
    }
    sa_val = next_sa;
    if (sac == 0xffffffff) // overflow
        return 1;

    if (next_sa == 1// next_sa が立ち上がり
        sble = next_sb;

    for (sac=1; sac!=0xffffffff; sac++){ // saの値が変わらない間はループ
        sum_sa_sb(sa, sb, next_sa, next_sb);
        if (sa_val != next_sa)
            break;
    }
    sa_val = next_sa;
    if (sac == 0xffffffff) // overflow
        return 1;

    if (next_sa == 1// next_sa が立ち上がり
        sble = next_sb;

    for (sac++; sac!=0xffffffff; sac++){ // saの値が変わらない間はループ
        sum_sa_sb(sa, sb, next_sa, next_sb);
        if (sa_val != next_sa)
            break;
    }
    if (sac == 0xffffffff) // overflow
        return 1;

    sa_count = sac;
    sb_level = sble;

    return 0;
}


motor_monitor.h を示す。

// motor_monitor.h
// 2016/06/16 by marsee
//

#ifndef __MOTOR_MONITOR___
#define __MOTOR_MONITOR___

#include <ap_int.h>

typedef ap_uint<1> ap_uint_1;
#endif


motor_monitor_tb.cpp を示す。

// motor_monitor_tb.cpp
// 2016/06/15 by marsee
//

#include <ap_int.h>
#include <hls_stream.h>

#include "motor_monitor.h"

#define DATASIZE 2000

int motor_monitor(hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
        ap_uint<32> & sa_count, ap_uint_1 & sb_level, int & sum_count);

int main(){
    using namespace std;

    hls::stream<ap_uint_1> sa;
    hls::stream<ap_uint_1> sb;

    ap_uint<32> sa_count;
    ap_uint_1 sb_level;
    int sum_count;

    ap_uint_1 salv=0;
    ap_uint_1 sblv=0;
    int cnt = 0;
    for (int j=0; j<(4*2); j++){
        for (int i=0; i<DATASIZE/4; i++){
            sa << salv;
            sb << sblv;
        }
        if (cnt==0)
            sblv = ~sblv;
        else if (cnt==1)
            salv = ~salv;
        else if (cnt==2)
            sblv = ~sblv;
        else // cnt == 3
            salv = ~salv;
        if (cnt==3)
            cnt = 0;
        else
            cnt++;
    }

    int ret_val = motor_monitor(sa, sb, sa_count, sb_level, sum_count);

    printf("sa_count = %d, sb_level = %d, return value = %d, sum_count = %d\n",
            (unsigned int)sa_count, (unsigned int)sb_level, ret_val, sum_count);

    return 0;
}


これで、C シミュレーションを行った。
motor_monitor_5_160702.png

うまく行っている。

C コードへの合成を行った。
motor_monitor_6_160702.png

Loop1, Loop2 の Latency の min が 104 クロックになっている。

motor_monitor_7_160702.png

C/RTLコシミュレーションを行った。
motor_monitor_8_160702.png

C/RTLコシミュレーション波形を示す。
motor_monitor_9_160702.png

拡大してみると、sum_sa_sb() が 100 クロック + 4 クロック = 104 クロックであることがわかる。そこで、sum_count には 104 を返すことにした。
motor_monitor_10_160702.png

これでIP 化を行った。

実機でテストしてみると sa_count の値はばらついてはいるが、大きく変動することはなくなった。しかし、 sb_level がいい加減だった。まだ何か間違っているだろうか?わかる人がいたら、ぜひご指摘ください。
sb_level は安定しなくてもPWM でどっち方向にモーターを回すかを設定しているので、回転方向は別に取れなくてもよいのだが。。。
  1. 2016年07月02日 05:09 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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