ホーム › フォーラム › Texas Instruments › マイコン › C2000 › IQ型を使った演算時間の短縮化について
このトピックには3件の返信が含まれ、2人の参加者がいます。5 年、 7 ヶ月前に 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が発生するという認識でよろしいでしょうか。以上、宜しくお願い致します。
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のみを選択していただくことで対応できると思います。
ご確認のほど、よろしくお願いいたします。
早急なご対応、誠にありがとうございました。
①について
早速、実施したところ、3.7us→3.0usとなり、かなり改善されました。
ありがとうございました。
ちなみに、演算速度を速める他の方法として、変数のIQ型のグローバル宣言の部分について、
16bitシフトした値をlong型で宣言した方が速くなるような気がしているのですが、
それに関しまして見解をご教示願います。②について
内容承知致しました。ありがとうございました。以上、宜しくお願い致します。
amatsu1さん
ちなみに、演算速度を速める他の方法として、変数のIQ型のグローバル宣言の部分について、
16bitシフトした値をlong型で宣言した方が速くなるような気がしているのですが、
それに関しまして見解をご教示願います。こちらは、_IQ(…)で定数を定義(例:#define MAX_CNTVAL _IQ(414))するよりも、long型の変数として定義(例: long MAX_CNTVAL = (long)(414 << 16)としたほうが実行速度が早くなるのではという質問でしょうか。
C2000のアセンブラで考えた場合、演算対象が定数と変数(メモリアクセス)では実行サイクル数は変わりませんので、どちらの定義でもそれほど変化はないのではと考えております。しかし、コンパイラの最適化(速度有優先、サイズ優先)により、場合によっては違いが出てきますので、一概にどちらが早いということはコメントすることができません。実際に測定いただくことをお薦めいたします。
ご確認のほど、よろしくお願いいたします。
内容承知致しました。
早急なご対応、誠にありがとうございました。 -
投稿者投稿