Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Разное поведение в отладчике и без него.
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
tdi@013h
Дано: KEIL, плата на stm32f103rb, ULINK2.
Задача: поморгать диодами.
Код:
Код
int main(void)
{
    InitHardware();
    for (;;)
    {
        GPIO_ResetBits(Led_1);
        Wait(25000);
        GPIO_ResetBits(Led_2);
        Wait(25000);
        GPIO_SetBits(Led_1);
        Wait(25000);
        GPIO_SetBits(Led_2);
        Wait(25000);
    }
}

Код
void Wait(int Count)
{
    for(; Count !=0; Count--);
}


Когда расставляю брэйкпоинты по телу фона и хожу в отладчике по шагам, то все моргает в нужной последовательности.
Когда отключаю дебаггер, делаю ресет и запускаю, то оба диода просто горят.
Что я делаю не так? И почему так происходит?
mdmitry
Цитата(tdi@013h @ Apr 28 2012, 18:29) *
Код
void Wait(int Count)
{
    for(; Count !=0; Count--);
}

Как Вы думаете, сколько времени выполняется эта функция? У Вас 25000 циклов выполняется при тактовой в МГц. Сделайте задержки большими и лучше штатными средствами типа delay. Посмотрите библиотеку к вашему компилятору.
scifi
Цитата(tdi@013h @ Apr 28 2012, 18:29) *
Когда отключаю дебаггер, делаю ресет и запускаю, то оба диода просто горят.

Действительно забавно. Они моргают, только быстро-быстро :-)
Точные задержки нужно к аппаратным таймерам привязывать. Компилятор может просто выкинуть ваш цикл ожидания и будет прав.
Сергей Борщ
QUOTE (scifi @ Apr 28 2012, 17:57) *
Компилятор может просто выкинуть ваш цикл ожидания и будет прав.
99.99%, что он именно так и сделал. Чтобы этого избежать, можно объявить Count как volatile.
tdi@013h
Цитата(mdmitry @ Apr 28 2012, 17:53) *
Как Вы думаете, сколько времени выполняется эта функция? У Вас 25000 циклов выполняется при тактовой в МГц. Сделайте задержки большими и лучше штатными средствами типа delay. Посмотрите библиотеку к вашему компилятору.

Скопировал 1в1 функцию из примера моргалки к своей плате.

Компилятор проверю, потому как пересаживаюсь из Eclipse и arm-none-eabi-gcc на Keil и его компилятор, там такие фокусы работали.
Общую идею понял, спасибо.
Сергей Борщ
QUOTE (tdi@013h @ Apr 30 2012, 05:09) *
пересаживаюсь из Eclipse и arm-none-eabi-gcc на Keil и его компилятор, там такие фокусы работали.
Только при отключении оптимизации (-O0).
toweroff
задержки а-ля
for(i=0;i<NEED_SIZE;i++)
в отдельно взятой функции проходили и здесь жевали уже. Все верно, либо оптимизацию в 0, либо volatile
+1 в общем sm.gif
ViKo
У меня в Keil задержки в виде
#define Delay(TIME) for (uint32 i=(72000000/4*TIME); i ; i--)
не оптимизировались до выбрасывания никогда.

А у топикстартера частота моргания диодов порядка 180 Гц. Нужно иметь слишком зоркий глаз... соколиный sm.gif
Dog Pawlowa
Цитата(ViKo @ Apr 30 2012, 23:37) *
У меня в Keil задержки не оптимизировались до выбрасывания никогда.

Что свидетельствует о качестве оптимизации хвалёного кайла wink.gif
ViKo
Цитата(Dog Pawlowa @ May 1 2012, 04:50) *
Что свидетельствует о качестве оптимизации хвалёного кайла wink.gif

Просто Кайл знает, чего хотят люди, когда пишут такие циклы.

Доводя мысль до абсурда - зачем вообще что-то компилировать, если устройство рано или поздно отключится (сдохнет)?

