FC2カウンター FPGAの部屋 PmodHB5インターフェース回路 (PmodHB5_inf) の作成

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

FPGAの部屋

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

PmodHB5インターフェース回路 (PmodHB5_inf) の作成

PmodHB5: H-bridge Driver with Feedback Inputs のインターフェース回路を作成することにした。
今まで作ったPWM モジュールの”Vivado HLS で PWM モジュールIP を作ってみた”と”PmodHB5 のセンサー・フィードバック処理IP を作ってみた”を合わせたIP を作ろうということだ。

具体的には、pwm() と motor_monitor() を順にコールするのだが、関数を並列実行できるDATAFLOW 指示子を使って並列実行させようということだ。具体的なメインのC++ コードだけを示す。

int PmodHB5_inf(ap_uint<7> sw_late, ap_uint<1> dir, volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out,
        hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
        ap_uint<32> & sa_count, ap_uint_1 & sb_level, ap_uint_1 & overflow){
#pragma HLS DATAFLOW
#pragma HLS INTERFACE s_axilite port=dir
#pragma HLS INTERFACE ap_none register port=dir_out
#pragma HLS INTERFACE ap_none register port=pwm_out
#pragma HLS INTERFACE s_axilite port=sw_late
#pragma HLS INTERFACE s_axilite port=return
#pragma HLS INTERFACE s_axilite port=overflow
#pragma HLS INTERFACE s_axilite port=sb_level
#pragma HLS INTERFACE s_axilite port=sa_count
#pragma HLS INTERFACE ap_hs port=sb
#pragma HLS INTERFACE ap_hs port=sa

    pwm(sw_late, dir, pwm_out, dir_out);

    motor_monitor(sa, sb, sa_count, sb_level, overflow);

    return 0;
}


ヘッダファイル PmodHB5_inf.h を示す。

// PmodHB5_inf.h
// 2016/06/20 by marsee
//

#ifndef __MOTOR_MONITOR___
#define __MOTOR_MONITOR___

#include <ap_int.h>

typedef ap_uint<1> ap_uint_1;

#define PWM_MAX_VALUE    100
#define PWM_WAIT_CLOCK    500
#define PWM_ALL_CLOCKS    ((PWM_MAX_VALUE)*(PWM_WAIT_CLOCK))
#endif


テストベンチファイル PmodHB5_inf_tb.cpp を示す。

// PmodHB5_inf_tb.cpp
// 2016/06/20 by marsee
//
// PWMとモーターのフィードバック・ピン処理用IP のテストベンチ
//

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

#include "PmodHB5_inf.h"

#define SASB_PULSE_WIDTH 500

int PmodHB5_inf(ap_uint<7> sw_late, ap_uint<1> dir, volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out,
        hls::stream<ap_uint_1 >& sa, hls::stream<ap_uint_1 >& sb,
        ap_uint<32> & sa_count, ap_uint_1 & sb_level, ap_uint_1 & overflow);

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;
    ap_uint_1 overflow;

    ap_uint_1 pwm_out;
    ap_uint_1 dir_out;

    for (int i=0; i<PWM_ALL_CLOCKS; i++){
        if (i%SASB_PULSE_WIDTH <= SASB_PULSE_WIDTH/4)
            sa << (ap_uint_1)1;
        else if (i%SASB_PULSE_WIDTH > SASB_PULSE_WIDTH/4 && i%SASB_PULSE_WIDTH <= SASB_PULSE_WIDTH/4*3)
            sa << (ap_uint_1)0;
        else
            sa << (ap_uint_1)1;

        if (i%SASB_PULSE_WIDTH < SASB_PULSE_WIDTH/2)
            sb << (ap_uint_1)0;
        else
            sb << (ap_uint_1)1;
    }
    PmodHB5_inf(00, pwm_out, dir_out,
            sa, sb, sa_count, sb_level, overflow);
    PmodHB5_inf(501, pwm_out, dir_out,
            sa, sb, sa_count, sb_level, overflow);
    PmodHB5_inf(1000, pwm_out, dir_out,
            sa, sb, sa_count, sb_level, overflow);

    printf("*sa_count = %d, *sb_level = %d, overflow = %d\n",
               (unsigned int)sa_count, (unsigned int)sb_level, (unsigned int)overflow);

    return 0;
}


これでC コードを合成して、C/RTLコシミュレーションを行った。C/RTLコシミュレーション波形を表示した。
PmodHB5_inf_1_160622.png

pwm_out_V を見ると 1 になるはずのところが X になっている。これはバグだ。

sa_V_V と sb_V_V のセンサー・フィードバック・ピンは、ほんの少し波形が出て後は 0 の定常状態になっている。
最初の部分を拡大してみよう。
PmodHB5_inf_2_160623.png 

sa_V_V が 1 -> 0 -> 1 と変化しているので、PWM に比べて短い時間で終了している。つまり、motor_monitor() は短い時間で終了したが、pwm() が終了していないので、付き合わされているということのようだ。これは考えてみれば当たり前かもしれない。

次に pwm() のバグを考えてみよう。pwm() のCソースコードを示す。

void pwm(ap_uint<7> sw_late, ap_uint<1> dir,
        volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out){

    dir_out = dir;
    for (int i=1; i<=PWM_MAX_VALUE; i++){
        for (int n=0; n<PWM_WAIT_CLOCK; n++){
#pragma HLS PIPELINE II=1 rewind
            if (sw_late == 0){
                pwm_out = 0;
            } else if(i==1){
                pwm_out = 1;
            } else if (sw_late < i){
                pwm_out = 0;
            }
        }
    }
}


これを見ると、「 } else if(i==1){ 」の部分は明らかにおかしい。 i が 1 のときのみ pwm_out = 1; になる。つまり他の pwm_out = 1; になるはずの部分の記述がないことになる。これは”Vivado HLS で PWM モジュールIP を作ってみた”と同じコード(厳密に言うと、dir_out 出力を追加してある)なのだが、前は良く正しく動いたと思う。明らかにバグだ。つまり、関数にすることでバグが顕在化したのだろう?
pwm() の新しいソースコードを示す。

void pwm(ap_uint<7> sw_late, ap_uint<1> dir,
        volatile ap_uint<1> & pwm_out, ap_uint<1> & dir_out){

    dir_out = dir;
    for (int i=1; i<=PWM_MAX_VALUE; i++){
        for (int n=0; n<PWM_WAIT_CLOCK; n++){
#pragma HLS PIPELINE II=1 rewind
            if (sw_late == 0){
                pwm_out = 0;
            } else if(i>=1 && sw_late >= i){
                pwm_out = 1;
            } else if (sw_late < i){
                pwm_out = 0;
            }
        }
    }
}

これで、C コードの合成、C/RTLコシミュレーションを行った。C/RTLコシミュレーション波形を示す。
PmodHB5_inf_3_160623.png

これで pwm_out_V も正常になった。

これで良いように思うが、 pwm_out_V の処理時間よりもセンサー・フィードバック処理用IPのsa, sb の入力の処理時間が長くなるとどうなるだろうか?
PWM の時間も伸びてしまうと思う。つまり、PmodHB5 用のIP として 2 つの関数を一緒にVivado HLS でIP 化するのは問題があると思う。
  1. 2016年06月22日 05:54 |
  2. Zybot
  3. | トラックバック:0
  4. | コメント:0

コメント

コメントの投稿


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

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