问题描述
我只是失去了天,从字面上看,约25个小时的工作,因为要调试我的代码在简单的东西,我不知道.
I just lost days, literally, ~25 hrs of work, due to trying to debug my code over something simple that I didn't know.
事实证明,在AVR ATmega328 8位微控制器(Arduino)上,递减C ++中单字节数组的元素不是原子操作,并且需要原子访问保护(即关闭中断).为什么是这样???另外,什么是C语言技术来确保原子自动访问Atmel AVR微控制器上的变量?
It turns out decrementing an element of a single-byte array in C++, on an AVR ATmega328 8-bit microcontroller (Arduino) is not an atomic operation, and requires atomic access guards (namely, turning off interrupts). Why is this??? Also, what are all of the C techniques to ensure atomic access to variables on an Atmel AVR microcontroller?
这是我所做工作的简明版本:
Here's a dumbed down version of what I did:
//global vars:
const uint8_t NUM_INPUT_PORTS = 3;
volatile uint8_t numElementsInBuf[NUM_INPUT_PORTS];
ISR(PCINT0_vect) //external pin change interrupt service routine on input port 0
{
//do stuff here
for (uint8_t i=0; i<NUM_INPUT_PORTS; i++)
numElementsInBuf[i]++;
}
loop()
{
for (uint8_t i=0; i<NUM_INPUT_PORTS; i++)
{
//do stuff here
numElementsInBuf[i]--; //<--THIS CAUSES ERRORS!!!!! THE COUNTER GETS CORRUPTED.
}
}
这是很好的循环版本:
loop()
{
for (uint8_t i=0; i<NUM_INPUT_PORTS; i++)
{
//do stuff here
noInterrupts(); //globally disable interrupts
numElementsInBuf[i]--; //now it's ok...30 hrs of debugging....
interrupts(); //globally re-enable interrupts
}
}
请注意原子访问保护",即:在递减之前禁用中断,然后在中断之后重新启用它们.
Notice the "atomic access guards", ie: disabling interrupts before decrementing, then re-enabling them after.
由于我在这里处理一个字节,所以我不知道我需要原子访问保护.为什么在这种情况下需要它们?这是典型的行为吗?我知道如果这是2个字节的值的数组,我会需要它们,但是为什么要使用1个字节的值呢?通常对于1字节的值,这里不需要原子访问保护...
因此,我们知道在AVR 8位元文件上读取或写入任何单字节变量是原子操作,但是STM32 32位元文件又如何呢? 哪些变量在STM32上具有自动的原子读写功能?答案在这里:哪些变量类型/大小是原子的在STM32微控制器上?.
So we know that reading from or writing to any single-byte variable on AVR 8-bit mcus is an atomic operation, but what about STM32 32-bit mcus? Which variables have automatic atomic reads and writes on STM32? The answer is here: Which variable types/sizes are atomic on STM32 microcontrollers?.
推荐答案
好,答案是为什么要增加/减少单字节变量不是原子的?" 此处的伊沙梅尔和.
Ok, the answer to "Why is incrementing/decrementing a single byte variable NOT atomic?" is answered very well here by Ishamael here, and Michael Burr here.
现在我得到了答案,即使对字节值进行了操作,--
减量和++
增量操作也永远不会是原子的(请参见上面的答案和尼克·卡蒙(Nick Gammon)的链接),我想确保对如何强制在Atmel AVR微控制器上强制原子化的后续问题是还回答了这个问题,因此成为某种资源:
Now that I got my answer that --
decrement and ++
increment operations are never atomic, even when done on byte values (see answers above and Nick Gammon's link here), I'd like to ensure the follow-up question of how do I force atomicity on Atmel AVR microcontrollers is also answered so this question becomes somewhat of a resource:
1)选项1(首选方法):
uint8_t SREG_bak = SREG; //save global interrupt state
noInterrupts(); //disable interrupts (for Arduino only; this is an alias of AVR's "cli()")
//atomic variable-access code here
SREG = SREG_bak; //restore interrupt state
2)选项2(不太安全,不建议使用的方法,因为如果您不小心在ISR内部调用的代码块或库中使用此方法,可能会导致您无意中启用嵌套中断):
noInterrupts(); //disable interrupts (Arduino only; is an alias to AVR's "cli()" call)
//atomic variable-access code here
interrupts(); //enable interrupts (Arduino only; is an alias to AVR's "sei()" call)
替代方法2:
cli(); //clear (disable) interrupts flag; noInterrupts() is simply a macro for this
//atomic variable-access code here
sei(); //set (enable) interrupts flag; interrupts() is simply a macro for this
3)选项3(与选项1基本相同;只是使用avr-libc库中保留的宏,并且在括号内应用了可变范围)
来源: http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html
3) Option 3 (essentially the same as option 1; just using a macro held in an avr-libc library instead, and with variable scope applied within the braces of course)
source: http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html
#include <util/atomic.h> //(place at top of code)
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
{
//atomic access code here
}
相关:
- 哪些变量类型/大小在STM32上是原子的微控制器?
- https://stm32f4-discovery.net/2015/06/如何正确启用isable-interrupts-in-arm-cortex-m/
- Which variable types/sizes are atomic on STM32 microcontrollers?
- https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/
这篇关于C ++递减单字节(易失性)数组的元素不是原子的!为什么? (另外:我如何在Atmel AVR mcus/Arduino中强制原子化)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!