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.