STM32F2: Makefile, skrypt linkera i kombinacja plików startowych bez komercyjnego IDE

16

Pracuję z STM32F2 (konkretnie STM32F217IGH6 na płycie programistycznej) od około dwóch miesięcy. Zdecydowanie mój największy problem dotyczył „instalacji”, która obejmuje makefile, skrypt linkera i plik startowy.

W szczególności nie byłem w stanie poprawnie skonfigurować mojej tabeli wektorów przerwań i wywołałem procedury obsługi przerwań. ST dostarcza przykłady dostosowane do komercyjnych IDE. Zamiast tego korzystam z bezpłatnej rekompilacji Yagarto zestawu narzędzi GCC (i OpenOCD, aby załadować obraz za pomocą JTAG).

Czy są jakieś przykładowe projekty dla mojej płyty (lub jej bliskiego kuzyna), które zawierają odpowiedni plik makefile, skrypt linkera i kombinację plików startowych dla niekomercyjnych IDE skonfigurowanych do wywoływania procedur obsługi przerwań?

Randomblue
źródło
2
Powinieneś poszukać przykładów Cortex M3, dokładna płyta i procesor nie są tak ważne dla rzeczy, o które pytasz. Prawdopodobnie musisz zmodyfikować układ pamięci w skrypcie linkera i metodę flashowania w pliku makefile, ale to wszystko.
starblue
1
Czy możesz to wszystko umieścić w repozytorium git i umieścić na github lub coś w tym stylu?
AngryEE
1
Właśnie z tego powodu przestałem używać STM, gdy tylko go wypróbowałem. Jeśli zamierzają utrudnić mi życie paskudnym łańcuchem narzędzi, idę gdzie indziej. Kiedy próbowałem IDE dla PSoC3 i PSoC5, był to świat różnic.
Rocketmagnet
Czy jesteś zaangażowany w Yagarto? To całkiem w porządku i stanowi świetne pytanie, ale znam łańcuch narzędzi CodeSourcery Lite . Odpowiedź na inny zestaw narzędzi mogłaby prawdopodobnie zostać dostosowana, ale nie działałaby od razu po wyjęciu z pudełka.
Kevin Vermeer

Odpowiedzi:

20

http://github.com/dwelch67

w szczególności stm32f4 i stm32vld, ale inne również mogą ci się przydać. mbed i katalog mzero w mbed (cortex-m0).

Podoba mi się proste głupie podejście, minimalne skrypty linkera, minimalny kod startowy itp. Praca jest wykonywana przez kod, a nie przez żaden konkretny łańcuch narzędzi.

Większość form gcc i binutils (zdolnych do obsługi kciuka) będzie działać nieco z tymi przykładami, ponieważ używam kompilatora do kompilacji nie jako zasobu do wywołań biblioteki, nie używam skryptów linkera, itp. Starsze gcc i binutils nie będą wiedzieć o nowsze części thumb2, więc mogą być wymagane pewne zmiany.

Tworzę własne gcc, binutils i llvm / clang, a także używam na przykład codeourcery (teraz grafika mentora, ale nadal możesz uzyskać wersję darmową / lite).

Zwłaszcza, kiedy zaczynasz przygotowywać projekt dla nowego celu, musisz wykonać demontaż. W szczególności, aby upewnić się, że elementy są tam, gdzie chcesz, na przykład tabela wektorów.

Spójrz na przykład na stm32f4d / blinker02. Zaczyna się od wektorów.s tablica wyjątków / wektorów oraz niektóre procedury obsługi 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

W tym przykładzie nie ma żadnych zakłóceń, ale inne potrzebne rzeczy są tutaj.

blinker02.c zawiera główną część kodu C z punktem wejścia C, który nazywam notmain (), aby uniknąć nazywania go main (niektóre kompilatory dodają śmieci do twojego pliku binarnego, gdy masz main ()).

