Table des matières:

Partie 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo : 16 étapes
Partie 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo : 16 étapes

Vidéo: Partie 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo : 16 étapes

Vidéo: Partie 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo : 16 étapes
Vidéo: Part 1 ARM Assembly TI RSLK Robotics Learning Curriculum Lab 7 STM32 Nucleo 2024, Juillet
Anonim
Image
Image

L'objectif de ce Instructable est le micro-contrôleur STM32 Nucleo. La motivation pour cela de pouvoir créer un projet d'assemblage à partir des os nus. Cela nous aidera à approfondir et à comprendre le projet MSP432 Launchpad (le TI-RSLK) qui a déjà fait l'objet de plusieurs Instructables.

Il n'y a pas beaucoup d'aide en ligne pour créer un projet d'assemblage uniquement pour le MSP432, à l'aide de Code Composer Studio. Jusqu'à présent, nous n'avons fait que copier/coller à partir d'un projet d'assemblage préexistant. Cette approche nous a bien servi.

Cependant, maintenant, pour Lab 7, nous avons rencontré un petit problème. Ou au moins un hoquet temporaire. Le Lab 7 introduit les machines à états finis, et la première chose que nous rencontrons est le besoin de créer et d'utiliser un tableau de valeurs. Étant donné que le cours TI utilise principalement la programmation C, ce n'est pas un problème. Mais ces Instructables se sont concentrés sur l'assemblage, pas sur C.

De plus, étant donné que le tableau contient des valeurs en lecture seule, il serait bon de le mettre dans la mémoire flash, pas dans la RAM.

Il semble y avoir beaucoup plus d'aide en ligne pour les projets d'assemblage utilisant le MCU STM32, nous commençons donc par cet Instructable, dans le but d'utiliser ce qui est appris, pour ensuite appliquer au MSP432 et au Code Composer Studio.

Sur la route de cet objectif, nous aurons également acquis de l'expérience avec un autre micro-contrôleur populaire.

Étape 1: Test initial de l'appareil

Test initial de l'appareil
Test initial de l'appareil
Test initial de l'appareil
Test initial de l'appareil
Test initial de l'appareil
Test initial de l'appareil

Encore une fois, pourquoi choisir le STM32 Nucleo en particulier ?

Franchement? Parce que je cherchais de bons articles sur des projets d'assemblage bare-metal pour les contrôleurs ARM, et je suis tombé sur cette série. Et aussi parce que le STM32 semble être un MCU populaire.

J'ai fait quelques recherches (il y a beaucoup de versions à choisir - voir l'image ci-dessus), mais à la fin, c'est devenu ce que je peux réellement obtenir, puisque j'allais utiliser Amazon (aux États-Unis).

Il est livré dans un emballage simple mais professionnel, avec quelques instructions de démarrage. C'était un peu drôle de voir que la démo gravée dans le contrôleur était presque exactement ce que nous avons fait dans les précédents Instructables - une LED clignote et change de vitesse en fonction de la pression d'un bouton.

Il semble que cette carte de développement soit très similaire à la MSP432 dans la mesure où il y a 2 LED et un bouton-poussoir utilisateur. Le MSP432 dispose de 2 boutons utilisateur.

Comme vous pouvez le voir sur les photos, j'ai été un peu surpris que la carte dispose d'un mini et non d'un micro USB. J'ai dû courir pour acheter un cordon.

