Перейти к содержанию
    

Keil uVision ARM v 5.16a странное поведение

1)

 

Собираю проект в Keil ARM 5.16a для STM32F407 с максимальной оптимизацией по скорости Otime, O3.

 

По мере написания проекта столкнулся со странным поведением, при максимальной оптимизации O3 программа иногда идёт иногда нет, зависит от порядка расположения переменных, функций. Если поменять их порядок местами, то иногда удаётся получить работающий код при O3.

 

Опытным путём через #pragma optimize был выявлен проблемный кусок: им оказалась точка входа в main(). Если всё заоптимизировать с O3, но точку входа в main сделать O1 (выше может не пойти), то будет работать:

 

#pragma push
#pragma Otime
#pragma O3

//Тут переменные, функции , константы, макросы............

//Точка входа в main с уровнем оптимизации не более O1, если поставить выше, то в некоторых случаях может не заработать. Глюк Keil ???
#pragma push
#pragma Otime
#pragma O1

int main(void)
{
#pragma push
#pragma Otime
#pragma O3

//тут программа.........

#pragma pop
}

#pragma pop

#pragma pop

 

С чем может быть связано такое поведение?

 

2)

Использую CMSIS-овскую функцию __REV16(), в ассемблерном листинге она вставляется в виде перехода на функцию, а не как одна ассемблерная инструкция.

Причем остальные типа: __REV() , __CLZ() встраиваются в виде инструкций.

 

Заменил __REV16() на :

inline u32  rev16(u32 x)
{
__asm("REV16 x,x");
  return x;
}

 

и в листинге идёт вставка ассемблерной инструкции без перехода как на функцию.

 

Получается, что используя CMSIS , доверяй, но проверяй?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странно. Использовал _REV16 и аналогичные и в KEIL и в IAR - не замечал никаких глюков. Оптимизация максимальная по скорости.

В кейле я сейчас не работаю. Проект был на старом месте работы. Как меняет IAR эти макросы - могу посмотреть, если хотите.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

программа иногда идёт иногда нет, зависит от порядка расположения переменных, функций. Если поменять их порядок местами, то иногда удаётся получить работающий код при O3

посмотрите map-файл, что располагается в памяти рядом с main() в нерабочих билдах, и что в рабочих билдах. Соседи меняются? Вот соседей и проверять дальше попробовать

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1) UB, либо выход за пределы массива - 99%. Вообще 99% случаев когда говорят об ошибках в компиляторе на самом деле ошибка в исходниках. :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Думаю, если вы используете микроконтроллер - значит используете периферию. Если периферию - значит возможно прерывания. Если прерывания - то не забывайте VOLATILE ставить где надо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Странно. Использовал _REV16 и аналогичные и в KEIL и в IAR - не замечал никаких глюков. Оптимизация максимальная по скорости.

В кейле я сейчас не работаю. Проект был на старом месте работы. Как меняет IAR эти макросы - могу посмотреть, если хотите.

 

С IAR-ом незнаком, смотреть лучше в любом случае, если критично по скорости.

 

1) UB, либо выход за пределы массива - 99%. Вообще 99% случаев когда говорят об ошибках в компиляторе на самом деле ошибка в исходниках. :)

 

UB - undefined behavior (неопределенное поведение?). Вполне возможно, что вы правы, приходится много работать с чужими исходными кодами, в которых может быть всё что угодно.

Утечка памяти и выход за пределы массива с нечётко объявленными границами, например.

 

Вот недавно пришлось скрестить C + C++ + ASM :)

Потому что часть исходников написаны на плюсах, с объявлением классов, а часть обработки звука на Асме :)

 

 

 

Думаю, если вы используете микроконтроллер - значит используете периферию. Если периферию - значит возможно прерывания. Если прерывания - то не забывайте VOLATILE ставить где надо.

:) Я очень ревностно слежу за волатайлами, чтоб они были объявлены должным образом!

Все регистры периферии, порты ввода-выводи и переменные в обработчиках прерываний, использующиеся внаружу - всё volatile :)

 

Чтоб небыть голословным:

 

Дано: Keil uVision 5.16a. Более старшие не идут в WinXP. Версии компилеров: 5.06(build 20) и 5.05 upd.2 (build 169).

Оптмизация: -O3, -oTime (максимальная по скорости). Установка глобальная. В сорцах прочих прагм оптимизации нет.

 

Фрагмент кода:

*pL++=(__REV16(G)&0xFF0000FF)|(R&0x00FF0000)|(B&0x0000FF00);

 

В листинге выглядит так:

...
    RRS     r0,r0,r1
        STR      r0,[r4],#4
        MOV      r0,r11
        BL       __asm___6_main_c_NEXT____REV16
        BFC      r0,#8,#16
        AND      r1,r7,#0xff0000
        ORRS     r0,r0,r1
...

    AREA ||.rev16_text||, CODE
    THUMB
    EXPORT |__asm___6_main_c_NEXT____REV16|