oszczędzę ci cięcia i wklejania. plik makefile opowiada o kompilowaniu i łączeniu. Zauważ, że wiele moich przykładów kompiluje dwa lub więcej plików binarnych z tego samego kodu. kompilator gcc, kompilator llvm, tylko thumb i thumb2, różne optymalizacje itp.

Zacznij od utworzenia plików obiektowych z plików źródłowych.

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, używa skryptu linkera, który nazywam memmap, może to być bardzo bolesne, czasem z dobrego powodu, a czasem nie. Wolę, że mniej znaczy więcej podejścia do jednego rozmiaru dla wszystkich, wszystko oprócz podejścia do zlewu kuchennego.

Zwykle nie używam .data (prawie nigdy) i ten przykład nie wymaga .bss, więc tutaj jest skrypt linkera, wystarczy umieścić program (.text) tam, gdzie powinien być dla tego procesora, tak jak ja jestem Użyj tego.

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

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

Mam region pamięci, aby to zdefiniować, nie ma nic szczególnego w nazwie ram, którą można nazwać foo, bar, bob lub ted, nie ma znaczenia, że ​​po prostu łączy elementy pamięci z sekcjami. Sekcje definiują takie rzeczy jak .text, .data, .bss, .rodata i gdzie idą na mapie pamięci.

kiedy to budujesz, widzisz, że wszystko demontuję (objdump -D) widzisz to

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}

Kluczową rzeczą do zapamiętania jest to, że adres po lewej stronie jest tam, gdzie go chcieliśmy, kod vectors.s jest najpierw w pliku binarnym (ponieważ jest on pierwszy w wierszu poleceń ld, chyba że zrobisz coś w skrypcie linkera, elementy pokażą się w pliku binarnym w kolejności, w jakiej znajdują się w wierszu poleceń ld). Aby poprawnie uruchomić komputer, musisz upewnić się, że stół wektorowy znajduje się we właściwym miejscu. Pierwszy przedmiot to adres mojego stosu, w porządku. Drugi element to adres do _start i powinien być liczbą nieparzystą. użycie .thumb_func przed etykietą powoduje, że tak się dzieje, więc nie musisz robić innych brzydko wyglądających rzeczy.

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

08000056 <hang>:
 8000056:       e7fe          

więc 0x08000051 i 0x08000057 są poprawnymi pozycjami wektorowymi dla _start i hang. rozpocznij wywołanie notmain ()

08000098 <notmain>:
 8000098:       b510            push    {

To wygląda dobrze (nie pokazują nieparzystego adresu w demontażu).

Wszystko dobrze.

Przejdź do przykładowego blinker05, ten obsługuje przerwania. i potrzebuje trochę pamięci RAM, więc zdefiniowano .bss.

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

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

pamiętaj, że ram i rom są dowolnymi nazwami, bob i ted, foo i bar wszystko działają dobrze.

Nie pokażę całych wektorów.s, ponieważ kora-m3 ma pozycje zillionów w tabeli wektorów, jeśli utworzysz pełny (różni się w zależności od rdzenia i może w obrębie tego samego rdzenia, w zależności od opcji wybranych przez dostawcę układu) Odpowiednie porcje znajdują się tutaj po demontażu:

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}

zajmuje trochę prób i błędów, aby umieścić ten moduł obsługi dokładnie we właściwym miejscu, sprawdzić za pomocą chipa, gdzie powinien być, niekoniecznie musi być w tym samym miejscu, co ten, a przy tak wielu przerwaniach i tak możesz szukać innego przerwania. procesory cortex-m, w przeciwieństwie do zwykłych ramion, sprawiają, że nie trzeba POTRZEBOWAĆ kodu trampoliny dla przerwań, zachowują pewną liczbę rejestrów i zarządzają przełączaniem trybów procesora poprzez zawartość rejestru linków. tak długo, jak sprzęt i abi kompilatora są wystarczająco blisko, wszystko działa. W tym przypadku zrobiłem moduł obsługi w C, w przeciwieństwie do innych platform, a przeszłości nie trzeba robić nic specjalnego, kompilator / składnia po prostu tworzą funkcję (ale nie robią głupich rzeczy w funkcji / module obsługi)