Un autre bon test est que lorsque vous le connectez à votre ordinateur (j'utilise une machine Linux), il apparaît dans mon gestionnaire de fichiers, en tant que système de fichiers, appelé "NODE_F303RE". Ouverture qui révèle deux fichiers, un HTML et un texte.

C'est tout, mais au moins, cela dit aussi que la connectivité semble assez facile.

Nous sommes maintenant prêts à commencer.

Je vais essayer de ne répéter aucune des bonnes informations de la série d'articles IVONOMICON Bare Metal, mais plutôt de les augmenter.

Étape 2: Les essentiels

La première chose dont nous avons besoin est un compilateur.

Et puis, nous avons besoin d'un débogueur:

devchu@chubox:~$ sudo apt-get install gdb-arm-none-eabiReading packages lists… Terminé Construction de l'arbre de dépendance Lecture des informations d'état… Terminé Les NOUVEAUX packages suivants seront installés: gdb-arm-none-eabi 0 mis à jour, 1 nouvellement installé, 0 à supprimer et 8 non mis à jour. Besoin d'obtenir 2 722 Ko d'archives. Après cette opération, 7 738 Ko d'espace disque supplémentaire seront utilisés. Obtenez:1 https://us.archive.ubuntu.com/ubuntu xenial/universe amd64 gdb-arm-none-eabi amd64 7.10-1ubuntu3+9 [2, 722 Ko] Récupéré 2 722 Ko en 1s (1 988 kB/s) Sélection du package gdb-arm-none-eabi précédemment non sélectionné. (Lecture de la base de données … 262428 fichiers et répertoires actuellement installés.) Préparation du décompression …/gdb-arm-none-eabi_7.10-1ubuntu3+9_amd64.deb … Déballage de gdb-arm-none-eabi (7.10-1ubuntu3+9) … Traitement déclencheurs pour man-db (2.7.5-1) … Configuration de gdb-arm-none-eabi (7.10-1ubuntu3+9) …

Étape 3: L'essentiel - Windows

L'étape ci-dessus suppose que nous utilisons Linux. Et si nous utilisions Windows ?

Vous pouvez aller sur le site du développeur arm, et plusieurs options de téléchargement sont disponibles. J'utilise une machine Windows 8.

Lors de l'installation, j'ai choisi de l'installer sur le lecteur racine "C:\" au lieu de Program Files simplement parce que j'utilise également cygwin, et il était plus facile de créer un lien de mon bac local vers un dossier racine C: que tous les désordre dans le chemin vers Program Files (avec des espaces, etc.).

Ainsi, mon environnement et mon chemin cygwin, etc., ressemblent à ceci:

C:\cygwin64\home\bin\arm-none-eabi-gcc, où arm-none-eabi-gcc est un lien vers C:\GNUToolsArmEmbedded\7.2018.q2.update\bin\arm-none-eabi- gcc.

J'ai ensuite créé un dossier "dev" sous cygwin home, et c'est là que j'ai placé le fichier core. S et exécuté la commande du compilateur. (voir plus loin pour les trucs du compilateur).

J'ai fait exactement la même chose pour gdb (arm-none-eabi-gdb).

Étape 4: Quels sont les éléments essentiels

Alors qu'est-ce que "gcc-arm-none-eabi" ?

Le compilateur gnu (GCC) compilera les langages de programmation (comme le C) en code natif pour la machine sur laquelle il s'exécute. Par exemple, si vous deviez compiler du code C en utilisant GCC sur votre machine Windows, il serait conçu pour s'exécuter sur la machine Windows. L'exécutable généré ne s'exécutera pas (généralement) sur le microcontrôleur ARM.

Ainsi, afin de construire des programmes à télécharger et à graver dans le micro-contrôleur ARM (dans notre cas présent, ce serait le STM32 Nucelo), nous devons donner à GCC autre chose: la possibilité de "cross-compiler". C'est-à-dire la possibilité de générer un exécutable, non pour son système natif (et son processeur), mais pour le système cible (le microcontrôleur ARM). C'est là que "gcc-arm-none-eabi" entre en jeu.

Alors qu'est-ce que "gdb-arm-none-eabi" ?

Une fois que nous avons téléchargé et gravé (flashé) l'exécutable nouvellement généré dans le micro-contrôleur, nous voudrons probablement le déboguer - pas à pas ligne par ligne du code. GDB est le débogueur gnu, et lui aussi a besoin d'un moyen de faire son travail, mais en ciblant un système différent.

Ainsi, gdb-arm-none-eabi est à GDB, ce que gcc-arm-none-eabi est à GCC.

Une autre installation de paquet suggérée était « libnewlib-arm-none-eabi ». C'est quoi celui-là ?

Newlib est une bibliothèque C et une bibliothèque mathématique destinée à être utilisée sur des systèmes embarqués. C'est un conglomérat de plusieurs parties de bibliothèque, toutes sous licences de logiciels libres qui les rendent facilement utilisables sur des produits embarqués.

Et enfin, le paquet "libstdc++-arm-none-eabi". Celui-là est assez évident; c'est la bibliothèque C++ pour le compilateur croisé; pour les microcontrôleurs ARM embarqués.

Étape 5: Le fichier de liaison

Le fichier de liaison
Le fichier de liaison
Le fichier de liaison
Le fichier de liaison

Créons un script d'éditeur de liens.

Une partie ou un bloc clé de ce fichier serait la commande MEMORY.

--- de sourceware.org:

La configuration par défaut de l'éditeur de liens permet l'allocation de toute la mémoire disponible. Vous pouvez remplacer cela en utilisant la commande MEMORY. La commande MEMORY décrit l'emplacement et la taille des blocs de mémoire dans la cible. Vous pouvez l'utiliser pour décrire quelles régions de mémoire peuvent être utilisées par l'éditeur de liens, et quelles régions de mémoire il doit éviter. Vous pouvez ensuite affecter des sections à des régions de mémoire particulières. L'éditeur de liens définira des adresses de section en fonction des régions de mémoire et avertira des régions qui deviennent trop pleines. L'éditeur de liens ne mélangera pas les sections pour s'adapter aux régions disponibles. Un script d'éditeur de liens peut contenir de nombreuses utilisations de la commande MEMORY, cependant, tous les blocs de mémoire définis sont traités comme s'ils étaient spécifiés dans une seule commande MEMORY. La syntaxe de MEMORY est:

MÉMOIRE

{ nom [(attr)]: ORIGINE = origine, LONGUEUR = longueur … }

L'exemple dans l'article:

/* Définit la fin de la RAM et la limite de la mémoire de la pile *//* (4 Ko SRAM sur la ligne STM32F031x6, 4096 = 0x1000) */ /* (RAM commence à l'adresse 0x20000000) _estack = 0x20001000;

MÉMOIRE

{ FLASH (rx): ORIGINE = 0x08000000, LONGUEUR = 32K RAM (rxw): ORIGINE = 0x20000000, LONGUEUR = 4K }

Nous devons donc déterminer la quantité de FLASH (pour notre programme et nos constantes, etc.) et la quantité de RAM (à utiliser par le programme; tas et pile, etc.) pour notre carte particulière. Cela devient un peu intéressant.

La jolie petite carte fournie avec le Nucleo indique qu'il a une mémoire flash de 512 Ko et SRAM est de 80 Ko. Cependant, en le connectant à l'USB, il est monté en tant que système de fichiers avec deux fichiers, et le gestionnaire de fichiers et GParted indiquent qu'il dispose de plus de 540 Ko d'espace. (RAM?).

MAIS, en essayant de supprimer les deux fichiers à l'aide du gestionnaire de fichiers, en déconnectant puis en reconnectant l'appareil, les deux fichiers sont toujours affichés. (et le gestionnaire de fichiers a reconnu quelque chose car il y a une petite icône de "cadenas" sur chaque fichier.

Alors allons-y avec les chiffres sur la carte. Alors maintenant, nous prenons l'exemple ci-dessus et le convertissons en notre carte spécifique.

Vous pouvez utiliser quelque chose comme ce convertisseur de mémoire en ligne, pour passer du Ko général à un nombre spécifique d'octets.

Ensuite, vous pouvez utiliser un convertisseur décimal en hexadécimal en ligne.

/* Définit la fin de la RAM et la limite de la mémoire de la pile */

/* (4 Ko SRAM sur la ligne STM32F031x6, 4096 = 0x1000) *//* l'exemple*/

/* étape 1: (80KB SRAM sur le STM32F303RE, 81920 = 0x14000) *//* notre carte */

/* étape 2, ajoutez la taille hexadécimale à l'adresse de début hexadécimale (ci-dessous). */

/* (la RAM commence à l'adresse 0x20000000) */

_estack = 0x20001000; /* l'exemple */

_estack = 0x20014000; /* notre conseil */

MÉMOIRE {

FLASH (rx): ORIGINE = 0x08000000, LONGUEUR = 512K

RAM (rxw): ORIGINE = 0x20000000, LONGUEUR = 80K

}

Appelons le fichier ci-dessus "linker.script.ld".

Étape 6: La table vectorielle

Le tableau des vecteurs
Le tableau des vecteurs

Nous allons maintenant créer un petit fichier d'assemblage (avec des directives) pour effectuer une gestion des interruptions très basique. Nous allons suivre l'exemple de l'article et créer un fichier nommé "core. S".

Encore une fois, voici le contenu du fichier d'exemple, mais j'ai apporté une modification pour notre tableau spécifique:

// Ces instructions définissent les attributs de notre puce et

// le langage assembleur que nous utiliserons:.syntax unified /* Voir ci-dessous après cette zone de code */ /*.cpu cortex-m0 */ /*commentez cette ligne de l'exemple */.cpu cortex-m4 /* ajouter à la place le cortex de notre conseil d'administration. voir l'image ci-dessus dans cette étape */ /*.fpu softvfp */ /* commentez cette ligne de l'exemple */.fpu vfpv4 /* ajoutez à la place celle de notre forum; il a un FPU */.thumb // Emplacements de mémoire globale..global vtable.global reset_handler /* * La table vectorielle réelle. * Seules la taille de la RAM et le gestionnaire de 'réinitialisation' sont * inclus, pour plus de simplicité. */.type vtable, %object vtable:.word _estack.word reset_handler.size vtable,.-vtable

Hmm.. Pas de directive '.align'

Cependant, ce n'est pas critique. Plus à ce sujet (peut-être) plus tard.

.syntaxe unifiée

.syntaxe [unifiée | divisé]

Cette directive définit la syntaxe du jeu d'instructions comme décrit dans la section ARM-Instruction-Set

9.4.2.1 Syntaxe du jeu d'instructions Deux syntaxes légèrement différentes prennent en charge les instructions ARM et THUMB. La valeur par défaut, divisée, utilise l'ancien style où les instructions ARM et THUMB avaient leurs propres syntaxes distinctes. La nouvelle syntaxe unifiée, qui peut être sélectionnée via la directive.syntax.

.fpu vfpv4

Le compilateur GCC peut produire des binaires avec plusieurs options concernant la virgule flottante: soft - adapté pour fonctionner sur des CPU sans FPU - les calculs sont effectués dans le logiciel par le compilateur généré softfp - adapté pour fonctionner sur des CPU avec ou sans FPU - utilisera un FPU s'il est présent. Pour notre cas spécifique (vous devrez faire vos propres recherches), le FPU de cette carte particulière est conforme à vfpv4. Vous devrez peut-être jouer avec ça. Ou même le laisser à softfp.

.thumb (vs.arm)

Ces microcontrôleurs ARM ont en fait un mélange de jeux d'instructions. L'un est ARM, l'autre est THUMB. Une différence réside dans les instructions de 16 bits par rapport aux instructions de 32 bits. Ainsi, cette directive indique au compilateur de traiter les instructions suivantes comme THUMB ou ARM.

Nous allons simplement prendre le reste du fichier tel quel, car ces Instructables n'ont pas encore exploré la programmation d'assemblage pilotée par interruption.

Étape 7: La version d'assemblage d'un programme « Hello World »

Les éléments suivants peuvent également aller dans le fichier "core. S" précédemment créé. Ceci, encore une fois, est tiré de l'exemple de l'article.

/* * Le gestionnaire de réinitialisation. Appelé lors de la réinitialisation. */.type reset_handler, %function reset_handler: // Place le pointeur de pile à la fin de la pile. // La valeur '_estack' est définie dans notre script d'éditeur de liens. LDR r0, =_estack MOV sp, r0

// Définir des valeurs factices. Quand on voit ces valeurs

// dans notre débogueur, nous saurons que notre programme // est chargé sur la puce et fonctionne. LDR r7, =0xDEADBEEF MOVS r0, #0 main_loop: // Ajoutez 1 pour enregistrer 'r0'. AJOUTE r0, r0, #1 // Rebouclage. B main_loop.size reset_handler,.-reset_handler

Ainsi, l'objectif du programme ci-dessus est de charger un motif reconnaissable dans un registre MCU central (dans ce cas R7), et une valeur incrémentielle commençant à zéro dans un autre registre MCU central (dans ce cas R0). Si nous parcourons le code d'exécution, nous devrions voir l'incrément de données de R0.

Si vous avez suivi les Instructables concernant le MSP432 et les cours/laboratoires TI-RSLK, alors à peu près tout le programme ci-dessus devrait vous être familier.

La seule nouvelle chose que je peux voir est l'utilisation de "=" lors du chargement de "DEADBEEF" pour enregistrer R7. Nous n'avions pas utilisé ça.

Le fichier "core. S" joint ici contient maintenant la source complète.

Étape 8: Compilation du code

Il est temps de faire quelques trucs en ligne de commande. Quelque chose de réel, enfin.

Cependant, nous n'en sommes pas tout à fait là. Nous devons à nouveau peaufiner la commande donnée dans l'article et la modifier en fonction de notre propre situation.

Voici l'exemple de code:

arm-none-eabi-gcc -x assembleur-with-cpp -c -O0 -mcpu=cortex-m0 -mthumb -Wall core. S -o core.o

Si nous allons sur le site gnu.org pour GCC, (dans ce cas la version 7.3),

X

Le -x sert à spécifier la langue. Sinon, s'il n'y a pas de -x, le compilateur essaiera de deviner en utilisant l'extension de fichier. (dans notre cas, *. S).

L'exemple ci-dessus de l'article spécifie assembler-with-cpp, mais nous pourrions simplement faire assembler.

c

Le -c dit compiler mais ne pas lier.

O0

Le -O sert à définir le niveau d'optimisation. L'utilisation de -O0 (oh-zero) dit "réduire le temps de compilation et faire en sorte que le débogage produise les résultats attendus. C'est la valeur par défaut".

mcpu=cortex-m0

Le -mcpu spécifie le nom du processeur cible. Dans notre cas, ce serait cortex-m4.

mpouce

Le -mthumb spécifie la sélection entre la génération de code qui exécute les états ARM et THUMB.

Mur

Le -Mur est bien sûr très répandu et bien connu. Il active tous les drapeaux d'avertissement.

Enfin, à la fin de la commande, nous avons le fichier d'entrée core. S et le fichier de sortie core.o.

Voici la nouvelle ligne de commande résultante pour s'adapter à notre cas spécifique.

arm-none-eabi-gcc -x assembleur -c -O0 -mcpu=cortex-m4 -mthumb -Wall core. S -o core.o

Et cela compilé.

Étape 9: Lier le programme

Directement à partir de l'exemple dans l'article, nous avons ceci:

arm-none-eabi-gcc core.o -mcpu=cortex-m0 -mthumb -Wall --specs=nosys.specs -nostdlib -lgcc -T./STM32F031K6T6.ld -o main.elf

La plupart de ce que vous avez vu ci-dessus. Ci-dessous les nouveautés.

specs=nosys.specs

Celui-ci est un peu délicat à expliquer.

Cela a à voir avec le "semihosting" et le "retargeting", et cela a à voir avec les entrées/sorties. Cela concerne également les appels système et les bibliothèques.

En règle générale, les systèmes embarqués ne fournissent pas de périphériques d'entrée/sortie standard. Cela affecterait les appels système ou de bibliothèque (exemple: printf()).

Le semi-hébergement signifie que le débogueur (voir l'image de l'étape 11 avec la partie du débogueur entourée en rouge) a un canal spécial et utilise le protocole de semi-hébergement, et vous pouvez voir la sortie de printf() sur la machine hôte (via le débogueur).

Le reciblage, en revanche, signifie que ces mêmes appels système ou bibliothèque signifient autre chose. Ils font autre chose, qui a du sens pour le système embarqué. Dans un sens, disons pour printf(), il y a une nouvelle implémentation, une implémentation reciblée de cette fonction.

Cela dit, le --specs=nosys.specs signifie que nous ne serons pas semi-hébergés. Cela signifierait normalement que nous sommes en train de recibler. Cela nous amène au drapeau suivant.

nostdlib

L'option de l'éditeur de liens -nostdlib est utilisée pour lier un programme destiné à fonctionner de manière autonome. -nostdlib implique les options individuelles -nodefaultlibs et -nostartfiles. Ci-dessous, nous discutons des deux options séparément, mais l'utilisation la plus courante est simplement nostdlib pour un guichet unique. Lors de la liaison d'un programme hébergé, les bibliothèques système standard telles que libc sont liées par défaut, donnant au programme l'accès à toutes les fonctions standard (printf, strlen et amis). L'option de l'éditeur de liens -nodefaultlibs désactive la liaison avec ces bibliothèques par défaut; les seules bibliothèques liées sont exactement celles que vous nommez explicitement à l'éditeur de liens en utilisant l'indicateur -l.

lgcc

libgcc.a est une bibliothèque standard qui fournit des sous-programmes internes pour surmonter les lacunes de certaines machines. Par exemple, le processeur ARM n'inclut pas d'instruction de division. La version ARM de libgcc.a inclut une fonction de division et le compilateur émet des appels à cette fonction si nécessaire.

T

C'est juste une façon de dire à l'éditeur de liens d'utiliser ce fichier comme script de l'éditeur de liens. Dans notre cas, le nom du fichier est linker.script.ld.

o main.elf

Enfin, nous indiquons à l'éditeur de liens quel sera le nom du fichier image de sortie final qui sera gravé/flashé dans notre appareil.

Voici notre version de la ligne de commande complète, modifiée pour notre situation spécifique:

arm-none-eabi-gcc core.o -mcpu=cortex-m4 -mthumb -Wall --specs=nosys.specs -nostdlib -lgcc -T./linker.script.ld -o main.elf

Nous nous assurons que ce fichier de script et le fichier core.o se trouvent tous les deux dans le même répertoire, où nous exécuterons la ligne de commande ci-dessus.

Et ça se connecte sans problème.

Un chèque

On lance alors:

arm-none-eabi-nm main.elf

et on obtient:

devchu@chubox:~/Development/Atollic/TrueSTUDIO/STM32_workspace_9.1$ arm-none-eabi-nm main.elf 20014000 A _estack 08000010 t main_loop 08000008 T reset_handler 08000000 T vtable

Cela semble bon. La commande arm-none-eabi-nm est un moyen de répertorier les symboles dans les fichiers objets.

Étape 10: Test de connexion au STM32 Nucleo-64

Test de connexion au STM32 Nucleo-64
Test de connexion au STM32 Nucleo-64
Test de connexion au STM32 Nucleo-64
Test de connexion au STM32 Nucleo-64

Votre première mission, si vous choisissez de l'accepter, est de faire en sorte que votre système voie votre carte de développement.

Utilisation de Windows

Pour Windows, j'ai décidé d'installer TrueSTUDIO d'Atollic (version gratuite). C'était une installation indolore et le pilote a été automatiquement installé pour que je puisse utiliser st-link pour tester la connexion. Une fois que j'ai installé TrueSTUDIO et que le gestionnaire de périphériques a vu le périphérique, j'ai téléchargé les outils texan/stlink suggérés par l'article Bare Metal que nous avons suivi. J'ai à nouveau placé le dossier directement sous "C:\" et j'ai de nouveau créé des liens depuis mon bac local cygwin vers les commandes.

ln -s /c/STM32. MCU/stlink-1.3.0-win64/bin/st-info.exe ~/bin/st-info

Comme test initial pour voir si nous pouvons vraiment communiquer avec l'appareil, j'ai exécuté:

st-info --sonde

Et je suis revenu:

Trouvé 1 programmeurs stlink

Alors maintenant, nous savons que nous pouvons parler/interroger notre carte de développement.

Utiliser Linux

Pour Linux, vous n'avez pas vraiment besoin d'un pilote. Mais pour Debian, vous devrez construire les outils st à partir des sources.

git clone

Assurez-vous que libusb-1.0-0-dev est installé.

liste apt | grep -E "*libusb.*dev*"

Tu devrais voir:

libusb-1.0-0-dev/xenial, maintenant 2:1.0.20-1 amd64 [installé]

ou quelque chose comme ça.

Pour l'installer:

sudo apt-get install libusb-1.0-0-dev

Notez que ce qui précède n'est pas la même chose que:

sudo apt-get install libusb-dev

Le dev libusb manquant correct peut causer des problèmes à cmake.

Erreur CMake: les variables suivantes sont utilisées dans ce projet, mais elles sont définies sur NOTFOUND. Veuillez les définir ou vous assurer qu'elles sont définies et testées correctement dans les fichiers CMake: LIBUSB_INCLUDE_DIR (ADVANCED)

Accédez au répertoire racine du projet (…blah/blah /stlink). Faites un "make release".

Après cette compilation, les outils doivent être sous ".. /build/Release".

Vous pouvez ensuite exécuter "st-info --probe". Voici la sortie avec le Nucleo connecté, alors non.

devchu@chubox:~/Development/stlink$./build/Release/st-info --probeFound 1 série de programmeurs stlink: 303636414646353034393535363537 openocd: "\x30\x36\x36\x41\x46\x46\x35\x30\x34\ x39\x35\x35\x36\x35\x37" flash: 524288 (taille de page: 2048) sram: 65536 chipid: 0x0446 descr: F303 périphérique haute densité devchu@chubox:~/Development/stlink$./build/Release/st- info --probe Trouvé 0 programmeurs stlink devchu@chubox:~/Development/stlink$

Étape 11: Utilisons GDB avec Linux

Utilisons GDB avec Linux
Utilisons GDB avec Linux
Utilisons GDB avec Linux
Utilisons GDB avec Linux

Si vous avez essayé tout cela et que vous êtes arrivé jusqu'ici, tant mieux ! Excellent. Amusons-nous un peu maintenant.

Lorsque vous achetez ces cartes de développement ARM, qu'il s'agisse du Launchpad MSP432 de Texas Instruments, ou de celle dont nous parlons maintenant, la Nucleo-F303 (STM32 Nucleo-64), elles arrivent généralement déjà flashées avec un programme en cours d'exécution, généralement un programme clignotant qui comprend également le fait d'appuyer sur un interrupteur pour modifier la vitesse à laquelle les LED clignotent.

Avant que nous ne soyons si prompts à écraser cela, voyons ce qu'il y a à voir et à faire.

Avec Linux, ouvrez un terminal, changez de répertoire dans le projet stlink git que nous venons de construire et trouvez l'outil st-util.

devchu@chubox:~/Development/stlink$ find. -nom st-util

./build/Release/src/gdbserver/st-util

Exécutez cet outil. Puisque nous avons déjà testé notre connexion avec st-info --probe, nous devrions obtenir une sortie comme ceci:

st-util 1.4.0-50-g7fafee2 2018-10-20T18:33:23 INFO common.c: Chargement des paramètres de l'appareil…. 2018-10-20T18:33:23 INFO common.c: L'appareil connecté est: F303 appareil haute densité, id 0x10036446 2018-10-20T18:33:23 INFO common.c: Taille SRAM: 0x10000 octets (64 KiB), Flash: 0x80000 octets (512 KiB) en pages de 2048 octets 2018-10-20T18:33:23 INFO gdb-server.c: Chip ID est 00000446, Core ID est 2ba01477. 2018-10-20T18:33:23 INFO gdb-server.c: Écoute à *:4242…

C'est le serveur GDB qui fonctionne actuellement, et il voit notre carte de développement, et plus important encore, il écoute sur le port 4242 (le port par défaut).

Nous sommes maintenant prêts à lancer le client GDB.

Sous Linux, ouvrez un autre terminal, saisissez ceci:

arm-none-eabi-gdb -tui

C'est exactement la même chose que d'exécuter gdb strictement en ligne de commande, mais il produit à la place un terminal basé sur du texte (je suppose qu'il utilise des malédictions).

Nous avons le client GDB et le serveur GDB en cours d'exécution. Cependant, le client n'est pas connecté au serveur. Pour le moment, il ne sait rien de notre Nucleo (ou de la carte de votre choix). Nous devons le dire. Dans le terminal, votre invite devrait maintenant être le "(gdb)". Entrer:

aider à cibler

Il vous donnera une liste. Notez que celui que nous voulons est target extended-remote - Utilisez un ordinateur distant via une ligne série.

Mais il faut aussi lui donner l'emplacement. Ainsi, à l'invite (gdb), entrez:

(gdb) cible étendu-distant localhost:4242

Vous devriez obtenir une réponse comme ceci:

(gdb) cible étendu-distant localhost:4242

Débogage à distance à l'aide de localhost:4242 0x080028e4 dans ?? ()

Pendant ce temps, sur le terminal exécutant le st-util gdbserver, nous avons ceci:

2018-10-20T18:42:30 INFO gdb-server.c: Trouvé 6 registres de points d'arrêt hw

2018-10-20T18:42:30 INFO gdb-server.c: GDB connecté.

Étape 12: Répétons, avec Windows et Flash notre programme

Répétons, avec Windows et Flash notre programme
Répétons, avec Windows et Flash notre programme
Répétons, avec Windows et Flash notre programme
Répétons, avec Windows et Flash notre programme
Répétons, avec Windows et Flash notre programme
Répétons, avec Windows et Flash notre programme

Les étapes pour exécuter le st-util gdbserver et le client arm-none-eabi-gdb sont essentiellement les mêmes que celles que nous avons faites lors de l'étape précédente. Vous ouvrez deux terminaux (cygwin, DOS cmd ou Windows Powershell), recherchez l'emplacement du st-util, exécutez-le. Dans l'autre terminal, exécutez le client arm-none-eabi-gdb. La seule différence est que le mode -tui (affichage de texte basé sur un terminal) n'est probablement pas pris en charge.

Si ce qui précède a fonctionné sous Windows, vous devrez probablement arrêter (uniquement le client). À ce stade, vous devrez d'une manière ou d'une autre exécuter le client GDB où se trouve votre fichier de construction ("core.out"), ou ajouter le chemin d'accès complet à ce fichier en tant qu'argument du client GDB.

J'ai simplifié ma vie en utilisant cygwin et en créant des liens à partir de mon répertoire local $HOME//bin vers l'endroit où résident ces deux outils.

Ok, nous avons compilé et lié comme avant, et nous avons le fichier main.elf prêt à être flashé.

Nous avons st-util exécuté dans une fenêtre. On redémarre le client GDB, cette fois on fait:

arm-none-eabi-gdb main.elf

Nous le laissons démarrer, attendons l'invite (gdb), exécutons notre même commande de connexion au serveur GDB (st-util), et nous sommes prêts à flasher l'exécutable. C'est très anti-climatique:

(gdb) charge

Fonctionnant avec des terminaux cygwin, il existe un problème connu avec parfois les commandes de la console ne s'affichent pas. Donc dans notre cas, la fenêtre exécutant le serveur était complètement silencieuse. Celui qui exécute le client, où nous avons exécuté la charge, affiche ceci:

Section de chargement.text, taille 0x1c lma 0x8000000Adresse de début 0x8000000, taille de chargement 28 Taux de transfert: 1 Ko/sec, 28 octets/écriture.

Étape 13: Flasher avec Linux - Plus gratifiant:D

Flasher avec Linux - Plus gratifiant:D
Flasher avec Linux - Plus gratifiant:D

Étape 14: Plongeons un peu plus loin

Si vous arrivez ici, excellent. Allons-nous en.

Pourquoi ne pas regarder à l'intérieur du fichier main.elf, l'exécutable ? Exécutez ce qui suit:

arm-none-eabi-objdump -d main.elf

Vous devriez voir une sortie comme celle-ci:

main.elf: format de fichier elf32-littlearm

Démontage de la section.text:

08000000:

8000000: 00 40 01 20 09 00 00 08.@. ….

08000008:

8000008: 4802 ldr r0, [pc, #8]; (8000014) 800000a: 4685 mov sp, r0 800000c: 4f02 ldr r7, [pc, #8]; (8000018) 800000e: 2000 movs r0, #0

08000010:

8000010: 3001 ajoute r0, #1 8000012: e7fd b.n 8000010 8000014: 20014000.word 0x20014000 8000018: deadbeef.word 0xdeadbeef

Quelles petites pépites pouvons-nous obtenir de la sortie ci-dessus ?

Si vous vous souvenez de la discussion et de la création du fichier linker.script.ld, nous avons déclaré que ces périphériques ARM avaient une RAM commençant à 0x20000000 et que la mémoire FLASH commençait à 0x08000000.

Ainsi, nous pouvons voir qu'effectivement le programme est tel que tout réside dans la mémoire FLASH.

Ensuite, au-dessus, mais à une étape ultérieure, lorsque nous discutions de la partie "Hello World", il y avait une instruction dans laquelle nous chargeions une valeur littérale constante et immédiate ("0xDEADBEEF") dans un registre central MCU ("R7").

La déclaration était:

LDR R7, = 0xDEADBEEF

Dans notre code, c'est le seul endroit où nous mentionnons même DEADBEEF. Nulle part ailleurs. Et pourtant, si vous regardez les instructions ci-dessus démontées/reconstruites, etc., il y a plus de choses liées à DEADBEEF que nous ne le pensions.

Ainsi, le compilateur/éditeur de liens a en quelque sorte décidé de flasher en permanence la valeur de DEADBEEF dans une adresse FLASH, à l'emplacement 0x8000018. Et puis, le compilateur a changé notre instruction LDR ci-dessus pour qu'elle soit:

LDR R7, [PC, #8]

Cela a même généré un commentaire pour nous. Comme c'est gentil. Et il nous dit de prendre la valeur actuelle du compteur de programme (le registre PC), d'ajouter 0x8 à cette valeur, et c'est là que DEADBEEF a été gravé, d'obtenir cette valeur et de la mettre dans R7.

Cela signifie donc également que le compteur de programme (PC) pointait vers l'adresse 0x8000010, qui est le début de main_loop, et que la valeur DEADBEEF se trouve à deux adresses après la fin de main_loop.

Étape 15: Enfin, un bref aperçu du programme en cours d'exécution

Même si vous quittez GDB, ressaisissez simplement la commande. Vous n'avez même pas besoin de lui donner de fichier; nous ne flashons plus, nous l'exécutons simplement.

Une fois que vous avez reconnecté le client GDB au serveur GDB, à l'invite de commande (gdb):

(gdb) registres d'informations

Vous devriez voir quelque chose comme ceci:

r0 0x0 0

r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0x0 0 r8 0x0 0 r9 0x0 0 r10 0x0 0 r11 0x0 0 r12 0x0 0 sp 0x20014000 0x200000ffffr8000 lps 0216000

Mais ensuite, à l'invite (gdb), entrez:

(gdb) continuer

Et très rapidement appuyez sur CTRL-C. Cela devrait mettre le programme en pause. Entrez à nouveau la commande "info registers".

Cette fois, c'est différent:

(gdb) registres d'informations

r0 0x350ffa 3477498 r1 0x0 0 r2 0x0 0 r3 0x0 0 r4 0x0 0 r5 0x0 0 r6 0x0 0 r7 0xdeadbeef 3735928559 r8 0x0 0 r9 0x0 0 r10 0x0 lr 8000 pc 014000x 014000 0 r12000 01400000 16777216

Que s'est-il passé? Exactement ce que nous voulions. DEADBEEF a été chargé dans R7, et R0 a été (extrêmement rapide) incrémenté. Si vous répétez, vous verrez à nouveau R0 avec une autre valeur.

Étape 16: Nous voulions créer un tableau en lecture seule dans Flash

Une façon de créer l'équivalent d'un tableau à l'aide d'assembly et de directives est la suivante:

.type myarray, %object // le nom ou l'étiquette 'myarray' est défini comme un type d'objet.

myarray: // c'est le début de la déclaration de 'myarray' // (en quoi il consistera)..word 0x11111111 //le premier membre ou la première valeur contenue dans 'myarray'..word 0x22222222 //la deuxième valeur (adresses contiguës)..word 0x333333333 //et ainsi de suite..size myarray,.-myarray // le compilateur/assembleur sait maintenant où la fin ou // la limite de 'myarray'.

Maintenant que nous l'avons configuré en mémoire FLASH, nous pouvons l'utiliser dans le programme. Ci-dessous une partie:

LDR R1, myarray // ceci charge les données contenues au 1er emplacement de 'myarray'.' // ce n'est pas ce que nous voulons.

LDR R1, =myarray // cela charge la valeur de l'emplacement elle-même (la 1ère adresse), // pas les données.. // c'est ce que nous voulons.

MOV R2, #0 // R2 gardera un compte pour s'assurer que nous ne partons pas

// fin du tableau. LDR R3, =myarrsize // R3 sera l'équivalent de 'myarrsize'.

// R0 contiendra nos données

boucle principale:

LDR R0, [R1] // Charge les données pointées par R1 ('myarray') dans R0. CMP R2, R3 // Sommes-nous à la limite du tableau ? BEQ main_loop // Si c'est le cas, nous avons terminé, nous allons donc boucler indéfiniment.

AJOUTER R2, #1 // Sinon, nous pouvons continuer à parcourir le tableau.

AJOUTER R1, #4 // Ajoutez 4 au registre R1, afin qu'il pointe correctement vers le suivant

// adresse..

B main_loop // Boucle arrière.

La vidéo passe en revue tout cela, et il y a un bug dedans. C'est bien; cela montre qu'il est important d'exécuter et de déboguer le code. Il montre un cas classique de sortie de la fin d'un tableau.

Conseillé: