如何确保已读取微控制器外设寄存器

时间:2014-10-31 08:27:45

标签: c embedded microcontroller

让我们以STM32F205微控制器为例。它有硬件SPI接口。 SPI由几个寄存器组成。接收的字节存储在数据寄存器SPI-> DR中。并且当已经接收到新字节时,硬件将SPINE标志(Rx not empy)设置在SPI状态寄存器SPI-> SR中。清除该标志的正确方法是读出数据寄存器SPI-> DR的内容。如果我使用临时变量,它可能会被优化掉(因为它没有被使用):

uint8_t foo = SPI1->DR;

我在嵌入式软件中看到了另一个不寻常的东西,但我不确定它是否正确:

(void)SPI1->DR;

所以我正在寻找如何确保数据寄存器在高优化级别读取的方式。

5 个答案:

答案 0 :(得分:2)

头文件中的所有硬件寄存器都被声明为volatile,因此读取 NEVER 将被优化掉。您显示的构造 - (void)SPI1->DR;(void)部分实际上是多余的)只是 - 一个不会被优化的读取操作,因此您可以安全地使用它并且那个'最好的选择 - 不需要无用的临时变量。这与您有时看到的内容类似(void)0;

答案 1 :(得分:1)

您可以使用volatile关键字来阻止不必要的优化。

volatile uint8_t foo = SPI1->DR;

为避免编译器警告,您可以执行以下操作

(void)foo;

答案 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