ホーム フォーラム Texas Instruments マイコン C2000 IQ型を使った演算時間の短縮化について

このトピックには3件の返信が含まれ、2人の参加者がいます。5 年、 5 ヶ月前 amatsu1 さんが最後の更新を行いました。

5件の投稿を表示中 - 1 - 5件目 (全5件中)
  • 投稿者
    投稿
  • #5973 返信

    amatsu1
    参加者

    IQ型を使った演算時間の短縮化について

    いつも大変お世話になっております。
    早速ですが、TMS320F28027にて、以下の2点質問がございます。

    ①以下のようなコードを書いたところ、演算時間が3.7usでした。
    処理時間をさらに早くする方法について、ご教示願います。

    #define GLOBAL_Q 16
    #define MAX_CNTVAL _IQ(414)
    #define MIN_CNTVAL _IQ(14.4)
    #define PWM_PERIOD _IQ(600)
    #define K0 _IQ(0.01347)
    #define K1 _IQ(0.01347)
    #define K2 _IQ(0.99917)
    _iq IoutDetect_Ch1;
    _iq IoutDetect_Ch2;
    _iq CtrlVal0_Ch1;
    _iq CtrlVal0_Ch2;
    _iq Ierror0_Ch1;
    _iq Ierror0_Ch2;
    _iq Ierror1_Ch1;
    _iq Ierror1_Ch2;

    interrupt void ADCINT1_ISR(void) // ADC (Can also be ISR for INT10.1 when enabled)
    {
    //計測開始
    IoutDetect_Ch1=AdcResult.ADCRESULT2;
    IoutDetect_Ch2=AdcResult.ADCRESULT3;
    _iq NxtCntVal_Ch1, NxtCntVal_Ch2;
    //Ierror0_Ch1= _IQ((IoutCommand_Ch1-IoutDetect_Ch1) >> 2); ←最初こちらのコードを書きましたが、_IQに相当する16bit左シフトと元々の2bit右シフトを合算した14bit左シフト(1行下のコード)の方が速かった為、コメントアウトしました
    Ierror0_Ch1= (IoutCommand_Ch1-IoutDetect_Ch1) << 14;
    NxtCntVal_Ch1 = __IQmpy(K0,Ierror0_Ch1,16)+__IQmpy(K1,Ierror1_Ch1,16)+__IQmpy(K2,CtrlVal1_Ch1,16);
    NxtCntVal_Ch1=((NxtCntVal_Ch1 > MAX_CNTVAL) ? MAX_CNTVAL: NxtCntVal_Ch1);
    EPwm3Regs.CMPA.all=((NxtCntVal_Ch1 < MIN_CNTVAL) ? MIN_CNTVAL: NxtCntVal_Ch1);

    CtrlVal1_Ch1=EPwm3Regs.CMPA.all;
    Ierror1_Ch1=Ierror0_Ch1;

    //Ch2でも上記と同じ処理(冗長の為、ここでは省略しますが、演算時間に含まれています)
      
      //計測終了(ここまでが3.7us)
    }

    ②ADCCTL1レジスタのINTPULSEPOSについてですが、SOC0~SOC5のラウンドロビンでSOC5時にINT pulseを発生させる場合、
    INTPULSEPOS=0とすると、SOC5開始時にINT pulseが発生するという認識でよろしいでしょうか。

    以上、宜しくお願い致します。

    #5974 返信
    Yojiro
    Yojiro
    従業員

    amatsu1さん

    ①以下のようなコードを書いたところ、演算時間が3.7usでした。
    処理時間をさらに早くする方法について、ご教示願います。

    コードを確認させていただきましたが乗算(__IQmpy)に関しましては、Intrinsic関数をご利用頂いておりますので、これ以上の高速化は難しいです。
    コードの後半で、最大値と最小値の判定を行っていますが、次のIntrinsic関数がご利用いただけるのではないかと考えます。
    __IQsat( long A, long max, long min );

    NxtCntVal_Ch1=((NxtCntVal_Ch1 > MAX_CNTVAL) ? MAX_CNTVAL: NxtCntVal_Ch1);
    EPwm3Regs.CMPA.all=((NxtCntVal_Ch1 < MIN_CNTVAL) ? MIN_CNTVAL: NxtCntVal_Ch1);

    __IQsat関数をご利用いただくと、上記2行は「__IQsat(NxtCntVal_Ch1, MAX_CNTVAL, MIN_CNTVAL);」の1行で記述でき、かつアセンブラコードも次の3命令に集約されますので、実行速度の改善につながるものと思います。

    MOVL ACC, NxtCntVal_Ch1
    MINL ACC, MAX_CNTVAL
    MAXL ACC, MIN_CNTVAL

     

    ②ADCCTL1レジスタのINTPULSEPOSについてですが、SOC0~SOC5のラウンドロビンでSOC5時にINT pulseを発生させる場合、
    INTPULSEPOS=0とすると、SOC5開始時にINT pulseが発生するという認識でよろしいでしょうか。

    INTPULSEPOSビットにつきましては、割込み信号(ADCINTx)の制御ではなく、ADC内部の変換完了信号(EOC)パルスの生成タイミングを設定します。INTPULSEPOS=0の場合は、EOCは各SOC動作時のサンプリング終了後(AD変換前)にEOCパルスが発生し、INTPULSEPOS=1の場合は、各SOC動作時のAD変換終了後にRESULTレジスタへ変換データを格納したあとにEOCパルスが発生します。
    データシート(SPRS523)のFigure 6-21.(INTPULSEPOS=1)、Figure 6-22. (INTPULSEPOS=0)にタイミングチャートがございますので、ご確認ください。
    ※タイミングチャートでは、最初のEOCパルスでCPUへの割込み(ADCINT)を発生させています。

    EOCパルスは全てのSOC動作で発生しますので、SOC5の変換開始時にADC変換割込みを発生させたい場合は、INTPULSEPOS=0として、INTSELxNyレジスタにEOC5のみを選択していただくことで対応できると思います。

     

    ご確認のほど、よろしくお願いいたします。

    #5975 返信

    amatsu1
    参加者

    早急なご対応、誠にありがとうございました。

    ①について
    早速、実施したところ、3.7us→3.0usとなり、かなり改善されました。
    ありがとうございました。
    ちなみに、演算速度を速める他の方法として、変数のIQ型のグローバル宣言の部分について、
    16bitシフトした値をlong型で宣言した方が速くなるような気がしているのですが、
    それに関しまして見解をご教示願います。

    ②について
    内容承知致しました。ありがとうございました。

    以上、宜しくお願い致します。

    #5978 返信
    Yojiro
    Yojiro
    従業員

    amatsu1さん

    ちなみに、演算速度を速める他の方法として、変数のIQ型のグローバル宣言の部分について、
    16bitシフトした値をlong型で宣言した方が速くなるような気がしているのですが、
    それに関しまして見解をご教示願います。

    こちらは、_IQ(…)で定数を定義(例:#define MAX_CNTVAL _IQ(414))するよりも、long型の変数として定義(例: long MAX_CNTVAL = (long)(414 << 16)としたほうが実行速度が早くなるのではという質問でしょうか。

    C2000のアセンブラで考えた場合、演算対象が定数と変数(メモリアクセス)では実行サイクル数は変わりませんので、どちらの定義でもそれほど変化はないのではと考えております。しかし、コンパイラの最適化(速度有優先、サイズ優先)により、場合によっては違いが出てきますので、一概にどちらが早いということはコメントすることができません。実際に測定いただくことをお薦めいたします。

     

    ご確認のほど、よろしくお願いいたします。

    #5979 返信

    amatsu1
    参加者

    内容承知致しました。
    早急なご対応、誠にありがとうございました。

5件の投稿を表示中 - 1 - 5件目 (全5件中)