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, він може бути корисним і для вас, я думаю, що я змусив його виконувати переривання в якійсь формі або способі.