//-------------------------------------------------------------------
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
//-------------------------------------------------------------------

Plik makefile dla blinker05 powinien przypominać przykład blinker02, w większości wyciąć i wkleić dla większości z nich. zamień poszczególne pliki źródłowe w obiekty, a następnie połącz. Buduję dla thumb, thumb2 używając gcc i clang. możesz zmienić linię all:, aby uwzględnić elementy gcc tylko wtedy, gdy nie masz / chcesz zaangażować cll (llvm). Używam binutils do łączenia i łączenia wyjścia bangu.

Wszystkie te projekty wykorzystują bezpłatne, gotowe półki, otwarte oprogramowanie, narzędzia. bez IDE, tylko wiersz poleceń. Tak, robię bałagan tylko z Linuksem, a nie z Windowsem, ale te narzędzia są również dostępne dla użytkowników systemu Windows, zmieniaj rzeczy, takie jak rm -f, aby usunąć coś z pliku makefile, takie rzeczy podczas budowania na Windowsie. To lub uruchom Linux na vmware lub virtualbox lub qemu. Nieużywanie IDE oznacza, że ​​wybierasz również edytor tekstów, nie będę się tym zajmować, mam swoje ulubione. Zauważ, że niezwykle denerwującą cechą programu make gnu jest to, że wymaga on rzeczywistych zakładek w pliku makefile, z pasją nienawidzę niewidocznych zakładek. Tak więc jeden edytor tekstu dla plików makefile, który pozostawia tabulacje, a drugi dla kodu źródłowego, który tworzy spacje. Nie wiem o oknach,

Mam nadzieję, że to pomaga, to nie jest dokładny układ / płytka, ale cortex-m4 well m4 nie m3, wystarczająco blisko do tej dyskusji. zobacz katalog mbed lub stm32vld, aby zobaczyć rzeczywistą cortex-m3 (niewystarczające różnice w stosunku do m4 dla plików makefile i kodu rozruchowego itp.), ale nie wykonane przez st. Rdzeń kory-m3 powinien być taki sam u wszystkich sprzedawców, zarówno kora-m3, jak i kora-m4 są ARMv7m i są raczej bliższe niż różne. Kora-m0 to ARMv6m, prawie nie ma wystarczających instrukcji kciuka2, kompilatory nie nadążają z tym, więc po prostu używaj tylko kciuka (udawaj, że budujesz dla ARMv4T (tylko kciuk), jeśli to konieczne). Mój symulator kciuka to tylko kciuk, bez kciuka2, może też być przydatny, myślę, że zmusiłem go do wykonywania przerwań w jakiejś formie lub modzie.

old_timer
źródło
Czytałem odpowiedź i myślę, że autorem tej odpowiedzi będzie TY. Twoje odpowiedzi bardzo mi pomogły i zmotywowały mnie do przejścia na procesory ARM niż bycie fanem AVR i PIC. Dzięki
MaNyYaCk
Nie ma za co ... zapłać dalej ...
old_timer
2

Możesz zajrzeć na tę stronę, gdzie próbuje wyjaśnić podstawy linkera i low_level_init w kodzie.

Należy pamiętać, że strona koncentruje się na opisaniu problemu, więc wektor nvic jest w pewnym sensie minimalny.

Następnie masz pełniejsze przykłady w „bibliotece standardowych urządzeń peryferyjnych STM32F2xx”, po prostu zajrzyj do sekcji gcc (ponieważ Yagarto jest oparty na gcc). I jest tam przykładowy kod, który pomoże ci z prawidłową konfiguracją nvic (tablica wektorów przerwań).

Więc nawet jeśli nie jest to pełna odpowiedź, mam nadzieję, że i tak jest pomocna.

Johan
źródło