STM32F2: Makefile, script de l'éditeur de liens et combinaison de fichiers de démarrage sans IDE commercial

16

Je travaille avec un STM32F2 (en particulier, le STM32F217IGH6 sur une carte de développement) depuis environ deux mois. De loin, mon plus gros problème était lié à la "configuration", qui comprend le makefile, le script de l'éditeur de liens et le fichier de démarrage.

En particulier, je n'ai pas pu configurer correctement ma table de vecteurs d'interruption et j'ai appelé des gestionnaires d'interruption. ST fournit des exemples adaptés aux IDE commerciaux. Au lieu de cela, j'utilise la recompilation gratuite Yagarto de la chaîne d'outils GCC (et OpenOCD pour charger l'image via JTAG).

Existe-t-il des exemples de projets pour ma carte (ou un proche parent) qui contiennent le makefile, le script de l'éditeur de liens et la combinaison de fichiers de démarrage appropriés pour les IDE non commerciaux qui sont configurés pour appeler les gestionnaires d'interruption?

Randomblue
la source
2
Vous devriez chercher des exemples de Cortex M3, la carte et le processeur exacts ne sont pas si importants pour les choses que vous demandez. Vous devrez probablement modifier la disposition de la mémoire dans le script de l'éditeur de liens et la méthode pour flasher dans le makefile, mais cela devrait être tout.
starblue
1
Pouvez-vous mettre tout cela dans un dépôt git et le mettre sur github ou quelque chose?
AngryEE
1
C'est exactement la raison pour laquelle j'ai cessé d'utiliser la STM dès que je l'ai essayé. S'ils vont me rendre la vie difficile avec la méchante chaîne d'outils, alors je vais ailleurs. Quand j'ai essayé l'IDE pour PSoC3 et PSoC5, c'était un monde de différence.
Rocketmagnet
Êtes-vous engagé envers Yagarto? C'est tout à fait correct et pose une excellente question, mais je connais la chaîne d'outils CodeSourcery Lite . Une réponse pour une chaîne d'outils différente pourrait probablement être adaptée, mais ne fonctionnerait pas prête à l'emploi.
Kevin Vermeer

Réponses:

20

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.

old_timer
la source
Je lisais la réponse et je suppose que l'auteur de cette réponse serait VOUS. Vos réponses m'ont beaucoup aidé et m'ont motivé à passer aux processeurs ARM plutôt qu'à AVR et PIC Fanboy. Merci
MaNyYaCk
Vous êtes les bienvenus ... payez-le en avant ...
old_timer
2

Vous pouvez jeter un oeil à ce site où il essaie d'expliquer les bases de l'éditeur de liens et low_level_init dans le code.

Veuillez noter que la page se concentre sur la description du problème, donc le vecteur nvic est plutôt minimal.

Ensuite, vous avez des exemples plus complets dans la "bibliothèque de périphériques standard STM32F2xx", il suffit de regarder dans les sections gcc (car Yagarto est basé sur gcc). Et il y a un exemple de code qui vous aidera à configurer correctement le nvic (table de vecteur d'interruption).

Donc, même si ce n'est pas une réponse complète, j'espère que cela sera utile de toute façon.

Johan
la source