3

40 MIPS で動作し、C でプログラミングする 16 ビット PIC を使用する組み込みデバイス用のファームウェアに取り組んでいます。システムは 2 つのステッピング モーターの位置を制御し、各モーターのステップ位置を常に維持します。各モーターの最大位置は約 125000 ステップなので、16 ビット整数を使用して位置を追跡することはできません。32 ビット符号なし整数 (DWORD) を使用する必要があります。モーターは 1 秒あたり 1000 ステップで動きます。タイマー ISR でステップが処理されるようにファームウェアを設計しました。タイマー ISR は次のことを行います。

1) 1 つのモーターの現在位置を目標位置と比較し、同じ場合は isMoving フラグを false に設定して戻ります。それらが異なる場合は、isMoving フラグを true に設定します。

2) 目標位置が現在位置より大きい場合は、1 ステップ進めてから現在位置をインクリメントします。

3) 目標位置が現在位置より小さい場合は、1 ステップ後ろに移動し、現在位置をデクリメントします。

コードは次のとおりです。

void _ISR _NOPSV _T4Interrupt(void)
{
    static char StepperIndex1 = 'A';    

    if(Device1.statusStr.CurrentPosition == Device1.statusStr.TargetPosition)
    {
        Device1.statusStr.IsMoving = 0;
        // Do Nothing
    }   
    else if (Device1.statusStr.CurrentPosition > Device1.statusStr.TargetPosition)
    {
        switch (StepperIndex1)      // MOVE OUT
        {
            case 'A':
                SetMotor1PosB();
                StepperIndex1 = 'B';
                break;
            case 'B':
                SetMotor1PosC();
                StepperIndex1 = 'C';
                break;
            case 'C':
                SetMotor1PosD();
                StepperIndex1 = 'D';
                break;
            case 'D':
                default:
                SetMotor1PosA();
                StepperIndex1 = 'A';
                break;      
        }
        Device1.statusStr.CurrentPosition--;    
        Device1.statusStr.IsMoving = 1;
    }   
    else
    {
        switch (StepperIndex1)      // MOVE IN 
        {
            case 'A':
                SetMotor1PosD();
                StepperIndex1 = 'D';
                break;
            case 'B':
                SetMotor1PosA();
                StepperIndex1 = 'A';
                break;
            case 'C':
                SetMotor1PosB();
                StepperIndex1 = 'B';
                break;
            case 'D':
                default:
                SetMotor1PosC();
                StepperIndex1 = 'C';
                break;      
        }
        Device1.statusStr.CurrentPosition++;
        Device1.statusStr.IsMoving = 1;
    }   
    _T4IF = 0;          // Clear the Timer 4 Interrupt Flag.
}

目標位置は、移動要求が受信されたときにメイン プログラム ループで設定されます。SetMotorPos 行は、特定のポート ピンをオン/オフするための単なるマクロです。

私の質問は: このコードの効率を改善する方法はありますか? コードは、位置が 16 ビット整数の場合は問題なく機能しますが、32 ビット整数の場合は処理が多すぎます。このデバイスはためらうことなく PC と通信する必要があり、書かれているように、顕著なパフォーマンス ヒットがあります。本当に必要なのは 18 ビット演算だけですが、それを行う簡単な方法がわかりません! 建設的な意見や提案をいただければ幸いです。

4

5 に答える 5

6

警告: すべての数字は構成されています...

上記の ISR にコンパイル済みコードの約 200 (おそらく、それより少ない) 命令があり、それらには ISR の前後に CPU レジスタを保存/復元する命令が含まれ、それぞれに 5 クロック サイクル (おそらく 1 ~ 3) かかり、次のように呼び出すとします。そのうちの 2 つがそれぞれ 1 秒あたり 1000 回、2*1000*200*5 = 1 秒あたり 200 万クロック サイクルまたは 2 MIPS になります。

残りの 38 MIPS を実際に別の場所で消費しますか?

ここで重要かもしれない唯一のことはわかりませんが、SetMotor*Pos*()関数内で行われることです。彼らは複雑な計算をしますか? 送信されたコマンドに応答するのを待つなど、モーターとの通信が遅いですか?

いずれにせよ、このような単純なコードが 16 ビットよりも 32 ビットの整数を扱う場合の方が著しく遅くなるとは思えません。

コードが遅い場合は、どこでどのくらい時間が費やされているかを調べて、プロファイリングします。ISR で方形パルス信号を生成し (ISR が開始すると 1 になり、ISR が戻りそうになると 0 になります)、その持続時間をオシロスコープで測定します。または、それを見つけるのがより簡単なことは何でもしてください。プログラムのすべての部分で費やされた時間を測定し、それまで考えていた場所ではなく、本当に必要な場所を最適化します。

于 2011-11-04T22:12:15.847 に答える
1

インクリメントと比較のみを使用するため、16 ビット演算と 32 ビット演算の違いはそれほど大きくないと思います。しかし、おそらく問題は、各 32 ビット算術演算が関数呼び出しを意味することです (コンパイラがより単純な演算のインライン化を行うことができない/行う意思がない場合)。

1 つの提案は、Device1.statusStr.CurrentPosition を Device1.statusStr.CurrentPositionH と Device1.statusStr.CurrentPositionL のように 2 つに分割して、自分で計算することです。次に、いくつかのマクロを使用して、次のような操作を行います。

#define INC(xH,xL) {xL++;if (xL == 0) xH++;}

于 2011-11-04T22:48:25.820 に答える
0

申し訳ありませんが、あなたは悪いプログラム設計を使用しています。

16ビットと32ビットのPIC24またはPIC33asmコードの違いを確認してみましょう...

16ビット増分

inc    PosInt16               ;one cycle

したがって、16ビットの増分には1サイクルかかります

32ビット増分

clr    Wd                     ;one cycle
inc    low PosInt32           ;one cycle
addc   high PosInt32, Wd      ;one cycle

32の増分には3サイクルかかります。合計の差は2サイクルまたは50ns(ナノ秒)です。

単純な計算ですべてが表示されます。1秒あたり1000ステップと40MipsDSPがあるため、1秒あたり1000ステップで1ステップあたり40000命令があります。十二分に!

于 2011-11-05T10:34:51.353 に答える
0

16 ビットから 32 ビットに変更する場合、コンパイル フラグを変更して、代わりに 32 ビット アプリケーションとしてコンパイルするように指示しますか。

32 ビット拡張でコンパイルしようとしましたが、16 ビット整数のみを使用しましたか。それでもパフォーマンスが低下しますか?

16 ビットから 32 ビットに変更するだけで、一部の操作が異なる方法でコンパイルされる可能性があります。おそらく、コンパイルされた 2 つの ASM コード セット間で Diff を実行し、実際の違いを確認します。

解決策は、32 ビット整数を使用する代わりに、2 つの 16 ビット整数を使用することです。次に、valueA >= 26696 (または unsigned または signed int16 を使用する場合は同様のもの) を確認し、12500 でモーターを確認します。

于 2011-11-07T12:46:16.787 に答える
0

変数を削除しStepperIndex1、代わりに の下位 2 ビットを使用してCurrentPosition、現在のステップ インデックスを追跡します。または、(各ステップではなく) 完全な回転で現在の位置を追跡し、16 ビット変数に収まるようにします。移動するときは、フェーズ「A」に移動するときにのみ位置を増減します。もちろん、これは、すべてのステップではなく、各完全な回転のみをターゲットにできることを意味します。

于 2011-11-04T23:09:13.470 に答える