STM32F2: Makefile, сценарій посилання та комбінація файлів запуску без комерційного IDE


16

Я працюю з STM32F2 (конкретно, STM32F217IGH6 на дошці розробок) близько двох місяців. На сьогодні моя найбільша проблема була пов'язана з "налаштуванням", яке включає makefile, скрипт linker та файл запуску.

Зокрема, я не зміг належним чином налаштувати свою векторну таблицю переривань і викликав обробники переривань. ST надає приклади, пристосовані до комерційних IDE. Натомість я використовую безкоштовну перекладку Yagarto з ланцюжка інструментів GCC (та OpenOCD для завантаження зображення через JTAG).

Чи є приклади проектів для моєї плати (або її близького двоюрідного брата), які містять відповідний файл makefile, скрипт посилання та комбінацію файлів запуску для некомерційних IDE, створених для виклику обробників переривань?


2
Ви повинні шукати приклади Cortex M3, точна плата та процесор не так важливі для запитань. Можливо, вам потрібно змінити макет пам’яті в скрипті посилання та метод спалаху в makefile, але це повинно бути все.
starblue

1
Чи можете ви помістити все це в git repo і покласти його на github чи щось таке?
AngryEE

1
Це саме та причина, що я перестав використовувати STM, як тільки спробував її. Якщо вони зроблять важке моє життя з бридким інструментальним ланцюжком, то я йду кудись ще. Коли я спробував IDE для PSoC3 та PSoC5, це був світ різниці.
Rocketmagnet

Ви віддані Ягарто? Це абсолютно добре і викликає велике запитання, але я знайомий із інструментальною ланцюжком CodeSourcery Lite . Відповідь на інший ланцюжок інструментів, ймовірно, може бути адаптований, але він не вийшов із-за меж.
Кевін Вермер

Відповіді:


20

http://github.com/dwelch67

stm32f4 і stm32vld зокрема, але інші можуть бути корисні і вам. mbed та каталог mzero під mbed (cortex-m0).

Мені подобається простий дурний підхід, мінімальні сценарії посилання, мінімальний стартовий код тощо. Робота виконується кодом, а не будь-яким певним інструментальним ланцюгом.

Більшість форм gcc та binutils (здатних на великий палець) дещо працюватимуть із цими прикладами, оскільки я використовую компілятор для компіляції не як ресурс для бібліотечних викликів, я не використовую сценарії біркового зв’язку тощо. Старіші gcc та binutils не знають про нові частини thumb2, тому можуть знадобитися деякі зміни.

Я будую свої власні gcc, binutils та llvm / clang, а також використовую, наприклад, кодовий ресурс (тепер наставник графіки, але ви все одно можете отримати безкоштовну / Lite версію).

Esp, коли починаєте складати проект для нової цілі, вам потрібно зробити кілька розбирань. Зокрема, щоб переконатися, що елементи знаходяться там, де ви їх хочете, наприклад, векторна таблиця.

Наприклад, подивіться на stm32f4d / blinker02. Він починається з vectors.s виняток / векторна таблиця плюс деякі процедури підтримки ASM:

/* vectors.s */
.cpu cortex-m3
.thumb

.word   0x20002000  /* stack top address */
.word   _start      /* 1 Reset */
.word   hang        /* 2 NMI */
.word   hang        /* 3 HardFault */
.word   hang        /* 4 MemManage */
.word   hang        /* 5 BusFault */
.word   hang        /* 6 UsageFault */
.word   hang        /* 7 RESERVED */
.word   hang        /* 8 RESERVED */
.word   hang        /* 9 RESERVED*/
.word   hang        /* 10 RESERVED */
.word   hang        /* 11 SVCall */
.word   hang        /* 12 Debug Monitor */
.word   hang        /* 13 RESERVED */
.word   hang        /* 14 PendSV */
.word   hang        /* 15 SysTick */
.word   hang        /* 16 External Interrupt(0) */
.word   hang        /* 17 External Interrupt(1) */
.word   hang        /* 18 External Interrupt(2) */
.word   hang        /* 19 ...   */

.thumb_func
.global _start
_start:
    /*ldr r0,stacktop */
    /*mov sp,r0*/
    bl notmain
    b hang

.thumb_func
hang:   b .

/*.align
stacktop: .word 0x20001000*/

;@-----------------------
.thumb_func
.globl PUT16
PUT16:
    strh r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl PUT32
PUT32:
    str r1,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET32
GET32:
    ldr r0,[r0]
    bx lr
;@-----------------------
.thumb_func
.globl GET16
GET16:
    ldrh r0,[r0]
    bx lr

.end

На цьому прикладі жодних перерв немає, але тут потрібні інші речі.

