簡體   English   中英

在16位處理器上提高32位數學性能

[英]Increasing performance of 32bit math on 16bit processor

我正在為嵌入式設備開發一些固件,該設備使用16位PIC,工作速率為40 MIPS,並以C編程。系統將控制兩個步進電機的位置,並始終保持每個電機的步進位置。 每個電機的最大位置大約是125000步,所以我不能使用16位整數來跟蹤位置。 我必須使用32位無符號整數(DWORD)。 電機以每秒1000步的速度移動,我設計了固件,以便在定時器ISR中處理步驟。 計時器ISR執行以下操作:

1)將一個電機的當前位置與目標位置進行比較,如果它們是相同的,則設置isMoving標志為false並返回。 如果它們不同,則將isMoving標志設置為true。

2)如果目標位置大於當前位置,向前移動一步,然后增加當前位置。

3)如果目標位置小於當前位置,向后移動一步,然后減小當前位置。

這是代碼:

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位數學,但我不知道這樣做的簡單方法! 任何建設性的意見/建議都將非常受歡迎。

警告:所有號碼都已組成......

假設上面的ISR有大約200(可能,更少)編譯代碼指令,那些包括在ISR之前和之后保存/恢復CPU寄存器的指令,每個指令占用5個時鍾周期(可能是1到3)並且你調用其中2個每秒1000次,我們最終得到2 * 1000 * 200 * 5 =每秒2百萬個時鍾周期或2 MIPS。

你真的在其他地方消費38 MIPS嗎?

唯一可能重要的是我無法看到它,就是在SetMotor * Pos *()函數內部完成的事情。 他們做任何復雜的計算嗎? 他們是否與電機進行一些慢速通信,例如等待它們響應發送給它們的命令?

無論如何,使用32位整數而不是使用16位時,這種簡單的代碼會明顯變慢,這是值得懷疑的。

如果您的代碼很慢,請找出花費的時間和數量,然后對其進行分析。 在ISR中生成方波脈沖信號(當ISR開始時變為1,當ISR即將返回時變為0)並用示波器測量其持續時間。 或者做任何更容易找到的事情。 測量在程序的所有部分花費的時間,然后優化真正需要的地方,而不是您之前認為的那樣。

我認為,16位和32位算術之間的差異不應該那么大,因為你只使用增量和比較。 但也許問題是每個32位算術運算意味着一個函數調用(如果編譯器不能/不願意進行簡單操作的內聯)。

一個建議是通過將Device1.statusStr.CurrentPosition和Device1.statusStr.CurrentPositionH和Device1.statusStr.CurrentPositionL中的Device1.statusStr.CurrentPosition分開來自己做算術。 然后使用一些宏來執行操作,例如:

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

我將擺脫StepperIndex1變量,而是使用CurrentPosition的兩個低位來跟蹤當前步驟索引。 或者,在完整旋轉(而不是每個步驟)中跟蹤當前位置,因此它可以適合16位變量。 移動時,只有在移動到階段'A'時才增加/減少位置。 當然,這意味着您只能定位每個完整的旋轉,而不是每一步。

抱歉,您使用的程序設計不好。

我們來檢查16位和32位PIC24或PIC33 asm代碼之間的區別......

16位增量

inc    PosInt16               ;one cycle

因此16位增量需要一個周期

32位增量

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

32增量需要三個周期。 總差異為2個周期或50ns(納秒)。

簡單的鈣化將向您展示所有。 您每秒有1000步和40Mips DSP, 因此您每步可以獲得40000條指令,每秒1000步。 綽綽有余!

當您將其從16位更改為32位時,您是否更改了任何編譯標志,以告訴它編譯為32位應用程序。

您是否嘗試使用32位擴展進行編譯,但僅使用16位整數。 你還有這樣的性能下降嗎?

可能只是通過從16位更改為32位,某些操作的編譯方式不同,也許在兩組編譯的ASM代碼之間進行差異,看看實際上有什么不同,它是很多還是只有幾行。

解決方案可能是使用32位整數而不是使用兩個16位整數,當值A為int16.Max然后將其設置為0然后將valueB遞增1,否則只是將ValueA加1,當值B> = 3時然后檢查valueA> = 26696(或類似的東西取決於你是否使用unsigned或signed int16)然后你的電機檢查在12500。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM