Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Настройка GCC компилятора для CortexM4
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
sidy
Здравствуйте, уважаемые форумчане. Пытаюсь настроить GCC компилятор для работы с STM32F4. Нашел на сайте gcc что для оптимального использования инструкций процессора необходимо задать ключ -mtune со следующими атрибутами: -mtune=arm7m. STM32F4 (Cortex-M4) выполнен архитектуре ARMv7E-M и поддерживает DSP инструкции. А ключ -mtune=arm7m относится к процессорам Cortex-M3 (архитектура ARMv7-M) - которые не поддерживают DSP. Кто знает какой атрибут ключа должен быть задан для ARMv7E-M?
etoja
-mcpu=cortex-m4 -mthumb -c -Os -std=c99 -Wall -Wl,--gc-sections -Wno-psabi -mfpu=fpv4-sp-d16 -mfloat-abi=softfp -ffunction-

( h..p://code.google.com/p/yus-repo/downloads/detail?name=lm4f-gcc-arm-ide-win32.7z )
Kornelij
Посмотри здесь:
http://electronix.ru/forum/lofiversion/ind...hp/t106724.html
sidy
Цитата(Kornelij @ Jul 2 2013, 15:45) *

По-моему это не серьезно. Компилятор, если ему указать, должен сам подставлять нужные инструкции.
sidy
Сравнивал два компилятора GCC 4.7 и ARMCC 4.1.0 в Keil'e. Код вида i+=a*a эти компиляторы исполняют по разному. В ARMCC это выглядит следующим образом:
Нажмите для просмотра прикрепленного файла
т.е. используется одна команда MLA ( Multiply with accumulate).
А GCC делает этот код следующим образом:
Нажмите для просмотра прикрепленного файла
сначала mul (умножение) потом adds (add with substract).
Т.е. команд в GCC становится на 3 больше. Вопрос можно ли заставить gcc использовать такие же инструкции как и в ARMCC. (MLA не DSP инструкция).
Уровни оптимизации одинаковые -O0
Сергей Борщ
QUOTE (sidy @ Jul 3 2013, 07:03) *
Уровни оптимизации одинаковые -O0
gcc сделал именно то, что вы просили - сначала умножил, потом прибавил. И без всякой самодеятельности, ибо оптимизацию вы ему запретили. Попробуйте -Os, -O3, тогда можно будет что-то сравнивать.
sidy
Задам еще один вопрос: сейчас использую CooCox CoIDE и программа сваливается в заглушку Default Handler. И я не знаю как посмотреть стэк (и можно ли это вообще сделать) в CoIDE. В Keil это можно было сделать - там был stack view, в котором видно, какая функция вызывалась последней. Есть ли такая возможность в CoIDE? И если нет, то как выяснять откуда попадаем в Default Handler?
jcxz
Прочитать наконец доку на используемое ядро.
Посмотреть содержимое LR. По нему определить стек возврата (PSP или MSP). Прочитать 8 слов с этого стека.
sidy
Вот я снова получил Default Handler:
Нажмите для просмотра прикрепленного файла
в LR содержится 0xFFFFFFF1, но прочитав документ Cortex M4 programming manual не нашел как по содержимому LR определить стек возврата MSP или PSP.
Сергей Борщ
Невнимательно вы читали. Раздел "Exception model", пункт 2.3.7 "Exception entry and return", таблица 18. Это если речь идет о документе от ST "STM32F3xxx and STM32F4xxx Cortex-M4 programming manual". Если у вас другой - дайте полное название или ссылку.
klen
GCC не умет???????????????

c-код
Код
  NOP();
  NOP();
  NOP();
  i+=a*b;
  NOP();
  NOP();
  NOP();



ключи -mcpu=cortex-m3 -mfloat-abi=soft -mthumb -Os -fomit-frame-pointer -finline-functions -ffunction-sections -fdata-sections -fgraphite -funroll-loops -flto=8

выход компиллера
Код
80016d0:    bf00          nop
  NOP();
80016d2:    bf00          nop
  NOP();
80016d4:    bf00          nop
  i+=a*b;
80016d6:    4f59          ldr    r7, [pc, #356]; (800183c <ResetHandler.4045+0x880>)
80016d8:    4b59          ldr    r3, [pc, #356]; (8001840 <ResetHandler.4045+0x884>)
80016da:    680e          ldr    r6, [r1, #0]
80016dc:    6818          ldr    r0, [r3, #0]
80016de:    683a          ldr    r2, [r7, #0]
80016e0:    fb00 2406     mla    r4, r0, r6, r2
80016e4:    603c          str    r4, [r7, #0]
  NOP();
80016e6:    bf00          nop
  NOP();
80016e8:    bf00          nop
  NOP();
80016ea:    bf00          nop


под четверку тем более....
SII
Цитата(sidy @ Dec 6 2013, 09:25) *
в LR содержится 0xFFFFFFF1, но прочитав документ Cortex M4 programming manual не нашел как по содержимому LR определить стек возврата MSP или PSP.


Читать надо документацию на архитектуру в целом. Конкретно по прерывания можно на русском посмотреть здесь.
sidy
Как написано в ReferenceManual во время исключения в LR записывается значение EXC_RETURN. У меня в LR записано 0xFFFFFFF1. Как написано в RM такое значение появляется при: Return to Handler mode, exception return uses non-floating-point state from the MSP and execution uses MSP after return. Т.е. теперь мне необходимо в DefaultHandler прочитать MSP следующим образом: uint32_t i=__get_MSP(), и в i будет содержаться адрес с которого программа попадает в HardFault. Правильно ли я понял?
A. Fig Lee
Цитата(sidy @ Dec 16 2013, 09:55) *
Как написано в ReferenceManual во время исключения в LR записывается значение EXC_RETURN. У меня в LR записано 0xFFFFFFF1. Как написано в RM такое значение появляется при: Return to Handler mode, exception return uses non-floating-point state from the MSP and execution uses MSP after return. Т.е. теперь мне необходимо в DefaultHandler прочитать MSP следующим образом: uint32_t i=__get_MSP(), и в i будет содержаться адрес с которого программа попадает в HardFault. Правильно ли я понял?


Вот код стыбренный на просторах интернета (на форуме st) для Cortex M3:


Код
   void hard_fault_handler_c(unsigned int * hardfault_args)
{
  unsigned int stacked_r0;
  unsigned int stacked_r1;
  unsigned int stacked_r2;
  unsigned int stacked_r3;
  unsigned int stacked_r12;
  unsigned int stacked_lr;
  unsigned int stacked_pc;
  unsigned int stacked_psr;

  stacked_r0 = ((unsigned long) hardfault_args[0]);
  stacked_r1 = ((unsigned long) hardfault_args[1]);
  stacked_r2 = ((unsigned long) hardfault_args[2]);
  stacked_r3 = ((unsigned long) hardfault_args[3]);

  stacked_r12 = ((unsigned long) hardfault_args[4]);
  stacked_lr = ((unsigned long) hardfault_args[5]);
  stacked_pc = ((unsigned long) hardfault_args[6]);
  stacked_psr = ((unsigned long) hardfault_args[7]);

  printf ("[Hard fault handler]\n");
  printf ("R0 = %x\n", stacked_r0);
  printf ("R1 = %x\n", stacked_r1);
  printf ("R2 = %x\n", stacked_r2);
  printf ("R3 = %x\n", stacked_r3);
  printf ("R12 = %x\n", stacked_r12);
  printf ("LR = %x\n", stacked_lr);
  printf ("PC = %x\n", stacked_pc);
  printf ("PSR = %x\n", stacked_psr);
  printf ("BFAR = %x\n", (*((volatile unsigned long *)(0xE000ED38))));
  printf ("CFSR = %x\n", (*((volatile unsigned long *)(0xE000ED28))));
  printf ("HFSR = %x\n", (*((volatile unsigned long *)(0xE000ED2C))));
  printf ("DFSR = %x\n", (*((volatile unsigned long *)(0xE000ED30))));
  printf ("AFSR = %x\n", (*((volatile unsigned long *)(0xE000ED3C))));


  while (1);

}


/*******************************************************************************
* Description : This function handles Hard Fault exception.
* Input       : -
* Return      : -
*******************************************************************************/
void HardFault_Handler(void)
{
    // Go to infinite loop when Hard Fault exception occurs
  asm("TST LR, #4");
  asm("ITE EQ");
  asm("MRSEQ R0, MSP");
  asm("MRSNE R0, PSP");
  asm("B hard_fault_handler_c");
    while (1);
}


Доработaть по вкусу.
printf можно выбросить.
Поставить брейкпойнт на месте первого printf.
Сравнить пойманный аддресс с map файлом, найти из какой функции вылетает

Может, memory corruption или stack маленький.
Наиболее частые проблемы, мне кажется, особенно при таких странных LR
sidy
Я снова получил HardFault и использовал функцию, приведенную выше для определения адреса с которого перешли в HardFault. Значения переменных у меня получились следующие:
Нажмите для просмотра прикрепленного файла
А значения регистров в отладчике такие:
Нажмите для просмотра прикрепленного файла
Вопрос почему несовпадают значения r0, r1, r2, r3 и т.д. полученные в функции с тем что я вижу в регистрах? И как теперь мне определить адрес из которого попали в HardFault?
И еще мысль переменные stacked_r0 и т.д. должны быть глобальными, чтобы не портить стэк?

И еще в Reference Manual написано что нужно использовать функции __get_PSP() и __get_MSP(), но когда я их пытаюсь вызвать компилятор выдает следующую ошибку:
[cc] C:\ARTRON_VER1.1\cmsis/core_cmFunc.h:410:61: error: expected '=', ',', ';', 'asm' or '__attribute__' before '__get_PSP'
[cc] C:\ARTRON_VER1.1\cmsis/core_cmFunc.h:410:1: error: unknown type name '__STATIC_INLINE'
Сама функция в core_cmFunc.h описана так:
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void)
{
register uint32_t result;

__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
return(result);
}
Что нужно сделать чтобы данные функции вызывались нормально.

P.S. проверил в файле main.c функция __get_MSP(); вызывается, а вот в файле startup_stm32f4xx.c компилирует с ошибками, непонятно.
demiurg_spb
Цитата(sidy @ Dec 18 2013, 11:32) *
Что нужно сделать чтобы данные функции вызывались нормально.
правильно подключить библиотеку CMSIS.
Например, для stm32f10x это делается подключение заголовочного файла
Код
stm32f10x.h
, который подтягивает за собой всё необходимое, а вы, видимо, напрямую подключаете
Код
core_cmInstr.h
, что идеологически неверно...
sidy
Цитата(demiurg_spb @ Dec 18 2013, 13:44) *
правильно подключить библиотеку CMSIS.
Например, для stm32f10x это делается подключение заголовочного файла

Спасибо, помогло.
ig_z
QUOTE (sidy @ Dec 18 2013, 09:32) *
И как теперь мне определить адрес из которого попали в HardFault?


В местной файлохранилке есть книга из которой выдран пример вашего фаулт обработчика. Там всего несколько страниц очень понятного объяснения. Настоятельно рекомендую прочесть. Здесь на форуме давали ссылку на пример использования фаулт обработчика для поиска места сбоя. В качестве подопытного примера использовалось деление на ноль.
В вашем случае нужно смотреть окрестности 0x0000A74A.
sidy
Еще один вопрос: использую компилятор gcc, смотрю дизассемблер и вижу следующую строку:
08002a56: ; <UNDEFINED> instruction: 0x47c3
Т.е. получается какая-то инструкция не определена? И что это значит?
demiurg_spb
Цитата(sidy @ Dec 24 2013, 16:32) *
В этом месте могут быть данные, а не инструкции.
Также, возможно, что это глюк дизассемблера.
sidy
Поймал HardFault еще раз с помощью функции __get_MSP() взял адрес, 0x200098B0 посмотрел map файл, с 0x200019b0 по 0x200099b0 у меня находится стек длиной 8k слов. Адрес взятый при попадании в HardFault находится в стеке, значит получается у меня проблемы со стеком? Возможно нужно увеличить его размер?
demiurg_spb
Цитата(sidy @ Dec 25 2013, 09:17) *
Странные рассуждения...
Из стека у вас вряд ли выполнялась программа. Т.к. на стеке в нормальной ситуации могут быть лишь локальные данные.
Сдаётся мне, что вы неверно раскрутили эту ситуацию.
sidy
Цитата(demiurg_spb @ Dec 25 2013, 12:33) *

Функция get_MSP вернула мне такой адрес. А данный адрес попадает в диапазон адресов стека.
demiurg_spb
Цитата(sidy @ Dec 25 2013, 13:50) *
Функция get_MSP вернула мне такой адрес. А данный адрес попадает в диапазон адресов стека.
А теперь подумайте. Это хорошо или плохо.
А когда созреете дайте развёрнутый ответ.
sidy
Цитата(demiurg_spb @ Dec 25 2013, 13:56) *
А теперь подумайте. Это хорошо или плохо.
А когда созреете дайте развёрнутый ответ.

В том то и дело, что непонятно хорошо или плохо - я не знаю что с этим делать и нигде не могу найти информацию по этому поводу. Допустим когда использую функцию get_MSP в основной программе то получаю содержимое r2, но никак не адрес из диапазона адресов стека.
P.S. вот тут нашел похожее:
http://electronix.ru/forum/lofiversion/index.php/t72471.html
В той теме в последнем сообщении говорится, что стек пересчитывается, мне не совсем понятно как.
demiurg_spb
Цитата(sidy @ Dec 27 2013, 10:15) *

http://infocenter.arm.com/help/index.jsp?t...403c/index.html
sidy
Спасибо, руководство я уже скачал изучаю.
Вроде бы начало что-то получаться: сейчас записал в обработчике HardFault регистр PC, в нем содержится адрес 0х08001ас0. Но по этому адресу я криминала не вижу:
Нажмите для просмотра прикрепленного файла
Еще я посмотрел регистр SCB->CFSR, в нем установлены биты PRECISERR и BFARVALID, а в регистре BFAR содержится адрес 0x268dfb8, который как следует из руководства должен показывать место откуда произошел BUSFAULT. Но пока непонятно как можно связать 0х08001ас0 и 0x268dfb8.
Dron_Gus
Он будет указывать не на место, где произошло падение, а немного вперед, т.к. конвеер. На сколько именно - надо смотреть в мануале. Скорее всего падает на push'е.
sidy
Тестирую свою программу дальше и заметил, что при HardFault в регистре BFAR содержится почти всегда разные адреса, потом я сопоставил когда это возникло, и вспомнил что у меня DMA обслуживает передачу данных из АЦП в память, и после добавления трех каналов в АЦП и соответственно трех элементов в массив, куда идет пересылка с помощью DMA стал появляться HardFault. Может это быть как-то взаимосвязано, и может кто-нибудь уже сталкивался с таким явлением?
sidy
Поймал еще несколько раз Hard Fault. В регистре PC обычно содержатся разные адреса последний раз при hard fault там был адрес 0х080046EC:
Нажмите для просмотра прикрепленного файла
В регистре SCB->CFSR, всегда устанавливаются биты PRECISERR и BFARVALID.
В регистре BFAR который содержится адрес откуда произошел BUSFAULT тоже разные значений последний раз там было значение 0х4B404288.
Куда мне смотреть дальше?
sidy
Читаю книгу Joseph Yiu "The Definitive Guide to the ARM Cortex-M3" и нашел там в главе про bus fault следующее:
In the Cortex-M3, bus faults can also occur during the following:
Stack PUSH in the beginning of interrupt processing, called a stacking error.

Как видно у меня обработчик прерывания начинается с push:
Нажмите для просмотра прикрепленного файла
Теперь возникает вопрос как избавиться от push в начале прерывания?
_Артём_
Цитата(sidy @ Jan 23 2014, 21:59) *
Читаю книгу Joseph Yiu "The Definitive Guide to the ARM Cortex-M3" и нашел там в главе про bus fault следующее:
In the Cortex-M3, bus faults can also occur during the following: Stack PUSH in the beginning of interrupt processing, called a stacking error.
Книга хорошая конечно, но вы как-то не так этот момент поняли: отказ шины, возникающий во время сохранения регистров в стек (Stack PUSH) называется "stacking error". Очень вольный перевод.
Чем может быть вызвана эта ошибка не знаю - может стека не хватит или ещё что - не важно. Она ведь и возникать-то не должна в нормально написанной программе.

Цитата(sidy @ Jan 23 2014, 21:59) *
Как видно у меня обработчик прерывания начинается с push: Теперь возникает вопрос как избавиться от push в начале прерывания?
Не надо с ветряными мельницами бороться - компилятору не хватает регистров R0 - R2 (или какие там автоматом в стек попадают) для обработчика прерывания, вот он и сохраняет ещё несколько. И на выходе их восстановит.
Сергей Борщ
Цитата(sidy @ Jan 23 2014, 21:59) *
Как видно у меня обработчик прерывания начинается с push:
Полагаю, что тут имеется ввиду аппаратная запись стекового фрейма (R0-R3, R12, PC, LR, PSR).
Цитата
When the processor takes an exception, unless the exception is a tail-chained or a latearriving
exception, the processor pushes information onto the current stack. This operation
is referred as stacking and the structure of eight data words is referred as stack frame


На нее вы повлиять не можете.
sidy
А если я отключу bus fault то программа вернет в каком-то месте некорректное значение? Может быть это поможет в поиске места возникновения bus fault ?
_Артём_
Цитата(sidy @ Jan 24 2014, 16:10) *
А если я отключу bus fault
В смысле запретите ядру делать bus fault-ы? Или запретите обработчик BusFault?

Цитата(sidy @ Jan 24 2014, 16:10) *
А если я отключу bus fault то программа вернет в каком-то месте некорректное значение?
Ничего она не вернёт скорей всего - если BusFault_Handler запрещён, то будет вызван HardFault_Handler (это по-простому - на самом деле там несколько условий - почитайте например пункт мануала Fault handling). Если во время выполнения HardFault_Handler-a возникнет ошибка, то ядро будет заблокировано (Lookup state).

Цитата(sidy @ Jan 24 2014, 16:10) *
Может быть это поможет в поиске места возникновения bus fault ?
Скорей помешает - зачем запрещать специально предназначенный для этой цели обработчик?


sidy
В регистре SCB->CFSR установлены биты PRECISERR и BFARVALID, а в регистре BFAR последний раз был адрес 0x268dfb8. Что можно полезного извлечь из этого адреса? Как я понимаю это адрес памяти? Но программа у меня стартует с адреса 0х08000000.
_Артём_
Цитата(sidy @ Jan 24 2014, 20:16) *
BFAR последний раз был адрес 0x268dfb8.

Странный адрес какой-то...У вас внешнее ОЗУ не подключено? Или где-то в адресе цифру забыли написать?
sidy
Цитата(_Артём_ @ Jan 24 2014, 22:44) *
Странный адрес какой-то...У вас внешнее ОЗУ не подключено? Или где-то в адресе цифру забыли написать?

Внешнего ОЗУ нет. Адрес копировал из окна отладчика.
_Артём_
Цитата(sidy @ Jan 24 2014, 20:59) *
Внешнего ОЗУ нет. Адрес копировал из окна отладчика.

Ну тогда проект бы выложили...Гадать можно долго.
sidy
Выкладываю весь проект (достаточно большой): суть его управление трехфазным инвертором и выпрямителем. Сделан в CooCox CoIDE. Особая просьба посмотреть в файле startup_stm32f4xx.c обработчик Hard Fault может я не правильно вылавливаю Hard Fault.
Нажмите для просмотра прикрепленного файла
Mihey_K
С чего Вы взяли, что попадаете в Hard Fault, у Вас же на все исключения прописан обработчик Default_Handler? На мой взгляд убьете больше времени, разбираясь с запуском обработчика и выдергиванием точки входа в исключение, чем логически подумать, почему раньше работало, добавить перед каждым вызовом функций настройки периферии принтф. Если получаем Hard Fault, значит смотрим систему тактирования и настройки DMA, если Default Handler, значит не влезли в стек, накосячили с указателем и т.д.
Aaron
Ну на самом деле полезно сделать один раз качественный развёрнутый обработчик исключений и потом им постоянно пользоваться, может спусти не одну тысячу нервных клеток!
Для корректного разворачивания причины прерывания (анализ можно прямо в коде проводить и printf-ами выводить сообщения анализа) надо читать доку у STM, где всё-всё-всё расписано: PM0214: STM32F3xxx and STM32F4xxx Cortex-M4 programming manual
sidy
Обработчики для различных Fault'ов я добавил. Поймал сегодня еще один Fault. В регистре SCB->CFSR установлено 0x1000000, т.е. установлен бит UNALIGNED: the processor has made an unaligned memory access. В обработчике faul'та следующее:
Нажмите для просмотра прикрепленного файла
Т.е. если смотреть pc, там содержится 0х08002с24. По этому адресу содержится следующее:
Нажмите для просмотра прикрепленного файла
если я сделал все правильно, то непонятно, что в районе этого адреса может быть невыровнено.
Mihey_K
Для наглядности бы еще кусок исходного кода показали
sidy
Вот кусок исходного кода:
Код
if (CalcUBpA>=1){
      temp=(float)NUBpAPeriod/(float)SIZE; temp=vsqrt(temp);
      BypassInpUa=BypassInpUaK*UacCoeff*temp; CalcUBpA=0;
}
Mihey_K
Странно. Выходит падает на загрузке в регистр FPU. Где-нибудь еще в коде используете функции FPU? И настройки компилятора огласите
sidy
Цитата(Mihey_K @ Feb 1 2014, 15:12) *
Где-нибудь еще в коде используете функции FPU?

FPU используется еще во многих местах.
Вот настройки компилятора:
-mcpu=cortex-m4; -mfpu=fpv4-sp-d16; -mfloat-abi=hard; -mthumb; -Wall; -ffunction-sections; -g; -O1; -DSTM32F415RG; -DSTM32F4XX; -DUSE_STDPERIPH_DRIVER; -D__ASSEMBLY__; -D__FPU_USED; -I.;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.