blinker02.c містить основний корпус коду C із точкою входу C, яку я називаю notmain (), щоб уникнути його виклику основним (деякі компілятори додають у ваш двійковий файл непотрібний файл, коли у вас є main ()).

позбавить вас вирізу та пасти. makefile розповідає історію про складання та зв’язування. Зауважте, що ряд моїх прикладів складають два або більше двійкових файлів з одного і того ж коду. gcc компілятор, компілятор кланг llvm, лише великий палець і thumb2, різні оптимізації тощо.

Почніть із створення об’єктних файлів із вихідних файлів.

vectors.o : vectors.s
    $(ARMGNU)-as vectors.s -o vectors.o

blinker02.gcc.thumb.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -c blinker02.c -o blinker02.gcc.thumb.o

blinker02.gcc.thumb2.o : blinker02.c
    $(ARMGNU)-gcc $(COPS) -mthumb -mcpu=cortex-m3 -march=armv7-m -c blinker02.c -o blinker02.gcc.thumb2.o

blinker02.gcc.thumb.bin : memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb.elf -T memmap vectors.o blinker02.gcc.thumb.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb.elf > blinker02.gcc.thumb.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb.elf blinker02.gcc.thumb.bin -O binary

blinker02.gcc.thumb2.bin : memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-ld -o blinker02.gcc.thumb2.elf -T memmap vectors.o blinker02.gcc.thumb2.o
    $(ARMGNU)-objdump -D blinker02.gcc.thumb2.elf > blinker02.gcc.thumb2.list
    $(ARMGNU)-objcopy blinker02.gcc.thumb2.elf blinker02.gcc.thumb2.bin -O binary

Linker, ld, використовує скрипт linker, який я називаю memmap, це може бути надзвичайно болісно, ​​іноді з поважної причини, іноді ні. Я вважаю за краще, менший - більше підхід до одного розміру, який підходить всім, окрім підходу до кухонної мийки.

Я зазвичай не використовую. використовуючи його.

MEMORY
{
    ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}

SECTIONS
{
    .text : { *(.text*) } > ram
}

У мене є область пам'яті, щоб визначити це, немає нічого особливого в імені ram, який ви можете назвати його foo або bar або bob або ted це неважливо, він просто пов'язує елементи пам'яті з розділами. Розділи визначають такі речі, як .text, .data, .bss, .rodata та те, куди вони йдуть у карту пам'яті.

коли ви будуєте це, ви бачите, що я розбираю все (objdump -D), ви бачите це

Disassembly of section .text:

08000000 <_start-0x50>:
 8000000:       20002000        andcs   r2, r0, r0
 8000004:       08000051        stmdaeq r0, {r0, r4, r6}
 8000008:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 800000c:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}
 8000010:       08000057        stmdaeq r0, {r0, r1, r2, r4, r6}

Ключове, що слід зазначити, це адреса зліва, де ми цього хотіли. Код vectors.s спочатку знаходиться у двійковому (Тому що він перший у командному рядку ld, якщо ви не зробите щось у скрипті-лінкері, елементи відображатимуться в бінарному порядку в порядку, в якому вони знаходяться в командному рядку ld). Для належного завантаження потрібно переконатися, що векторна таблиця знаходиться в потрібному місці. Перший пункт - моя адреса стека, це добре. Другий пункт - це адреса до _start, і це має бути непарне число. використання .thumb_func перед ярликом спричиняє це, тому вам не доведеться робити інші негарні речі.

08000050 <_start>:
 8000050:       f000 f822       bl      8000098 <notmain>
 8000054:       e7ff            b.n     8000056 <hang>

08000056 <hang>:
 8000056:       e7fe          

тож 0x08000051 та 0x08000057 є належними векторними записами для _start та Hang. почати дзвінки notmain ()

08000098 <notmain>:
 8000098:       b510            push    {

Це виглядає добре (Вони не демонструють непарну нумеровану адресу при розбиранні).

Все добре.

Перейдіть до прикладу blinker05, цей підтримує переривання. і потребує деякого барана, тому .bss визначено.

MEMORY
{
    rom : ORIGIN = 0x08000000, LENGTH = 0x100000
    ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}

SECTIONS
{
    .text : { *(.text*) } > rom
    .bss  : { *(.bss*) } > ram
}

пам’ятайте, що ram і rom - це довільні назви, bob і ted, foo та bar - це все добре.

Не збиратись показувати цілі вектори.s тому, що в cortex-m3 є векторний мільйон записів у векторній таблиці, якщо ви складете повну (варіюється від ядра до ядра і, можливо, в межах одного ядра, залежно від параметрів, обраних постачальником мікросхеми) Релевантні частини знаходяться тут після розбирання:

08000000 <_start-0x148>:
 8000000:       20020000        andcs   r0, r2, r0
 8000004:       08000149        stmdaeq r0, {r0, r3, r6, r8}
 8000008:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
...
8000104:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}
 8000108:       08000179        stmdaeq r0, {r0, r3, r4, r5, r6, r8}
 800010c:       0800014f        stmdaeq r0, {r0, r1, r2, r3, r6, r8}

