2014-09-22 46 views
0

我有一個使用SPI的嵌入式C++項目。當我編譯並運行我的程序時沒有優化(-O0),外圍設備(一個LCD面板)工作正常。當我編譯優化(-O1)時,外圍設備無法正常工作。編譯器優化如何加速簡單操作之間的時間?

我用邏輯分析器檢查了兩種情況,唯一的區別在於優化後的代碼(時鐘速率,寫入的字節等)的寫入字節間的時間要短得多。編譯器優化如何能夠影響後續操作之間的時間,這些操作只是一個接一個地寫入硬件寄存器?如果我在SPI類中的每個寫入命令之後添加一個延遲,它將在優化的情況下工作。

與以下示例不同,在原始代碼中,對WriteCommand()WriteData()的調用是通過指針進行的。

的代碼片段,連續寫入到外設通過SPI:

{ 
    SPI m_spiPort(); 
    m_spiPort.Init(); 

    m_spiPort.WriteCommand(SLEEPOUT); 

    // Color Interface Pixel Format (command 0x3A) 
    m_spiPort.WriteCommand(COLMOD); 
    m_spiPort.WriteData(0x03); // 0x03 = 12 bits-per-pixel 

    // Memory access controller (command 0x36) 
    m_spiPort.WriteCommand(MADCTL); 
    m_spiPort.WriteData(0x00); 

    // Write contrast (command 0x25) 
    m_spiPort.WriteCommand(SETCON); 
    m_spiPort.WriteData(0x39); // contrast 0x30 

    // Display On (command 0x29) 
    m_spiPort.WriteCommand(DISPON); 

} 

SPI類:

class SPI { 
public: 
    void Init(); 
    void WriteCommand(unsigned int command); 
    void WriteData(unsigned int data); 
private: 
    void Write(unsigned int value); 
}; 

這個類的實現是:

void SPI::WriteCommand(unsigned int command) 
{ 
    command &= ~0x100; //clear bit 8 
    Write(command); 
} 

void SPI::WriteData(unsigned int data) 
{ 
    data |= 0x100; //set bit 8 
    Write(data); 
} 

void SPI::Write(unsigned int value) 
{ 
    LPC_SSP->DR = value; 
} 
void SPI::Init(void) 
{ 
    LPC_SYSCON->SYSAHBCLKCTRL |= (1<<11); //Enables clock for SPI 
    LPC_SYSCON->SSPCLKDIV = 0x01; 

    LPC_IOCON->PIO0_14 &= ~(0x7); // SCK 
    LPC_IOCON->PIO0_14 |= 0x2; 

    LPC_IOCON->PIO0_17 &= ~(0x7); // MOSI 
    LPC_IOCON->PIO0_17 |= 0x2; 

    /* SSP SSEL is a GPIO pin */ 
    LPC_IOCON->PIO0_27 = 0x0;  // configure as GPIO pin 
    LPC_GPIO0->MASK = (1<<27); 
    LPC_GPIO0->DIR |= (1<<27); // set in output mode */ 
    LPC_GPIO0->CLR = 1 << 27; 

    /* Set DSS data to 9-bit, Frame format SPI, CPOL = 0, CPHA = 0, and SCR is 0 */ 
    LPC_SSP->CR0 = 0x0008; 

    /* SSPCPSR clock prescale register, master mode, minimum divisor is 0x02 */ 
    LPC_SSP->CPSR = 0x4; // SPI clock will run at 6 MHz 

    /* set Master mode and enable the SPI */ 
    LPC_SSP->CR1 = 0x2; 
} 

編輯 - 從SPI :: Write()中刪除DelayInCycles()。沒有它,這些差異依然很明顯,我不打算把它包含在這篇文章中。

+0

關於哪個目標以及哪個編譯器?優化通常會加快執行時間...... – 2014-09-22 13:27:17

+0

使用'gcc -fverbose-asm -S'編譯使用和不使用優化,並比較生成的彙編代碼。 – 2014-09-22 13:29:09

+5

你在問爲什麼優化後的代碼運行速度更快?這是整個優化的關鍵。 – 2014-09-22 13:29:11

回答

3

對於每個命令和數據字節,您的代碼調用兩個函數,並且這兩個函數都沒有局部變量或許多臨時變量。

當忠實地實現時,這些函數中的每一個都會創建一個堆棧幀(需要一些指令來設置和拆卸)來存儲任何不能存放在寄存器中的局部變量和臨時值。這可能是在-O0編譯模式下發生的。

兩個能夠影響對於這樣的代碼的執行時間重要的優化是:

  • 堆棧幀省略:編譯器通知,對於Write(並且還可能用於WriteCommandWriteData)堆棧幀是未使用的,並且決定以消除設置(和拆除)堆棧幀的指示。
  • 函數內聯:作爲WriteWriteCommandWriteData都非常SIMPL功能,編譯器可以決定完全消除函數調用,並生成代碼,如果你寫了(不計任何可訪問性問題):

    { 
        SPI m_spiPort(); 
        m_spiPort.Init(); 
    
        m_spiPort.LPC_SSP->DR = (SLEEPOUT & ~0x100); 
    
        // Color Interface Pixel Format (command 0x3A) 
        m_spiPort.LPC_SSP->DR = (COLMOD & ~0x100); 
        m_spiPort.LPC_SSP->DR = (0x03 & 0x100); 
    
        // Memory access controller (command 0x36) 
        m_spiPort.LPC_SSP->DR = (MADCTL & ~0x100); 
        m_spiPort.LPC_SSP->DR = (0x00 & 0x100); 
    
        // Write contrast (command 0x25) 
        m_spiPort.LPC_SSP->DR = (SETCON & ~0x100); 
        m_spiPort.LPC_SSP->DR = (0x39 & 0x100); 
    
        // Display On (command 0x29) 
        m_spiPort.LPC_SSP->DR = (DISPON & ~0x100); 
    } 
    

這兩種優化都消除了寄存器實際寫入之間的一系列(簿記)指令,並使得寫入的速度快於彼此。