2014-09-22 47 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); 
    } 
    

这两种优化都消除了寄存器实际写入之间的一系列(簿记)指令,并使得写入的速度快于彼此。