потрібна певна спроба та помилка, щоб розмістити цей обробник точно в потрібному місці, перевірити своїм чіпом, де він повинен бути, це не обов’язково в тому ж самому місці, що і цей, і з такою кількістю переривань ви можете шукати інше переривання в будь-якому випадку. процесори cortex-m, на відміну від звичайних озброєнь, роблять це так, що вам не потрібен код батутного переривання для переривань, вони зберігають певну кількість регістрів і керують перемиканням режимів процесора через вміст реєстру посилань. до тих пір, поки апаратне забезпечення та абі для компілятора досить близько, все працює. У цьому випадку я зробив обробник на C, на відміну від інших платформ і минулого, вам не потрібно робити нічого особливого з компілятором / синтаксисом, просто зробити функцію (але не робити дурних речей у функції / обробника)

//-------------------------------------------------------------------
volatile unsigned int intcounter;
//-------------------------------------------------------------------
// CAREFUL, THIS IS AN INTERRUPT HANDLER
void tim5_handler ( void )
{
    intcounter++;
    PUT32(TIM5BASE+0x10,0x00000000);
}
// CAREFUL, THIS IS AN INTERRUPT HANDLER
//-------------------------------------------------------------------

Makefile для blinker05 повинен нагадувати приклад blinker02, здебільшого вирізати та вставити більшість із них. перетворіть окремі вихідні файли в об'єкти, потім посилання. Я будую для thumb, thumb2 за допомогою gcc та clang. ви можете змінити рядок all: під час включення елементів gcc лише у тому випадку, якщо у вас немає / хочете clang (llvm). Я використовую binutils для збирання та зв’язування вихідного сигналу btw.

Усі ці проекти використовують безкоштовні, відкриті джерела, інструменти. немає IDE, лише командний рядок Так, я плутаюся лише з Linux, а не з Windows, але ці інструменти доступні і для користувачів Windows, змінюють такі речі, як rm - якщо щось деле щось у makefile, такі речі під час створення Windows. Це або запустіть Linux на vmware або virtualbox або qemu. Якщо ви не використовуєте IDE, ви також підбираєте текстовий редактор, я не вникаю в це, у мене є мої улюблені. Зауважте, що надзвичайно дратівлива особливість програми gnu make полягає в тому, що їй потрібні фактичні вкладки в makefile, я ненавиджу невидимі вкладки з пристрастю. Отже, один текстовий редактор для файлів, що залишає вкладки, інший для вихідного коду, який робить пробіли. Я не знаю про вікна,

Я сподіваюся, що це допомагає, це не точна мікросхема / плата, а cortex-m4 і m4 не м3, достатньо близький для цього обговорення. дивіться mbed або stm32vld dir для фактичної кори-м3 (недостатньо відмінностей від m4 для makefiles та завантажувального коду тощо), але не зроблено st. Ядро кори-м3 має бути однаковим у постачальників, кора-м3 та кора-м4 - обидва ARMv7m і ближчі, ніж різні. Cortex-m0 - це ARMv6m, навряд чи має вказівки thumb2, достатньо для того, щоб потурбуватися, компілятори не догнали його, тому просто використовуйте лише великий палець (зробіть вигляд, що ви будуєте для ARMv4T (лише великий палець), якщо це потрібно). Мій симулятор thumbulator - це лише великий палець, no thumb2, він може бути корисним і для вас, я думаю, що я змусив його виконувати переривання в якійсь формі або способі.


Я читав відповідь і гадаю, що автором цієї відповіді буде ВАС. Ваші відповіді мені дуже допомогли та мотивували мене перейти до процесорів ARM, ніж бути AVR та PIC Fanboy. Дякую
MaNyYaCk

Запрошуємо вас ... сплатіть вперед ...
old_timer

2

Ви можете ознайомитись із цим сайтом, де він намагається пояснити основи лінкера та low_level_init у коді.

Зверніть увагу, що сторінка орієнтована на опис проблеми, тому вектор nvic є начебто мінімальним.

Тоді у вас є більш повні приклади в "стандартній бібліотеці периферійних пристроїв STM32F2xx", просто подивіться в розділи gcc (оскільки Yagarto заснований на gcc). І там є приклад коду, який допоможе вам правильно встановити nvic (таблицю переривань вектор).

Тож навіть якщо це не є повною відповіддю, я сподіваюся, що все одно це корисно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.