http://github.com/dwelch67
stm32f4 et stm32vld en particulier, mais les autres peuvent également vous être utiles. mbed et le répertoire mzero sous mbed (cortex-m0).
J'aime l'approche simple et stupide, les scripts de l'éditeur de liens minimaux, le code de démarrage minimal, etc. Le travail est effectué par le code et non par une chaîne d'outils particulière.
La plupart des formes de gcc et binutils (capables de fonctionner avec le pouce) fonctionneront quelque peu avec ces exemples car j'utilise le compilateur pour compiler non pas comme une ressource pour les appels de bibliothèque, je n'utilise pas les scripts de l'éditeur de liens, etc. Les anciens gcc et binutils ne seront pas au courant les parties plus récentes de thumb2, certaines modifications peuvent donc être nécessaires.
Je construis mes propres gcc, binutils et llvm / clang ainsi que l'utilisation de codesourcery par exemple (maintenant le mentor graphique mais vous pouvez toujours obtenir la version gratuite / lite).
Lorsque vous commencez à monter un projet pour une nouvelle cible, vous devez faire un démontage. En particulier pour vous assurer que les éléments sont là où vous les voulez, la table vectorielle par exemple.
Regardez stm32f4d / blinker02 par exemple. Il commence par vectors.s la table exception / vector plus quelques routines de support 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
Aucune interruption sur cet exemple, mais les autres choses dont vous avez besoin sont ici.
blinker02.c contient le corps principal du code C avec le point d'entrée C que j'appelle notmain () pour éviter de l'appeler main (certains compilateurs ajoutent du courrier indésirable à votre binaire lorsque vous avez un main ()).
vous épargnera un couper-coller. le makefile raconte l'histoire de la compilation et de la liaison. Notez qu'un certain nombre de mes exemples compilent deux binaires ou plus à partir du même code. compilateur gcc, compilateur clang de llvm, pouce seulement et pouce2, différentes optimisations, etc.
Commencez par créer des fichiers objets à partir des fichiers source.
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
l'éditeur de liens, ld, utilise un script de l'éditeur de liens que j'appelle memmap, ceux-ci peuvent être extrêmement douloureux, parfois pour une bonne raison, parfois non. Je préfère le moins, c'est plus l'approche de la taille unique, tout sauf l'approche de l'évier de cuisine.
Je n'utilise pas .data généralement (enfin presque jamais) et cet exemple n'a pas besoin de .bss alors voici le script de l'éditeur de liens, juste assez pour placer le programme (.text) où il doit être pour ce processeur comme je suis En l'utilisant.
MEMORY
{
ram : ORIGIN = 0x08000000, LENGTH = 0x1000
}
SECTIONS
{
.text : { *(.text*) } > ram
}
J'ai une région de mémoire pour définir cela, il n'y a rien de spécial à propos du nom ram que vous pouvez appeler foo ou bar ou bob ou ted, cela n'a pas d'importance, il relie simplement les éléments de mémoire aux sections. Les sections définissent des éléments tels que .text, .data, .bss, .rodata et leur emplacement dans la carte mémoire.
quand vous construisez ceci, vous voyez que je démonte tout (objdump -D) vous voyez ceci
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}
L'élément clé à noter est l'adresse à gauche est l'endroit où nous le voulions, le code de vectors.s est le premier dans le binaire dans le binaire dans l'ordre où ils se trouvent sur la ligne de commande ld). Pour démarrer correctement, vous devez vous assurer que votre table vectorielle est au bon endroit. Le premier élément est mon adresse de pile, c'est très bien. Le deuxième élément est l'adresse de _start et il doit s'agir d'un nombre impair. l'utilisation de .thumb_func avant une étiquette provoque cela, vous n'avez donc pas à faire d'autres choses laides.
08000050 <_start>:
8000050: f000 f822 bl 8000098 <notmain>
8000054: e7ff b.n 8000056 <hang>
08000056 <hang>:
8000056: e7fe
ainsi 0x08000051 et 0x08000057 sont les entrées vectorielles appropriées pour _start et hang. démarrer les appels notmain ()
08000098 <notmain>:
8000098: b510 push {
Cela semble bon (ils ne montrent pas l'adresse numérotée impaire dans le démontage).
Tout est bien.
Passez à l'exemple blinker05, celui-ci prend en charge les interruptions. et a besoin de RAM, donc .bss est défini.
MEMORY
{
rom : ORIGIN = 0x08000000, LENGTH = 0x100000
ram : ORIGIN = 0x20000000, LENGTH = 0x1C000
}
SECTIONS
{
.text : { *(.text*) } > rom
.bss : { *(.bss*) } > ram
}
rappelez-vous que ram et rom sont des noms arbitraires, bob et ted, foo et bar fonctionnent tous très bien.
Ne va pas montrer l'ensemble des vecteurs.s parce que le cortex-m3 a un zillion d'entrées dans la table vectorielle si vous en faites une complète (varie d'un cœur à l'autre et peut-être dans le même cœur en fonction des options choisies par le fournisseur de puces) Les parties pertinentes sont ici après le démontage:
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}
prend quelques essais et erreurs pour placer ce gestionnaire exactement au bon endroit, vérifiez avec votre puce où il doit être, il n'est pas nécessairement au même endroit que celui-ci, et avec autant d'interruptions, vous cherchez peut-être une interruption différente de toute façon. les processeurs cortex-m, contrairement aux bras normaux, font en sorte que vous n'avez PAS BESOIN de code de trampoline pour les interruptions, ils préservent un certain nombre de registres et gèrent la commutation des modes de processeur via le contenu du registre de liens. tant que le matériel et l'abi du compilateur sont suffisamment proches, tout fonctionne. Dans ce cas, j'ai fait le gestionnaire en C, contrairement aux autres plates-formes et au passé, vous n'avez pas besoin de faire quoi que ce soit de spécial avec le compilateur / la syntaxe, faites simplement une fonction (mais ne faites pas de choses stupides dans la fonction / le gestionnaire)
//-------------------------------------------------------------------
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
//-------------------------------------------------------------------
Le makefile pour blinker05 devrait ressembler à l'exemple de blinker02, principalement couper et coller pour la plupart d'entre eux. transformer les fichiers source individuels en objets puis lier. Je construis pour thumb, thumb2 en utilisant gcc et clang. vous pouvez changer la ligne all: à la fois pour n'inclure les éléments gcc que si vous n'avez pas / voulez que clang (llvm) soit impliqué. J'utilise des binutils pour assembler et relier la sortie clang btw.
Tous ces projets utilisent des outils gratuits, prêts à l'emploi et open source. pas d'IDE, ligne de commande uniquement. Oui, je ne plaisante qu'avec Linux et non avec Windows, mais ces outils sont également disponibles pour les utilisateurs de Windows, changent des choses comme rm -f quelque chose en del quelque chose dans le makefile, des choses comme ça lors de la construction sur Windows. Cela ou exécutez linux sur vmware ou virtualbox ou qemu. Ne pas utiliser un IDE signifie que vous choisissez également votre éditeur de texte, je ne m'y attarderai pas, j'ai mes favoris. Notez qu'une caractéristique extrêmement ennuyeuse du programme make gnu est qu'il nécessite de réels onglets dans le makefile, je déteste les onglets invisibles avec passion. Donc, un éditeur de texte pour les makefiles qui laisse des onglets, l'autre pour le code source qui crée des espaces. Je ne connais pas les fenêtres,
J'espère que cela aide, ce n'est pas la puce / carte exacte mais un cortex-m4 bien m4 pas m3, assez proche pour cette discussion. voir le répertoire mbed ou stm32vld pour un cortex-m3 réel (pas assez de différences par rapport au m4 pour les makefiles et le code de démarrage, etc.), mais pas fait par st. Les noyaux du cortex-m3 devraient être les mêmes d'un fournisseur à l'autre, le cortex-m3 et le cortex-m4 sont tous deux ARMv7m et sont plus proches que différents. Le cortex-m0 est un ARMv6m, a à peine assez d'instructions pour le pouce2, les compilateurs ne l'ont pas rattrapé alors utilisez simplement le pouce (faites comme si vous construisiez pour un ARMv4T (pouce seulement) si besoin est). Mon simulateur de pouce est uniquement le pouce, pas le pouce2, il pourrait aussi vous être utile, je pense que je l'ai fait effectuer des interruptions d'une manière ou d'une autre.