让我们以STM32F205微控制器为例。它有硬件SPI接口。 SPI由几个寄存器组成。接收的字节存储在数据寄存器SPI-> DR中。并且当已经接收到新字节时,硬件将SPINE标志(Rx not empy)设置在SPI状态寄存器SPI-> SR中。清除该标志的正确方法是读出数据寄存器SPI-> DR的内容。如果我使用临时变量,它可能会被优化掉(因为它没有被使用):
uint8_t foo = SPI1->DR;
我在嵌入式软件中看到了另一个不寻常的东西,但我不确定它是否正确:
(void)SPI1->DR;
所以我正在寻找如何确保数据寄存器在高优化级别读取的方式。
答案 0 :(得分:2)
头文件中的所有硬件寄存器都被声明为volatile,因此读取 NEVER 将被优化掉。您显示的构造 - (void)SPI1->DR;
((void)
部分实际上是多余的)只是 - 一个不会被优化的读取操作,因此您可以安全地使用它并且那个'最好的选择 - 不需要无用的临时变量。这与您有时看到的内容类似(void)0;
。
答案 1 :(得分:1)
答案 2 :(得分:1)
一种简单的方法是将读取放在单独编译的文件中。一个文件有一个函数读取,返回读取的值,不能优化,必须这样做。另一个文件调用该函数但不使用返回值,无法优化该函数。你有这个函数调用的成本,在这种情况下是相当便宜的,但是在你用llvm或类似的东西优化整个项目之前,它无法优化读取。
另一个解决方案是使用汇编语言制作一个简单的ldr r0,[r0],bx lr函数,传递它的地址。如上所述,因为它位于单独的编译/优化域中,因此无法进行优化。
答案 3 :(得分:0)
通常,SPI rx状态标志由两次读取清除:您读取数据寄存器,但您还需要读取状态寄存器以了解实际状态。由于读取数据寄存器会清除标志,因此您需要先读取状态寄存器。
为了确保存在错误行为并且没有生成错误的代码,我强烈建议将状态和数据寄存器的读取放在代码中。
为避免代码被优化掉,请使用声明为volatile的局部变量。
volatile uint8_t sr = SRI1->SR;
volatile uint8_t dr = SPI1->DR;
// do stuff with sr and dr
(void) dr; // if not interested in the received data
答案 4 :(得分:0)
它不会被优化掉,因为SPI1-> DR应该被声明为volatile
。