__nop, кстати, тоже никогда не выбрасывается.
toweroff
Цитата(Dog Pawlowa @ May 1 2012, 05:50) *
Что свидетельствует о качестве оптимизации хвалёного кайла wink.gif

так вроде ж это инструменты самого ARM, или я не прав?
Сергей Борщ
QUOTE (ViKo @ May 1 2012, 09:25) *
Просто Кайл знает, чего хотят люди, когда пишут такие циклы.
Телепатически узнает?
QUOTE (ViKo @ May 1 2012, 09:25) *
__nop, кстати, тоже никогда не выбрасывается.
Потому что он либо intrinsic-функция, о которой компилятор знает, что она с побочными эффектами, либо это asm volatile вставка.
aaarrr
Цитата(ViKo @ May 1 2012, 00:37) *
У меня в Keil задержки в виде
#define Delay(TIME) for (uint32 i=(72000000/4*TIME); i ; i--)
не оптимизировались до выбрасывания никогда.

Старые версии RVCT действительно не выбрасывали подобные конструкции. Но в новых такой фокус уже не пройдет.
ViKo
Результаты экспериментов с Keil 4.50 следующие.
Цикл вида
#define DELAY(TIME) for (uint32_t i = (24000000 / 4 * TIME); i-- ; )
выбрасывается в Keil в единственном случае - когда выбрана Optimization Level 3 и Optimize for Time. При остальных настройках - остается.
Размер кода для цикла вида
#define DELAY(TIME) for (volatile uint32_t i = (24000000 / 4 * TIME); i-- ; )
при Optimization Level 1, 2, 3 больше, чем без volatile. Но экономить на 4-х байтах смысла нет, поэтому лучше использовать volatile. Ну, и, естественно, такой цикл не выбрасывается.

Так что, Keil - оправдан. sm.gif
ViKo
Продолжение экспериментов. Исходный код:
Код
#define DELAY(TIME) for (volatile uint32_t i = (24000000 / 4 * TIME); i--; )
uint32_t cnt;
int32_t main(void)
{
  __nop;
  while (1) {
    cnt++;
    __nop; __nop; __nop;
    DELAY(0.001);
  }
}

Компилируется в следующий, при -O1 (при -O0 появляется одна команда NOP)
Код
;;;94     int32_t main(void)
000000  4a16              LDR      r2,|L1.92|
;;;95     {
;;;96       __nop;
;;;97       while (1) {
;;;98         cnt++;
;;;99         __nop; __nop; __nop;
;;;100        DELAY(0.001);
000002  f2417370          MOV      r3,#0x1770
                  |L1.6|
000006  6810              LDR      r0,[r2,#0]           ;98 ; cnt
000008  1c40              ADDS     r0,r0,#1             ;98
00000a  6010              STR      r0,[r2,#0]           ;98 ; cnt
00000c  4619              MOV      r1,r3
                  |L1.14|
00000e  0008              MOVS     r0,r1
000010  f1a10101          SUB      r1,r1,#1
000014  d1fb              BNE      |L1.14|
000016  e7f6              B        |L1.6|
;;;101      }
;;;102    }

Как!? Как это согласуется с цитатой из помощи:
Цитата
__nop
This intrinsic inserts a NOP instruction or an equivalent code sequence into the instruction stream generated by the compiler. One NOP instruction is generated for each __nop intrinsic in the source.

The compiler does not optimize away the NOP instructions, except for normal unreachable code elimination. The __nop intrinsic also acts as a barrier for instruction scheduling in the compiler. That is, instructions are not moved from one side of the NOP to the other as a result of optimization.
ViKo
Ох, дал маху! sm.gif
Крутил-вертел эти __nop - выкидывает Keil, и всё! Запаниковал уже. Оказалось, писать нужно __nop(), это же, типа, функция. sm.gif Знал, но забыл.
Теперь не выкидывает ни при каких настройках оптимизации. Что и должно быть.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.