#line 129 "C:\\Keil_v5\\ARM\\CMSIS\\Include\\core_cmInstr.h"
|__asm___6_main_c_NEXT____REV16| PROC
#line 130

rev16 r0, r0
bx lr
    ENDP
...

 

Смешно и грустно одовременно. Пришлось с-инлайнить самостоятельно.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А по первому пункту вопроса, в ходе копаний стало ясно почему программа не работала с -O3.

 

Не стартовал ЦАП и не происходило прерывание от него, которое синхронизировало внутренний цикл программы. Программа просто зависала и ждала снятия флага по прерыванию.

 

А ЦАП не стартовал из-за некорректной отработки функции инициализации ЦАП+ДМА+Таймер.

Заменил обычную память под выделяемые структуры на динамическую. Всё сразу заработало!

 

Вполне возможно, что SPL-ный говнокод приводит к большому потреблению памяти на структуры инициализации и переполнению стека, что при разных оптимизациях вполне возможно.

Ну и как проинитил часть железа - сразу осовобожать память.

 

Вот фрагмент кода в котором происходила проблема:

 

static void DAC_DMA_IRQ_Config()
{
DMA_DeInit(DMA1_Stream5);

DMA_InitTypeDef *DMA_InitStructure=malloc(sizeof(DMA_InitTypeDef));

DMA_InitStructure->DMA_Channel           =DMA_Channel_7;
DMA_InitStructure->DMA_PeripheralBaseAddr=DAC_DHR12R1;
DMA_InitStructure->DMA_Memory0BaseAddr   =(u32)&AudioBuffer;
DMA_InitStructure->DMA_DIR               =DMA_DIR_MemoryToPeripheral;
DMA_InitStructure->DMA_BufferSize        =L<<1;
DMA_InitStructure->DMA_PeripheralInc     =DMA_PeripheralInc_Disable;
DMA_InitStructure->DMA_MemoryInc         =DMA_MemoryInc_Enable;
DMA_InitStructure->DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure->DMA_MemoryDataSize    =DMA_MemoryDataSize_HalfWord;
DMA_InitStructure->DMA_Mode              =DMA_Mode_Circular;
DMA_InitStructure->DMA_Priority          =DMA_Priority_VeryHigh;
DMA_InitStructure->DMA_FIFOMode          =DMA_FIFOMode_Disable;
DMA_InitStructure->DMA_FIFOThreshold     =DMA_FIFOThreshold_HalfFull;
DMA_InitStructure->DMA_MemoryBurst       =DMA_MemoryBurst_Single;
DMA_InitStructure->DMA_PeripheralBurst   =DMA_PeripheralBurst_Single;

DMA_Init(DMA1_Stream5,DMA_InitStructure);

free(DMA_InitStructure);

DMA_ITConfig(DMA1_Stream5,DMA_IT_HT|DMA_IT_TC,ENABLE);

NVIC_InitTypeDef *NVIC_InitStructure=malloc(sizeof(NVIC_InitStructure));

NVIC_InitStructure->NVIC_IRQChannel=DMA1_Stream5_IRQn;
NVIC_InitStructure->NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure->NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure->NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(NVIC_InitStructure);

free(NVIC_InitStructure);

DAC_InitTypeDef *DAC_InitStructure=malloc(sizeof(DAC_InitTypeDef));

DAC_InitStructure->DAC_Trigger       =DAC_Trigger_T6_TRGO;
DAC_InitStructure->DAC_WaveGeneration=DAC_WaveGeneration_None;
DAC_InitStructure->DAC_OutputBuffer  =DAC_OutputBuffer_Enable;
DAC_Init(DAC_Channel_1,DAC_InitStructure);

free(DAC_InitStructure);
}

 

Но стоит только выделить под структуры статическую память (а она будет будет взята из секции стека, так как идёт из вызова процедуры), работать при -O3 перестанет.

 

Код работает и со статической памятью, если его вызвать не как функцию, а в main() написать всё что внутри void DAC_DMA_IRQ_Config(). Потому что память на структуры берется уже не из секции стека, а из секции DATA, которая больше. К сожалению говнокод, который в SPL приводит к таким вот неприятным вещам ...

 

Проблема решена. :)

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Глюки с прагмами, как заявляет разработчик, решены только в самой последней версии компилятора 5.06 update 6 (build 750), которая даже новей, чем внутри MDK ARM версии 5.24a.

https://developer.arm.com/products/software...loads/version-5

Проще внедрить в Keil новый компилятор установив его в каталог Keil_v5\ARM\ARMCC

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Глюки с прагмами, как заявляет разработчик, решены только в самой последней версии компилятора 5.06 update 6 (build 750), которая даже новей, чем внутри MDK ARM версии 5.24a.

https://developer.arm.com/products/software...loads/version-5

Проще внедрить в Keil новый компилятор установив его в каталог Keil_v5\ARM\ARMCC

 

Тут беда была не из-за прагм. Прагмы как раз работали. И компилятор свежий (версии тоже писал выше). Скачал ARM Compiler V6. Попробую его к Кейлу прикрутить (если будет клянчить лицензию - тогда fail)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...