Я получаю неожиданные результаты чтения глобальной переменной при компиляции следующего кода в avr-gcc 4.6.2 для ATmega328:
#include <avr/io.h>
#include <util/delay.h>
#define LED_PORT PORTD
#define LED_BIT 7
#define LED_DDR DDRD
uint8_t latchingFlag;
int main() {
LED_DDR = 0xFF;
for (;;) {
latchingFlag=1;
if (latchingFlag==0) {
LED_PORT ^= 1<<LED_BIT; // Toggle the LED
_delay_ms(100); // Delay
latchingFlag = 1;
}
}
}
Это весь код. Я ожидаю, что переключение светодиода никогда не будет выполняться, поскольку latchingFlag
установлено на 1
, однако светодиод постоянно мигает. Если latchingFlag
объявлен локальным для main()
, программа выполняется так, как ожидалось: светодиод никогда не мигает.
Дизассемблированный код не обнаруживает каких-либо ошибок, которые я вижу, вот разборка основного цикла версии с использованием глобальной переменной (с закомментированным вызовом процедуры задержки; такое же поведение)
59 .L4:
27:main.cpp **** for (;;) {
60 .loc 1 27 0
61 0026 0000 nop
62 .L3:
28:main.cpp **** latchingFlag=1;
63 .loc 1 28 0
64 0028 81E0 ldi r24,lo8(1)
65 002a 8093 0000 sts latchingFlag,r24
29:main.cpp **** if (latchingFlag==0) {
66 .loc 1 29 0
67 002e 8091 0000 lds r24,latchingFlag
68 0032 8823 tst r24
69 0034 01F4 brne .L4
30:main.cpp **** LED_PORT ^= 1<<LED_BIT; // Toggle the LED
70 .loc 1 30 0
71 0036 8BE2 ldi r24,lo8(43)
72 0038 90E0 ldi r25,hi8(43)
73 003a 2BE2 ldi r18,lo8(43)
74 003c 30E0 ldi r19,hi8(43)
75 003e F901 movw r30,r18
76 0040 3081 ld r19,Z
77 0042 20E8 ldi r18,lo8(-128)
78 0044 2327 eor r18,r19
79 0046 FC01 movw r30,r24
80 0048 2083 st Z,r18
31:main.cpp **** latchingFlag = 1;
81 .loc 1 31 0
82 004a 81E0 ldi r24,lo8(1)
83 004c 8093 0000 sts latchingFlag,r24
27:main.cpp **** for (;;) {
84 .loc 1 27 0
85 0050 00C0 rjmp .L4
Строки 71-80 отвечают за доступ к порту: согласно даташиту, PORTD
находится по адресу 0x2B
, который является десятичным 43
(ср. строки 71-74).
Единственная разница между локальным/глобальным объявлением переменной latchingFlag
заключается в том, как осуществляется доступ к latchingFlag
: версия с глобальной переменной использует sts
(сохранение непосредственно в пространстве данных) и lds
(загрузка непосредственно из пространства данных) для доступа к latchingFlag
, тогда как версия с локальной переменной использует ldd
(Косвенная загрузка из пространства данных в регистр) и std
(Сохранение косвенного из регистра в пространство данных) с использованием регистра Y
в качестве адресного регистра (который может использоваться в качестве указателя стека, avr-gcc AFAIK). Вот соответствующие строки из разборки:
63 002c 8983 std Y+1,r24
65 002e 8981 ldd r24,Y+1
81 004a 8983 std Y+1,r24
Глобальная версия также имеет latchingFlag
в разделе .bss. Мне действительно не к чему приписывать различное поведение глобальных и локальных переменных. Вот командная строка avr-gcc (обратите внимание -O0
):
/usr/local/avr/bin/avr-gcc \
-I. -g -mmcu=atmega328p -O0 \
-fpack-struct \
-fshort-enums \
-funsigned-bitfields \
-funsigned-char \
-D CLOCK_SRC=8000000UL \
-D CLOCK_PRESCALE=8UL \
-D F_CPU="(CLOCK_SRC/CLOCK_PRESCALE)" \
-Wall \
-ffunction-sections \
-fdata-sections \
-fno-exceptions \
-Wa,-ahlms=obj/main.lst \
-Wno-uninitialized \
-c main.cpp -o obj/main.o
С флагами компилятора -Os
цикл исчезает из разборки, но может быть вынужден снова появиться, если latchingFlag
объявлен volatile
, и в этом случае неожиданное для меня сохраняется.
-Werror -O0
в командную строку, компилятор выдает ошибку:functions from <util/delay.h> won't work as designed" [-Werror=cpp]
. Когда я меняю его на-Werror -Os
, ошибка исчезает. - person jippie   schedule 16.04.2013-O
!=0
. Непредвиденное поведение возникает независимо от того, используются функции задержки или нет, и поведение, описанное выше, одинаково независимо от того, является лиutil/delay.h
#include
d или нет. - person angelatlarge   schedule 16.04.2013_delay_ms(100)
строки в вашем листинге дизассемблера? - person Egor Skriptunoff   schedule 16.04.2013_delay_ms(100)
был удален при дизассемблировании. Поведение идентично независимо от того, сделан ли вызов_delay_ms()
или нет. - person angelatlarge   schedule 17.04.2013