Maîtrise rapide des microcontrôleurs STM32. Commençons par étudier Cortex-M en utilisant le STM32 comme exemple

Microcontrôleurs pour chatons

Miaou tout le monde, les chats :)

Un jour, un chat m'a quitté : (Eh bien, pourquoi manger de la valériane, j'ai décidé de me mettre au travail, pour ainsi dire, « pour le bien de la Patrie ». J'ai longtemps voulu travailler sur des appareils numériques, mais je ne l'ai pas fait Je n'ai pas le temps (vous savez, soit dormir, soit avec le chat qui marche sur les toits), et puis le temps est juste apparu. Bon, commençons..)

Comme d'habitude, tout commence par un choix. Eh bien, il semble que le choix se porte sur un petit PIC ou un AVR. D'une manière ou d'une autre, j'ai davantage aimé ce dernier. J'avais également besoin d'un programmateur USB en raison du manque d'autres ports sur l'ordinateur, dont le prix m'a presque fait tomber la queue. Il existe également un Arduino - une telle bête. Il peut également être programmé via USB. Eh bien, je pense, « exactement ce que le médecin m’a prescrit ». Dans notre village, vous ne pouvez l'obtenir que via une boutique en ligne. J'ai trouvé une meilleure offre, j'ai failli l'acheter et... OOP ! Je cherche - STM32VL-Discovery. De quel genre d'animal s'agit-il ? Hmm, STM32.. J'ai entendu quelque chose du coin de mon oreille.. Et les caractéristiques me font dresser la moustache, honnêtement !

Et elle a tellement de pattes !

Donc dans l'ordre :

  • Arduino dispose de 14 ports d'E/S numériques et de 6 entrées analogiques. Le STM32VL-Discovery dispose de 45 entrées/sorties numériques, dont 10 peuvent en option être converties en entrées analogiques.
  • Arduino dispose de 32 Ko de stockage de programme et de 2 Ko de RAM. Le STM32VL-Discovery dispose de 64 Ko de stockage de programme et de 8 Ko de RAM.
  • Arduino a une fréquence d'horloge de 16 MHz, tandis que STM32VL-Discovery a une fréquence d'horloge de 24 MHz.
  • Tout microcontrôleur STM32 peut être remplacé par un autre STM32, mais avec meilleures caractéristiques, sans changer le schéma
  • STM32 peut être programmé sans programmateur via le port COM (nous en reparlerons plus tard)
  • Le prix de l'Arduino au moment de la rédaction est d'environ 1 300 roubles, celui du STM32VL-Discovery d'environ 600 roubles. C'est plus de 2 fois moins cher !

Et après? Le STM32VL-Discovery dispose d'un programmeur/débogueur intégré qui, avec un léger mouvement de la patte (en retirant les cavaliers), peut programmer et déboguer (le débogage est une chose très utile, mais nous y reviendrons plus tard) les microcontrôleurs STM32 en dehors de la carte. Cela ne fonctionnera pas avec Arduino. Autrement dit, en utilisant STM32VL-Discovery, nous économisons de l'argent et obtenons une plus grande productivité et une plus grande liberté de création :)

Et les microcontrôleurs STM32 eux-mêmes semblent plus attrayants que les autres :

STM32F100C4T6B ATtiny24A-SSU PIC16F688-I/SL STM32F103RET6 ATmega1284P-PU PIC18F4550-I/PT
Prix ​​moyen, frotter 60 65 60 240 330 220
Fréquence d'horloge, MHz 24 20 20 72 20 48
Mémoire flash, Ko 16 2 4 512 128 16
RAM, octet 4096 128 256 65536 16384 2048
USART, pièces. 2 0 0 5 2 0
SPI, pièces. 1 1 0 3 1 1
ADC, pièces. 16x12 bits 8x10 bits 8x10 bits 16x12 bits 8x10 bits 13x10 bits
CAD, pièces. 1x12 bits 0 0 2x12 bits 0 0
Nombre de lignes d'entrée/sortie, pcs. 37 12 12 51 32 35

Et STM32 est en 32 bits, ce qui signifie qu'il peut fonctionner avec des données 32 bits en un seul cycle d'horloge. AVR et PIC ne peuvent pas s'en vanter.

Eh bien, les chats, êtes-vous convaincus ? Alors commençons le cours d'un jeune guerrier numérique !)

Comment ça marche? En quoi cela consiste? Que peut-il faire?

Comme vous le savez, tous les chats sont très curieux, et les chats radio en particulier !

Un microcontrôleur est un microcircuit qui combine les fonctions d'un processeur, de périphériques, de RAM et de mémoire flash. Comme un ordinateur, mais en plus petit !

Faisons une analogie : l’ordinateur est contrôlé par le système d’exploitation, et le microcontrôleur est contrôlé par le « firmware » que vous écrivez ; le système d’exploitation de l’ordinateur est stocké sur le disque dur, le « firmware » du microcontrôleur est stocké dans sa mémoire flash ; Les fonctions de la RAM sont similaires : stocker les données changeantes pendant l'exécution du programme. Et le MK dispose également de divers périphériques, comme l'ADC et le DAC par exemple.

MK communique avec le monde extérieur grâce à ses pattes sur son corps (pas comme celles des chats bien sûr, mais en métal). Mais tous ne sont pas contrôlés par le programme : il existe des broches d'alimentation, une broche de réinitialisation, des broches d'alimentation périphérique et une broche d'alimentation de secours. Et ceux qui sont contrôlés par le programme sont divisés en groupes appelés « ports ». Toutes ces sorties contrôlées sont nommées avec 2 lettres et un chiffre. Par exemple PA1 : P - port, A - port « A », 1 - numéro de broche de ce port.

Dans le programme, les ports sont configurés soit en entrée, soit en sortie, selon vos souhaits.

Les broches d'un port configuré pour l'entrée peuvent être dans différents modes ; pour chaque broche, cela peut être différent :

  • Une entrée numérique est une entrée dont la valeur (1 ou 0 logique) peut être lue par un programme. Si la tension à l'entrée est 0, alors la valeur est 0, si la tension à l'entrée est égale à la tension d'alimentation, alors la valeur de l'entrée est 1. Le troisième n'est pas donné. Peut être réalisé avec une résistance de rappel soit à l'alimentation, soit à la terre
  • Entrée analogique - une entrée dont la valeur peut être lue par le programme, mais il peut y avoir plusieurs valeurs - jusqu'à 4096. Plus précisément, de 0 si la tension d'entrée est de 0 par rapport à l'alimentation négative du microcontrôleur à 4095 si la tension d'entrée est égale à la tension d'alimentation. Toutes ces transformations sont effectuées par un ADC - un convertisseur analogique-numérique, avec son aide, vous pouvez, par exemple, mesurer la tension sur une thermistance et connaître la température, ou mesurer la tension sur une photorésistance et connaître la luminosité de la lumière qui tombe dessus... Eh bien, vous pouvez inventer beaucoup de choses si vous avez de l'imagination :) Si vous alimentez le microcontrôleur à partir de 3V, alors 0V = 0 et 3V = 4096, ce qui signifie 3/4096 = 0,000732421 , c'est à dire. lorsque la tension d'entrée change de 0,000732421 V, la valeur d'entrée dans le programme passe à 1. Ce n'est pas si compliqué, n'est-ce pas ? Poursuivre
  • Entrée numérique en mode fonction alternative - entrée pour travailler avec des périphériques. Par exemple, une entrée pour une minuterie ou une entrée pour une interface. La valeur de cette entrée ne peut pas être lue à partir du programme. Dans un programme, par exemple, vous pouvez lire les données reçues de cette sortie par une interface.

Et un port configuré pour la sortie peut avoir des broches dans les modes suivants :

  • Sortie. Juste une issue. Sortie numérique régulière. Il y a soit une tension d'alimentation au niveau de la broche (1 logique), soit aucune tension au niveau de la broche (0 logique). C'est simple.
  • Sortie en mode fonction alternative - sortie contrôlée par les périphériques. Cette sortie ne peut pas être contrôlée depuis un programme, mais un programme peut être forcé à contrôler cette sortie, par exemple une interface.

Mais toutes les conclusions ne peuvent pas être attribuées « à votre guise ». Afin de savoir ce qui est possible et ce qui ne l'est pas, vous devez consulter la documentation (Tableau 4) ou utiliser le programme MicroXplorer.

Avant d'utiliser le port, vous devez d'abord le synchroniser - lui envoyer des impulsions d'horloge, car au départ, ils ne sont pas fournis pour économiser de l'énergie. Vous pouvez choisir une fréquence d'horloge différente : plus la fréquence est élevée, plus les entrées ou sorties de ce port fonctionnent rapidement, mais aussi plus la consommation d'énergie est élevée.

Il y a aussi des conclusions DÉMARRAGE 0 Et DÉMARRAGE 1. Ces broches n'appartiennent pas aux ports, elles servent à contrôler le chargement du microcontrôleur. Si lors de l'alimentation il y a un zéro logique au niveau de la broche BOOT 0 (la broche est connectée à un point commun), alors le microcontrôleur exécute le programme chargé dans la mémoire flash, c'est-à-dire Votre firmware. Si, lorsque l'alimentation est fournie, la broche BOOT 0 est une broche logique (la broche est connectée à l'alimentation du microcontrôleur) et la broche BOOT 1 est un zéro logique, alors le microcontrôleur n'exécute pas votre firmware, mais un chargeur de démarrage enregistré en usine. . Souviens-toi de ça ! Vous l'utiliserez beaucoup lorsque vous travaillerez avec des microcontrôleurs STM32 ! Chargement parfois d'un chargeur de démarrage enregistré en usine - Le seul moyenécrire/modifier le firmware du microcontrôleur. Cela se produit, par exemple, lors de la configuration dans le firmware des broches auxquelles le programmateur est connecté ou lors du flashage du firmware du microcontrôleur sans utiliser de programmateur. Donc recommande fortement Lors de la conception d'un circuit imprimé, ces broches (ou au moins BOOT 0) doivent être situées dans un endroit pratique.

Nous avons donc compris :) Nous savons maintenant ce qu'est un microcontrôleur et en quoi il consiste. Nous allons maintenant en apprendre davantage sur la sagesse et passer à la chose la plus intéressante : la pratique !

Le programme dans le microcontrôleur est exécuté étape par étape. Un cycle de processeur correspond à une étape de programme.

Par exemple, laissez les voyants rouge et vert clignoter jusqu'à ce que le bouton soit enfoncé. La durée de chaque lampe est de 5 secondes. Voici l'algorithme :

  1. Vérifions s'il y a de la tension à l'entrée avec le bouton ? (le bouton ferme la sortie du microcontrôleur sur + alimentation)
  2. S'il n'y a pas de tension, alors le voyant rouge s'allume pendant 5 secondes, le voyant vert s'éteint, s'il y a de la tension, alors on recommence
  3. Vérifier à nouveau
  4. S'il n'y a pas de tension, alors le voyant vert s'allume pendant 5 secondes, le voyant rouge s'éteint, s'il y a de la tension, alors on recommence
  5. Recommençons

ARRÊT! Que se passe-t-il si j'appuie sur le bouton alors que la lumière est allumée ? Rien ne se passera! Parce que le programme est exécuté étape par étape et que l'étape de vérification de la pression sur le bouton se situe au moment de l'allumage des ampoules.
C'est précisément pour de tels cas qu'il existe une chose telle que interrompt

Les interruptions permettent d'interrompre l'exécution du programme principal. Cela peut se faire soit par un événement externe (appuyer sur un bouton, relâcher un bouton, recevoir des données, etc.) ou interne (par une minuterie ou il est temps de nourrir le chat par exemple). Lorsque cette interruption se produit, le sous-programme commence à s'exécuter. Les sous-programmes peuvent être différents pour différents types interruptions, ces routines sont appelées gestionnaires d’interruptions.

Lorsque ce même gestionnaire d'interruption termine son travail, le programme principal commence à s'exécuter à l'endroit où il a été interrompu.

Levons-nous !

Eh bien, les chatons, il est temps de se lever sur les pattes ! J'espère que vous avez déjà une carte de débogage ? Ou au moins un microcontrôleur ? J'espère qu'il y en a :) Et sinon, courons au magasin ! (et de préférence pas pour le saucisson. Quoique...) Qu'est-ce que cet enseignement sans pratique ?

C'est bien d'avoir une carte de débogage au début, par exemple STM32VL-Discovery, mais si le crapaud s'étrangle ou si vous n'en avez toujours pas assez pour les saucisses, alors vous pouvez vous débrouiller avec un microcontrôleur et une interface RS-232 -> UART convertisseur (par exemple MAX3232) ou USB -> UART (par exemple FT232RL). Dans ce cas, 100 roubles peuvent être entièrement dépensés, mais vous devrez réaliser un circuit imprimé et souder au moins 48 broches de 0,3 mm de large avec un écart de 0,2 mm. J'ai prévenu.

Vous devez d’abord connecter naturellement la carte de débogage ou le contrôleur à l’ordinateur.

Si vous disposez d'une carte de développement :

Avec une carte de débogage, bien sûr, c'est plus facile. Nous prenons un cordon Mini-USB et connectons la carte à l'ordinateur, tous les pilotes doivent être installés automatiquement. Voir Clé STMicroelectronics STLink dans le gestionnaire de périphériques - bon signe! Eh bien, si quelque chose ne va pas et que rien ne fonctionne, vous n'avez pas besoin de rayer le canapé, il vous suffit de venir ici et de l'installer. Utilitaire STM32 ST-LINK.

Eh bien, si vous êtes l'heureux propriétaire d'un ordinateur exécutant Windows 8, avant d'effectuer les étapes ci-dessus, vous devez procéder comme suit : Possibilités -> Modifier les paramètres de l'ordinateur -> Sont communs -> Options de téléchargement spéciales et sélectionnez une option Désactiver la vérification de la signature du pilote.

Si vous possédez un microcontrôleur :

Si vous possédez un microcontrôleur, vous devez avoir les jambes droites. Mais je ne doute pas de toi !

Avant de connecter le microcontrôleur à l'ordinateur, il doit être soudé au circuit imprimé. Pour cela, en plus d'un microcontrôleur et de pattes droites, vous avez besoin d'au moins un circuit imprimé. Et puis il y a votre créativité.

Le minimum de travail dans le diagramme ci-dessous :

Mais c'est un minimum sans intérêt.

Ajoutez des LED et des boutons (n'oubliez pas les broches BOOT), comme ceci

Mais il peut y avoir des problèmes avec la soudure de cette puce. Mais j'espère qu'ils ne surgiront pas. J'ai réussi à le souder avec mon fer à souder soviétique préféré de 25 W avec une largeur de pointe 3/4 de la largeur du contrôleur. J'ai plus de problèmes avec la fabrication d'un circuit imprimé... eh bien, chacun a sa propre technologie.

Et l'adaptateur doit être fabriqué vers UART selon la documentation du microcircuit que vous avez acheté.

Nous connectons les broches TxD et RxD du circuit imprimé avec les broches RxD et TxD, respectivement, de l'adaptateur. N'oublions pas le point commun et la nutrition de tout cela.

Sélection et installation du logiciel

Nous utiliserons l'environnement de développement CooCoxIDE, mais ce n'est pas comme ça, mais pour plusieurs raisons :

  • Premièrement, il s’agit d’un logiciel distribué gratuitement. Cela signifie que votre karma sera propre
  • À mon avis (et pas seulement le mien), cet environnement de développement est plus pratique que d'autres
  • Permet l'utilisation du débogage
  • Beaucoup d'exemples pouvant être chargés dans l'environnement de développement (utiles pour les chatons et plus)

L'environnement de développement est à la fois un programme de codage, un compilateur et un débogueur. Pratique :) Mais si un chat dur de Chelyabinsk est plus à l'aise pour écrire du code (dans un bloc-notes, par exemple), pour compiler et flasher avec différents programmes - cela ne me dérange pas, alors vous aurez besoin de l'utilitaire STM32 ST-LINK pour charger le firmware dans le microcontrôleur. Le propriétaire est un gentleman, comme on dit.

Cet environnement de développement est basé sur le célèbre Eclipse.

  1. Allons ici
  2. piquer Télécharger via CoCenter (recommandé)
  3. Entrez votre adresse email (c'est bon, elle est là « pour le spectacle »)
  4. Après le téléchargement, installez celui-ci CoCentre
  5. Dans la première ligne où il est écrit CooCoxCoIDE poussée Télécharger
  6. Une fois le téléchargement terminé, au lieu de Télécharger volonté Installer. Cliquez ici
  7. Allons ici
  8. Directement dans la colonne Télécharger téléchargez le fichier qui .exe. Installons-le.
  9. Nous l'ouvrons nous-mêmes CooCoxCoIDE, onglet Projet, Sélectionnez le chemin de la chaîne d'outils.
  10. Nous indiquons le chemin d'accès au fichier arm-none-eabi-gcc.exe (nous l'avons installé à l'étape 8, le chemin ressemble approximativement à ceci : D : Program Files (x86) GNU Tools ARM Embedded4.7 2013q1bin)
  11. Réouverture CoIDE, presse Voir -> Configuration, ouvrez l'onglet Débogueur et nous faisons ça [photo]
  12. Nous sommes heureux car nous pouvons désormais écrire un programme et le flasher dans le microcontrôleur ! C'est ce que nous ferons.

Si vous avez une option sans carte de débogage/programmeur, vous aurez alors besoin d'un programme pour charger le programme dans le MK. Démonstrateur du chargeur Flash qui est situé

Nous trouvons langage mutuel

Avant d'écrire votre premier programme, vous devez trouver un langage commun avec MK. Il est peu probable qu'il apprenne notre langue, nous devrons donc apprendre (ou peut-être simplement nous souvenir) la langue dans laquelle nous communiquerons avec MK, c'est C. Nous n'avons besoin que des bases (composition du programme, fonctions, opérateurs). Si vous connaissez cette langue, vous pouvez alors accéder immédiatement à la rubrique « Premier programme », mais je mettrai à jour ceux qui ne la connaissent pas.

Le projet est constitué de fichiers avec les extensions .c Et .h. Le premier contient les fonctions, le second contient les noms des fonctions utilisées et des constantes par exemple. C'est comme ça. La plupart fichier principal, qui contient le code du programme principal c. Pour utiliser diverses fonctions, vous devez connecter des bibliothèques avec ces fonctions. Ils se connectent en enregistrant #include "nom_bibliothèque" Eh bien, les bibliothèques devraient naturellement faire partie du projet. Ils sont inclus au tout début du fichier.

Les fonctions sont une partie unique d'un programme. En général, un programme est constitué d'une ou plusieurs fonctions. La fonction ressemble à :

return_variable_type nom_fonction (variable_type)
{
Corps de fonction
}

Vous pouvez envoyer une variable à une fonction, la fonction la traitera et renverra une valeur. Il est très pratique d'utiliser une fonction pour des actions répétées plutôt que d'écrire constamment le même morceau de code ; vous pouvez simplement envoyer une variable à la fonction et recevoir en retour la valeur traitée.

Avant de pouvoir utiliser une fonction, elle doit être déclarée au tout début du fichier. Ils font comme ça :

return_variable_type nom_fonction (type_variable);

Ah oui, j'ai oublié le plus important ! Il doit y avoir un point-virgule à la fin de chaque ligne !

Si la fonction ne renvoie rien (par exemple, un délai, elle tire juste le chat par la queue à temps), alors le type est indiqué vide.

Au démarrage, la fonction est toujours exécutée en premier principal().

Eh bien, il semble que nous ayons compris les fonctions, la compréhension ne viendra qu'avec la pratique.

J'ai mentionné ci-dessus type de variable. Toutes les variables peuvent être de différents types, voici les principales :

  • INT - une variable de ce type ne peut être qu'un entier compris entre -2147483648 et 2147483647.
  • FLOAT - une variable de ce type est un nombre avec une précision allant jusqu'à 7 chiffres de ±1,5*10-45 à ±3,4*1033
  • DOUBLE - nombre avec une précision allant jusqu'à 16 chiffres de ±5*10-324 à ±1,7*10306
  • ULONG est aussi un entier, mais de 0 à 18446744073709551615
  • LONG - entier de -9223372036854775808 à 9223372036854775807
  • CHAR - un caractère
  • BOOL est une variable logique. Il ne peut avoir que 2 valeurs : vrai ou faux.

Une chaîne (mot, phrase) peut être représentée comme un tableau de caractères char. Par exemple:

chaîne de caractères = "Mot" ;

Ici, les crochets sont le nombre de caractères dans la ligne, « stroka » est le nom du tableau.

Avant d'utiliser une variable, il faut la déclarer. (spécifiez simplement le type et le nom de la variable)

  • + - ajout.
  • - - soustraction.
  • * - multiplications.
  • / - division.
  • = - attribuer une valeur à une variable.

Par exemple l'expression a=b+c signifie attribuer à une variable un la valeur de la somme des valeurs des variables b Et c.

  • ++ - incrément. Augmenter la valeur d'une variable de 1
  • -- - décrémenter. Diminuer la valeur d'une variable de 1

Par exemple l'expression un++ signifie augmenter la valeur de la variable un par 1 (identique à une=une+1)

  • == - comparaison, signe égal. (À NE PAS CONFONDER AVEC AFFECTATION)
  • != - comparaison, signe « pas égal ».
  • < - comparaison, signe « inférieur à ».
  • <= - comparaison, signe « inférieur ou égal ».
  • > - comparaison, signe « plus ».
  • >= - comparaison, signe « supérieur ou égal ».

Par exemple l'expression un devient vrai si la valeur de la variable un inférieur à la valeur variable b et faux si les valeurs sont égales ou un plus b. Expression une==b vrai si unéquivaut à b et faux si un inégal b, MAIS l'expression une = b vrai Toujours parce que ce n'est pas une comparaison, c'est une affectation à une variable un valeurs variables b.

  • % - reste de la division

Par exemple si une=5,b=3, alors la valeur de l'expression un B sera égal à 2 (puisque 5/3=1 (2 restants))

  • << - décalage au niveau du bit vers la gauche. Sans entrer dans le détail du sens de l'expression un< en langage C ce sera égal à l'expression un*2 b
  • >> - décalage au niveau du bit vers la droite. Expression une>>b dans le programme est équivalent à l'expression a/2b
  • & - logique ET.
  • | - logique OU.
  • ~ - l'inversion.

J'ai presque oublié de te parler des cycles. Basique:

pendant que(condition) (

corps de boucle

Le corps de la boucle (tout entre accolades) est exécuté lorsque la condition est vraie (jusqu'à ce que la condition devienne fausse).

pour (valeur_initiale ; boucle_exécutée_jusqu'à, étape) (

corps de boucle

Valeur initiale- valeur initiale du compteur

Boucle_runs_jusqu'à - Jusqu'à quelle valeur est atteinte, la boucle s'exécute

Étape -à quelles étapes le compteur compte-t-il ?

Par exemple

pour (i=0; je<10, i++) {

corps de boucle

Voici la valeur initiale de la variable je est égal à 0, la boucle s'exécute jusqu'à la valeur de la variable je inférieur à 10, à chaque fois que la boucle est exécutée sur une variable je 1 est ajouté. Vous pouvez également modifier la valeur d'une variable directement dans la boucle.

si (condition)(

corps 1

) autre (

corps 2

Dans une transition conditionnelle, « corps 1 » est exécuté si la condition est vraie et « corps 2 » est exécuté si la condition est fausse. Il y a aussi cette option :

si (condition 1)(

) sinon si (condition 2) (

Dans ce cas, « corps 1 » est exécuté si la « condition 1 » est vraie, « corps 2 » est exécuté si « condition 2 » est vraie. Il peut y avoir un certain nombre de ces conditions, mais il peut aussi y en avoir une autre.

Les conditions peuvent être simples et composées : simples - une expression logique, et composées - plusieurs expressions logiques reliées par le signe & (les conditions sont vraies lorsque toutes les conditions reliées par ce signe sont vraies) ou | (une condition est vraie si au moins une condition reliée par ce signe est vraie).

Une autre chose utile, ce sont les commentaires. Ils vous aideront à retrouver un projet oublié :) ou simplement pour que vous n'oubliiez rien. Vous pouvez commenter soit après les panneaux // et jusqu'à la fin de la ligne ou commencer par les caractères /* et fin */ , dans ce cas, le commentaire peut comporter n'importe quel nombre de lignes. Les commentaires n'affectent pas la taille du programme.

Eh bien, cela semble être une question de base. Assez pour la première fois (jusqu'à la rédaction de la prochaine partie de l'article)

Premier programme

Ne nous écartons pas des traditions (sinon on ne sait jamais) et commençons par Hello World. Et en cours de route, nous continuerons à nous familiariser avec le microcontrôleur et à acquérir de l'expérience, pour ainsi dire.

Ouvrez l'environnement de développement :

Cliquez sur Parcourir dans le référentiel

Choisir ST

Ensuite, nous verrons une liste des bibliothèques connectées.

Pour notre programme simple, nous aurons besoin de : Noyau du CMSIS, Démarrage CMSIS, RCC, GPIO.

Bibliothèques Noyau du CMSIS Et Démarrage CMSIS - ceux du système, ils doivent être connectés

Bibliothèque RCC pour travailler avec un système de chronométrage

Bibliothèque GPIO pour travailler avec les ports E/S

Maintenant à gauche dans la fenêtre Projet ouvrir le fichier principal c.

Nous devons d’abord connecter nos bibliothèques (CMSIS n’a pas besoin d’être connecté).

On va au tout début du programme et on ajoute les lignes :

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

void Délai (int i) (
pour (; je != 0; je--);
}

Donc. Ici dans l'ordre, la fonction ne renvoie rien, donc vide, nom de la fonction Retard, déclarez immédiatement la variable je taper int. Entre accolades, le corps de la fonction est une boucle pour. C'est son entrée de ligne. Valeur initiale je on ne change pas, la boucle continue jusqu'à je n'est pas égal à zéro (comme je devient égal à zéro, le cycle s'arrête, la fonction est « désactivée »). A chaque exécution du corps de la boucle (cycle), la variable je diminue de 1. C'est-à-dire L’essence du cycle est simplement de se répéter un nombre égal de fois je. Pendant que la boucle s'exécute, le temps passe, un retard se produit.

Quel port est responsable de quelle sortie peut être trouvé dans la documentation du MK :

Pour synchroniser le port C, ajoutez la ligne :

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC , ENABLE);

Ajoutez la ligne au programme :

GPIO_InitTypeDef GPIO_Init1 ;

Avec cette ligne nous avons déclaré la structure GPIO_InitTypeDef- je lui ai donné un nom GPIO_Init pour une utilisation ultérieure dans notre programme.

Quels paramètres peuvent être configurés dans cette structure et quelle forme ils ont, nous regardons tout de la même manière stm32f10x_gpio.h:

Maintenant, pour configurer les paramètres de la broche à l'aide de la structure, vous devez écrire son nom, mettre un point et une fenêtre apparaîtra dans laquelle ces paramètres sont indiqués

Double-cliquez sur l'un d'eux, il apparaît dans la ligne, puis mettez = (attribuer) et écrire la valeur de stm32f10x_gpio.h

Nous faisons de même avec tous les paramètres. N'oubliez pas le point-virgule à la fin de chaque ligne !

GPIO_Init(GPIOC, &GPIO_Init);

Maintenant, nous allons cligner des yeux ! Nous clignerons des yeux de manière cyclique, nous ferons une boucle en boucle alors que. La condition du cycle sera 1. Un est toujours vrai, zéro est toujours faux... ça y est c'est la vie..

Pour appliquer du courant à la sortie, vous devez définir le bit ; pour désactiver la sortie, vous devez réinitialiser le bit. Comment faire - tout est pareil stm32f10x_gpio.h:

Nous faisons ceci :

tandis que (1)(

GPIO_SetBits(GPIOC, GPIO_Pin_9);

Retard (200 000);

GPIO_ResetBits(GPIOC, GPIO_Pin_9);

Retard (200 000);

1 est toujours vrai, ce qui signifie que la boucle sera en boucle.

GPIO_SetBits - fonction de réglage des bits

GPIO_ResetBits - fonction de réinitialisation des bits

Délai (200000) - sur cette ligne, l'exécution du programme passe à une fonction Retard, le même dans lequel le cycle pour. Le nombre 200000 entre parenthèses est passé à cette fonction en tant que variable je. (rappelez-vous la ligne Délai nul (int i)?) et la même boucle est exécutée dans cette fonction, toutes les 200 000 fois. C'est rapide :) une fois le cycle terminé pour fonction Drelais termine son travail parce que elle vide, alors il ne renvoie rien et le programme continue de s'exécuter.

Parce que alors que est bouclé, puis LED allumée, retard, LED éteinte, le retard sera effectué dans une boucle sans fin. Jusqu'à ce qu'il y ait une coupure de courant ou une interruption (plus d'informations à ce sujet dans le prochain article).

Eh bien, le premier programme est prêt. Appuyez maintenant sur F7, le programme se compile.

Maintenant, si vous avez une carte de débogage, connectez-la à l'aide d'un cordon USB et appuyez sur Télécharger le code pour flasher. Nous sommes satisfaits du travail effectué et des connaissances acquises :)

Et si vous n'avez pas de carte de débogage, connectez l'adaptateur fabriqué précédemment à votre carte et l'adaptateur au port COM de l'ordinateur. Ensuite, connectez la sortie DÉMARRAGE 0 avec l'alimentation positive du microcontrôleur et allumez le microcontrôleur. Cela fera passer le microcontrôleur en mode micrologiciel. En général, la procédure du firmware n'est pas compliquée. Il vous suffit de suivre les instructions de l'application Démonstrateur du chargeur Flash. Tout d'abord, indiquez le numéro du port COM via lequel votre microcontrôleur est connecté et la vitesse. Pour éviter les pannes, il vaut mieux choisir une vitesse inférieure

Si le programme voit votre microcontrôleur, une fenêtre apparaîtra dans laquelle il sera écrit la quantité de mémoire dont il dispose.

Après avoir cliqué sur « Suivant », vous verrez la page d'adressage de la mémoire. Nous n'en aurons pas besoin.

La prochaine étape est la plus importante. Vous pouvez choisir l'effacement de la mémoire ou le firmware

Pour le firmware, sélectionnez Télécharger sur l'appareil et sur le terrain Télécharger à partir du fichier sélectionnez le fichier .hex compilé, qui se trouve dans le dossier CooCox -> CooIDE -> espace de travail -> nom_projet -> nom_projet -> Debug -> Bin. Cliquez ensuite à nouveau sur « Suivant ».

Après avoir vu cette fenêtre :

Coupez l'alimentation du microcontrôleur et fermez Démonstrateur du chargeur Flash, débranchez l'adaptateur et allumez le microcontrôleur en mode normal (lorsque lorsqu'il est allumé la broche BOOT 0 est connectée à l'alimentation négative du microcontrôleur). Nous nous réjouissons !

Donc, maintenant nous savons pourquoi les microcontrôleurs STM sont meilleurs que les autres, nous savons comment fonctionne le microcontrôleur, nous savons comment flasher le microcontrôleur dans la carte de débogage et dans notre carte, nous connaissons les bases du langage C nécessaires pour programmer le STM32, nous avons acquis de l'expérience en travaillant avec le microcontrôleur (espérons-le positif) et le plus important est que vous puissiez désormais donner vie à vos idées d'appareils numériques (et en parler sur notre bien-aimée RadioKot) ! Ils sont peut-être encore simples, mais tout est inventé par l'expérience. Et dans les articles suivants, j'essaierai de parler des ADC, des DAC, des interruptions, de l'utilisation du débogage et d'autres choses utiles.

Que pensez-vous de cet article?

Toutes les images de cet article sont cliquables.

Les microcontrôleurs contiennent un cœur de microprocesseur ARM, plus précisément ARM Cortex-M. Ce noyau n'est pas seulement inhérent aux microcontrôleurs STM32, il existe en soi et de nombreux microcontrôleurs de différents fabricants sont produits sur sa base.

Ensuite on retrouve ce microcontrôleur dans la liste de gauche et on installe le package DFP correspondant :

Vous remarquerez peut-être que parmi les packages installés, il y a CMSIS. CMSIS est une bibliothèque pour le cœur Cortex-M, commune à tous les microcontrôleurs. La bibliothèque est développée par ARM et est disponible en téléchargement sur le site officiel après inscription. Il serait possible de ne pas installer ce package, mais d'utiliser la version officielle de la bibliothèque, mais ce sont des complications supplémentaires.

Fermez le gestionnaire de paquets et lancez Keil uVision5 (prononcé mu-vision) :

Keil uVision5 fait partie de MDK-ARM, un environnement GUI qui comprend un éditeur de code :

  1. Encodage UTF-8.
  2. La limite de code correcte est de 80 caractères.
  3. Indenter de 4 espaces.

Ces paramètres sont assez controversés. Chaque développeur a ses propres préférences.

Créons maintenant un projet. Pour ce faire, sélectionnez le menu « Projet -> Nouveau projet uVision… ». Dans la fenêtre qui s'ouvre, sélectionnez l'emplacement et le nom du projet. Il est préférable de créer un dossier séparé pour le projet et d'y enregistrer le projet.

Après l'enregistrement, une fenêtre de sélection de périphérique apparaîtra. Sélectionnez le microcontrôleur souhaité et cliquez sur « OK ». Si nous n'avions pas installé le package requis, le microcontrôleur ne serait pas dans la liste :

Dans la fenêtre suivante, vous devez sélectionner les composants qui seront utilisés dans le projet. Vous devez sélectionner « CMSIS : CORE » et « Device : Startup » :

Après avoir cliqué sur « OK », le processus de création du projet sera terminé.

À l'avenir, vous pourrez toujours lancer la fenêtre de sélection des composants pour les ajouter ou les supprimer. Pour ce faire, sélectionnez le menu « Projet -> Gérer -> Environnement d'exécution... ».

Lorsque vous sélectionnez des composants, vous constaterez peut-être qu'un composant dépend d'autres composants que vous n'avez pas sélectionnés. Vous en saurez plus grâce aux messages en bas de la fenêtre. Vous devrez sélectionner les composants dépendants.

Après avoir créé un projet de la manière décrite, dans la fenêtre de droite, vous verrez la structure de projet suivante :

Ici, nous voyons le nom du projet « exemple », l'objectif du projet « Target 1 », le groupe de fichiers vide « Source Group 1 », les composants CMSIS et Device.

Il peut y avoir n’importe quel nombre d’objectifs de projet. L'objectif inclut les paramètres de projet les plus importants, y compris la sélection du microcontrôleur. Des objectifs sont nécessaires pour que vous puissiez élaborer un programme différentes façons pour les mêmes fichiers de code source. Par exemple, vous devrez peut-être que votre projet s'étende sur plusieurs microcontrôleurs.

Des groupes de fichiers sont nécessaires pour regrouper joliment les fichiers de code source. Les groupes vous aident à parcourir facilement les fichiers dans grand projet. Par exemple, vous pouvez avoir un groupe de fichiers responsables des LED et un groupe distinct avec des fichiers permettant d'interagir avec l'USB.

Dans la structure, nous voyons deux fichiers. Un avec une extension "s". Il contient du code source en langage assembleur. L'autre avec l'extension "c". Il contient du code source en langage C.

Vous pouvez créer le projet et obtenir le fichier du firmware en appuyant sur la touche F7. Mais sous cette forme, le projet ne sera pas construit et vous recevrez une erreur car la fonction « main() » est manquante.

La fonction "main()" est le point d'entrée de votre programme, là où le programme commence. Sa présence est obligatoire si vous écrivez un programme en C.

Créons cette fonction. Faites un clic droit sur le groupe « Groupe source 1 » et sélectionnez « Ajouter un nouvel élément au « Groupe source 1 »... » (traduction : ajouter un nouvel élément au « Groupe source 1 »). Créons un fichier "main.c" :

Ajoutez le code au fichier créé :

Int main() (retour 0;)

Vous devez ajouter une ligne vide à la fin du fichier, sinon lors de l'assemblage, vous recevrez un avertissement « avertissement : #1-D : la dernière ligne du fichier se termine sans nouvelle ligne ».

Le projet peut maintenant être assemblé à l'aide de la touche F7. En conséquence, vous obtiendrez le fichier « Objets\exemple.axf » (par défaut, le nom du fichier est le même que le nom du projet). Le fichier se trouve dans le dossier du projet.

En règle générale, le développeur nécessite un fichier de micrologiciel au format Intel HEX. Pour l'obtenir, vous devez configurer l'objectif. Pour voir les paramètres cibles, appuyez sur Alt-F7, allez dans l'onglet "Sortie" et sélectionnez "Créer un fichier HEX".

Après la prochaine build, vous recevrez le fichier « Objects\example.hex ».

Désormais, le programme ne fait plus rien et cela ne sert à rien de le flasher. Écrivons un programme qui contrôle l'état de la broche du microcontrôleur.

Commençons par sélectionner les composants en utilisant le menu « Projet -> Gérer -> Environnement d'exécution... » et sélectionnons le composant « Périphérique : STM32Cube Hal : GPIO ».

Au bas de la fenêtre, nous verrons la dépendance insatisfaite « Device:STM32Cube Hal:Common ». Sélectionnons ce composant et voyons une liste de dépendances encore plus grande. Vous devez sélectionner toutes les dépendances requises :

  • Appareil : STM32Cube Hal : commun
  • Appareil : STM32Cube Hal : RCC
  • Appareil : STM32Cube Hal : PWR
  • Appareil : STM32Cube Hal : Cortex
  • Appareil : STM32Cube Framework : Classique

STM32Cube est une bibliothèque fournie par STMicroelectronics.

Lors du choix des composants, nous choisissons les fonctionnalités de cette bibliothèque à utiliser.

Le microcontrôleur, en plus du noyau, contient un grand nombre de périphériques : ADC, DAC, minuteries, diverses interfaces et bien plus encore. Chaque périphérique possède son propre nom. Par exemple, un périphérique permettant de travailler avec les ports du microcontrôleur s'appelle GPIO, vous pouvez en apprendre davantage à partir de la documentation du microcontrôleur.

La bibliothèque STM32Cube est multi-niveaux, c'est-à-dire qu'elle comprend de nombreuses bibliothèques intermédiaires. L'une des bibliothèques intermédiaires s'appelle STM32Cube HAL, ou simplement HAL. Il est divisé en modules et chaque module correspond à un périphérique. Le nom du module correspond au nom de l'appareil, par exemple, il existe un module GPIO.

Il existe une grande quantité de documentation pour le STM32Cube. Mais la description de base du travail avec les périphériques est contenue dans. Ceci est le guide utilisé par le développeur la plupart temps. Tournons-nous vers lui pour faire bouger les jambes du microcontrôleur.

Tout d’abord, connectons le HAL dans notre programme en ajoutant une ligne avant la définition de la fonction « main() » :

#include "stm32f4xx_hal.h"

Au tout début de la fonction « main() », on appelle la fonction « HAL_Init() », qui initialise la bibliothèque.

De cette façon, nous obtiendrons le code suivant dans le fichier "main.c":

#include "stm32f4xx_hal.h" int main() ( HAL_Init(); return 0; )

À suivre…

À ce stade, je suis obligé d'interrompre mon article, car ce moment Je n'ai rien sur lequel déboguer le programme, c'est-à-dire que je n'ai pas de carte de débogage sous la main.

J'ai écrit un programme qui est assemblé et qui devrait théoriquement fonctionner, mais je ne veux pas induire le lecteur en erreur. Je considère que le matériel ci-dessus est utile sans aucun résultat final.

#include "stm32f4xx_hal.h" int main() ( HAL_Init(); // Activer la synchronisation du port A. __HAL_RCC_GPIOA_CLK_ENABLE(); // Paramètres du port. GPIO_InitTypeDef s; s.Pin = GPIO_PIN_0; // Sortie 0. s.Mode = GPIO_MODE_OUTPUT_PP; // Sortie numérique. s.Pull = GPIO_NOPULL; // Pas de pullup. s.Speed ​​​​= GPIO_SPEED_FREQ_VERY_HIGH; // Vitesse maximale. // Configurer la broche 0 du port A. HAL_GPIO_Init(GPIOA, &s); // Basculez à l'infini l'état du port avec la vitesse maximale. while(1) ( HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_0); ) //return 0; ) void SysTick_Handler(void) ( HAL_IncTick(); )

Liens

  1. Capture d'écran " Outils Eclipse et GNU pour le développement de microcontrôleurs ARM «.
  2. Microcontrôleur STM32F407VG.
  3. Carte de développement STM32F4-Discovery.
  4. Bibliothèque STM32CubeF4.

DANS dernières années Les microcontrôleurs (MCU) 32 bits basés sur des processeurs ARM conquièrent rapidement le monde de l'électronique. Cette avancée est due à leurs hautes performances, leur architecture avancée, leur faible consommation d'énergie, leur faible coût et leurs outils de programmation avancés.

HISTOIRE COURTE
Le nom ARM est un acronyme pour Advanced RISC Machines, où RISC (Reduced Instruction Set Computer) signifie architecture de processeur à jeu d'instructions réduit. La très grande majorité des microcontrôleurs populaires, tels que les familles PIC et AVR, disposent également d'une architecture RISC, qui a augmenté les performances en simplifiant le décodage des instructions et en accélérant leur exécution. L'émergence de microcontrôleurs ARM 32 bits avancés et productifs nous permet de passer à la résolution de problèmes plus complexes que les MCU 8 et 16 bits ne peuvent plus résoudre. L'architecture du microprocesseur ARM avec un cœur de 32 bits et un jeu d'instructions RISC a été développée par la société britannique ARM Ltd, qui développe exclusivement des noyaux, des compilateurs et des outils de débogage. L'entreprise ne produit pas de MK, mais vend des licences pour leur production. MK ARM est l’un des segments du marché MK à la croissance la plus rapide. Ces appareils utilisent des technologies d'économie d'énergie, ils sont donc large application dans les systèmes embarqués et dominer le marché des appareils mobiles où une faible consommation d'énergie est importante. De plus, les microcontrôleurs ARM sont activement utilisés dans les appareils de communication, portables et intégrés où des performances élevées sont requises. Une caractéristique de l'architecture ARM est le cœur de calcul du processeur, qui n'est équipé d'aucun élément supplémentaire. Chaque développeur de processeur doit équiper indépendamment ce cœur des blocs nécessaires à ses tâches spécifiques. Cette approche a bien fonctionné pour les grands fabricants de puces, même si elle était initialement axée sur les solutions de processeurs classiques. Les processeurs ARM ont déjà traversé plusieurs étapes de développement et sont bien connus pour les familles ARM7, ARM9, ARM11 et Cortex. Ce dernier est divisé en sous-familles de processeurs CortexA classiques, de processeurs temps réel CortexR et de cœurs de microprocesseur CortexM. Ce sont les cœurs CortexM qui sont devenus la base du développement d'une large classe de MCU 32 bits. Ils diffèrent des autres variantes de l'architecture Cortex principalement par l'utilisation du jeu d'instructions Thumb2 16 bits. Cet ensemble combine les performances et la compacité des instructions ARM et Thumb « classiques » et a été développé spécifiquement pour travailler avec les langages C et C++, ce qui améliore considérablement la qualité du code. Le grand avantage des microcontrôleurs construits sur le cœur CortexM est leur compatibilité logicielle, qui permet théoriquement d'utiliser du code de programme dans le langage haut niveau dans des modèles de différents fabricants. En plus d'indiquer le domaine d'application du noyau, les développeurs MK indiquent les performances du noyau CortexM sur une échelle de dix points. Aujourd'hui, les options les plus populaires sont CortexM3 et CortexM4. Les MCU avec architecture ARM sont produits par des sociétés telles que Analog Devices, Atmel, Xilinx, Altera, Cirrus Logic, Intel, Marvell, NXP, STMicroelectronics, Samsung, LG, MediaTek, MStar, Qualcomm, SonyEricsson, Texas Instruments, nVidia, Freescale, Milander. , HiSilicon et autres.
Grâce à l'architecture optimisée, le coût des MCU basés sur le cœur CortexM est dans certains cas même inférieur à celui de nombreux appareils 8 bits. Les modèles « plus jeunes » peuvent actuellement être achetés pour 30 roubles. pour la carrosserie, ce qui crée une concurrence pour les générations précédentes de MK. MICROCONTRÔLEURS STM32 Considérons le MCU le plus abordable et le plus répandu de la famille STM32F100 de STMicroelectronics, l'un des principaux fabricants mondiaux de MCU. La société a récemment annoncé le début de la production d'un MK 32 bits tirant parti des technologies industrielles.
Cœurs STM32 dans des applications à faible coût. Les MCU de la famille STM32F100 Value line sont conçus pour les appareils où les performances des MCU 16 bits ne sont pas suffisantes et où les riches fonctionnalités des appareils 32 bits « classiques » sont redondantes. La gamme de MCU STM32F100 est basée sur un cœur ARM CortexM3 moderne avec des périphériques optimisés pour une utilisation dans des applications typiques où des MCU 16 bits ont été utilisés. Les performances du MCU STM32F100 à 24 MHz sont supérieures à celles de la plupart des MCU 16 bits. Cette ligne comprend des appareils avec différents paramètres :
● de 16 à 128 Ko de mémoire flash programme ;
● de 4 à 8 Ko de RAM ;
● jusqu'à 80 ports d'entrée/sortie GPIO ;
● jusqu'à neuf timers 16 bits avec fonctions avancées ;
● deux minuteries de surveillance ;
● CAN 12 bits haute vitesse 16 canaux ;
● deux DAC 12 bits avec générateurs de signaux intégrés ;
● jusqu'à trois interfaces UART prenant en charge les modes IrDA, LIN et ISO7816 ;
● jusqu'à deux interfaces SPI ;
● jusqu'à deux interfaces I2C prenant en charge les modes SMBus et PMBus ;
● Accès direct à la mémoire (DMA) à 7 canaux ;
● Interface CEC (Consumer Electronics Control) incluse dans la norme HDMI ;
● horloge en temps réel (RTC) ;
● Contrôleur d'interruption imbriqué NVIC.

Le schéma fonctionnel du STM32F100 est présenté à la figure 1.

Riz. 1. Architecture de la ligne MK STM32F100

Une commodité supplémentaire est la compatibilité des broches des appareils, qui permet, si nécessaire, d'utiliser n'importe quel MK de la famille avec plus de fonctionnalités et de mémoire sans retravailler le circuit imprimé. La gamme de contrôleurs STM32F100 est produite en trois types de boîtiers LQFP48, LQFP64 et LQFP100, comportant respectivement 48, 64 et 100 broches. L'affectation des broches est présentée sur les figures 2, 3 et 4. De tels boîtiers peuvent être installés sur des cartes de circuits imprimés sans utiliser d'équipement spécial, ce qui constitue un facteur important dans la production à petite échelle.


Riz. 2. MCU STM32 dans le boîtier LQFP48 Fig. 3. MCU STM32 dans le package LQFP64


Riz. 4. MCU STM32 dans le boîtier LQFP100

STM32F100 est un dispositif abordable et optimisé basé sur le cœur CortexM3, pris en charge par un environnement de développement avancé pour la famille de microcontrôleurs STM32, qui contient
Bibliothèques gratuites pour tous les périphériques, y compris la commande moteur et les claviers tactiles.

SCHÉMA DE CONNEXION STM32F100C4
Considérons l'utilisation pratique de MK en utilisant l'exemple du périphérique STM32F100C4 le plus simple, qui contient néanmoins tous les blocs principaux de la gamme STM32F100. Fondamental schéma électrique L'inclusion de STM32F100C4 est illustrée à la figure 5.


Riz. 5. Schéma de connexion pour MK STM32F100C4

Le condensateur C1 garantit la réinitialisation du MK à la mise sous tension et les condensateurs C2-C6 filtrent la tension d'alimentation. Les résistances R1 et R2 limitent le courant de signal des broches MK. L'oscillateur interne est utilisé comme source d'horloge, il n'est donc pas nécessaire d'utiliser un cristal externe.


Les entrées BOOT0 et BOOT1 vous permettent de sélectionner la méthode de chargement du MK lors de la mise sous tension conformément au tableau. L'entrée BOOT0 est connectée au bus à potentiel zéro via la résistance R2, qui protège la broche BOOT0 d'un court-circuit lorsqu'elle est utilisée comme port de sortie de PB2. À l'aide du connecteur J1 et d'un cavalier, vous pouvez modifier le potentiel à l'entrée BOOT0, déterminant ainsi comment le MK est chargé - à partir de la mémoire flash ou du chargeur de démarrage intégré. Si vous devez charger le MK depuis la RAM, un connecteur similaire avec un cavalier peut être connecté à l'entrée BOOT1.
La programmation du MK s'effectue via le port série UART1 ou via des programmeurs spéciaux - débogueurs JTAG ou STLink. Ce dernier fait partie du dispositif de débogage populaire STM32VLDISCOVERY, illustré à la figure 6. Sur la carte STM32VLDIS COVERY, le connecteur à 4 broches du programmeur - débogueur STLink - est désigné SWD. L'auteur de l'article suggère de programmer le MK via le port série UART1, car il est beaucoup plus simple, ne nécessite pas d'équipement spécial et n'est pas inférieur en vitesse à JTAG ou ST Link. Tout ordinateur personnel (PC) doté d'un port COM série ou d'un port USB avec un convertisseur USBRS232 peut être utilisé comme dispositif de contrôle capable de générer des commandes et d'afficher les résultats du programme MK, ainsi que comme programmeur.

Pour interfacer le port COM d'un PC avec un MK, tout convertisseur de signaux RS232 en niveaux de signaux logiques de 0 à 3,3 V, par exemple le microcircuit ADM3232, convient. Ligne de transmission TXD port série L'ordinateur, après le convertisseur de niveau, doit être connecté à l'entrée PA10 du microcontrôleur, et la ligne du récepteur RXD, via un convertisseur similaire, à la sortie PA9.

Si vous devez utiliser une horloge MK non volatile, vous devez y connecter une pile CR2032 avec une tension de 3 V et un résonateur à quartz avec une fréquence de 32768 Hz. À cet effet, le MK est équipé de broches Vbat/GND et OSC32_IN/OSC32_OUT. La broche Vbat doit d'abord être déconnectée du bus d'alimentation 3,3 V.

Les terminaux libres restants du MK peuvent être utilisés selon les besoins. Pour ce faire, ils doivent être connectés aux connecteurs situés autour du périmètre de la carte de circuit imprimé du MK, par analogie avec les appareils Arduino populaires et la carte de débogage STM32VLDISCOVERY.


Riz. 6. Dispositif de débogage STM32VLDISCOVERY


Schéma du circuit électrique STM32VLDISCOVERY.

Ainsi, selon le but et le mode d'utilisation du MK, vous pouvez vous y connecter éléments nécessaires pour activer d'autres blocs fonctionnels et ports, tels que ADC, DAC, SPI, I2C, etc. À l’avenir, ces appareils seront examinés plus en détail.

LA PROGRAMMATION
Aujourd'hui, de nombreuses entreprises proposent des outils pour créer et déboguer des programmes pour les microcontrôleurs STM32. Il s'agit notamment de Keil d'ARM Ltd, IAR Embedded Workbench pour ARM, Atol lic TrueStudio, CooCox IDE, GCC et Eclipse IDE. Le développeur peut choisir le logiciel selon ses préférences. Ci-dessous, nous décrirons la boîte à outils Keil uVision 4 de la société Keil, qui prend en charge un grand nombre de types de microcontrôleurs, dispose d'un système développé d'outils de débogage et peut être utilisée gratuitement avec des restrictions sur la taille du code généré de 32 Ko ( ce qui, en fait, est le maximum pour les microcontrôleurs considérés).

Démarrage facile et rapide avec CooCox CoIDE.

Alors, commençons. Accédez au site officiel de CooCox et téléchargez dernière version CooCox CoIDE. Pour télécharger, vous devez vous inscrire, l'inscription est simple et gratuite. Installez ensuite le fichier téléchargé et exécutez-le.

CooCoxCoIDE— un environnement de développement basé sur Eclipse, qui en plus de STM32 supporte un tas d'autres familles de microcontrôleurs : Freescale, Holtek, NXP, Nuvoton, TI, Atmel SAM, Energy Micro, etc. Avec chacun nouvelle version La liste CoIDE des MK est constamment mise à jour. Après avoir installé CoIDE avec succès, exécutez :

La fenêtre de démarrage de l'étape 1 apparaîtra, dans laquelle vous devrez sélectionner le fabricant de notre microcontrôleur. Appuyez sur ST et passez à l'étape 2 (sélection d'un microcontrôleur), dans laquelle vous devez sélectionner un modèle spécifique. Nous avons le STM32F100RBT6B, alors cliquez sur le modèle correspondant :

Sur la droite, la fenêtre d'aide affiche de brèves caractéristiques de chaque puce. Après avoir sélectionné le microcontrôleur dont nous avons besoin, nous passons à la troisième étape, l'étape 3 - pour sélectionner les bibliothèques nécessaires au travail :

Créons un projet simple pour faire clignoter une LED, comme il est d'usage pour l'apprentissage des microcontrôleurs.

Pour ce faire, nous avons besoin de la bibliothèque GPIO, lorsqu'elle est activée, CoIDE vous demandera de créer un nouveau projet. Cliquez sur Oui sur cette proposition, indiquez le dossier où sera stocké notre projet et son nom. Parallèlement, CoIDE connectera au projet 3 autres nécessaires au fonctionnement de la bibliothèque, et créera également toute la structure nécessaire du projet :

Un autre avantage de CoIDE est qu'il a la capacité de charger des exemples directement dans l'environnement de développement. Dans l'onglet Composants, vous pouvez voir qu'il existe des exemples pour presque toutes les bibliothèques, cliquez sur GPIO (avec 4 exemples) et voyez-les :

Vous pouvez y ajouter vos propres exemples. Comme vous pouvez le voir dans la capture d'écran ci-dessus, les exemples contiennent déjà du code pour faire clignoter la LED GPIO_Blink. Vous pouvez cliquer sur le bouton Ajouter et il sera ajouté au projet, mais en tant que fichier inclus, nous allons donc le faire différemment et copier simplement l'intégralité de l'exemple de code dans le fichier main.c. La seule chose est de remplacer la ligne void GPIO_Blink(void) par int main(void). Alors, appuyez sur F7 (ou sélectionnez Projet->Construire dans le menu) pour compiler le projet et... pas de chance !

L'environnement a besoin d'un compilateur GCC, mais nous n'en avons pas. Par conséquent, accédez à la page Outils GNU pour processeurs intégrés ARM, sélectionnez votre type de système d'exploitation sur la droite et téléchargez la dernière version de la chaîne d'outils. Ensuite, nous exécutons le fichier et installons la chaîne d'outils gcc. Ensuite, dans les paramètres CoIDE, nous indiquerons le chemin correct vers la chaîne d'outils :

Appuyez à nouveau sur F7 (Projet->Build) et vérifiez que la compilation a réussi :

Il ne reste plus qu'à flasher le microcontrôleur. Pour ce faire, nous connectons notre carte à l'ordinateur via USB. Ensuite, dans les paramètres du débogueur, vous devez installer ST-Link ; pour ce faire, sélectionnez Projet->Configuration dans le menu et ouvrez l'onglet Débogueur. Sélectionnez ST-Link dans la liste déroulante et fermez la fenêtre :

Essayons de flasher le MK. Dans le menu, sélectionnez Flash->Téléchargement du programme (ou cliquez sur l'icône correspondante dans la barre d'outils) et vérifiez que le MK a été flashé avec succès :

Nous voyons une LED clignotante sur le tableau, je pense que cela n'a aucun sens de fournir une vidéo ou une photo, car... tout le monde l'a vu.

De plus, différents modes de débogage fonctionnent dans CoIDE ; pour ce faire, appuyez sur CTRL+F5 (ou dans le menu Debug->Debug) :

C'est tout. Comme vous pouvez le constater, la configuration et l'utilisation de CoIDE sont très simples. J'espère que cet article vous encouragera à étudier les microcontrôleurs STM32 très prometteurs et peu coûteux.

Je souhaite la bienvenue à tous les amateurs de programmation, de microcontrôleurs et d'électronique en général sur notre site ! Dans cet article, je vais vous parler un peu de ce que nous allons faire ici, à savoir la formation sur les microcontrôleurs ARM.

Alors, commençons par déterminer ce que vous devez savoir et être capable de faire pour commencer à apprendre les ARM. Mais, en principe, rien de super compliqué et enchanteur 😉 Bien sûr, les gens passent généralement aux contrôleurs ARM après avoir déjà suffisamment joué avec les PIC et les AVR, c'est-à-dire que la plupart d'entre eux sont des développeurs expérimentés. Mais je vais essayer de décrire de manière aussi détaillée et claire que possible tout ce que nous analyserons, afin que ceux qui ont décidé de s'essayer à la programmation de microcontrôleurs pour la première fois puissent facilement comprendre le matériel. À propos, si vous avez des questions ou si quelque chose ne fonctionne tout simplement pas comme prévu, écrivez dans les commentaires, j'essaierai de comprendre et de vous aider.

Passons maintenant aux problèmes techniques) Plusieurs fois j'ai déjà évoqué le nom « Formation ARM", mais, dans l'ensemble, ce n'est pas tout à fait vrai. Il n’existe pas de microcontrôleur ARM. Il existe un contrôleur avec un noyau ARM (!), mais cela, voyez-vous, n'est toujours pas la même chose. Ainsi, de tels dispositifs sont produits par un certain nombre de sociétés, parmi lesquelles se distinguent STMicroelectronics et NXP Semiconductors. En conséquence, ils produisent des contrôleurs STM et LPC. J'ai opté pour le STM32, je les préférais juste =) C'est très captivant avec STM qu'une fois que vous aurez traité n'importe quel MK de la gamme STM32F10x, vous n'aurez aucun problème avec les autres. Une ligne – une fiche technique. D'ailleurs il y a grande quantité des cartes de développement à la fois chères et moins chères avec des contrôleurs STM32, ce qui est très agréable, même si au début nous déboguerons nos programmes dans un simulateur pour évaluer les capacités du contrôleur avant d'acheter du matériel. Voici, juste au cas où, le site officiel de STMicroelectronics -.

D'une manière ou d'une autre, nous sommes passés en douceur au sujet du compilateur, je vais donc en dire quelques mots. Sans y réfléchir à deux fois, j'ai choisi Keil, notamment en raison du puissant simulateur intégré. Vous pouvez y consulter l'UART et n'importe quel registre, et même un analyseur logique est disponible. En un mot, Keil ne m'a laissé pour la plupart que des impressions agréables, même s'il y a bien sûr quelques inconvénients, mais pas catastrophiques. Vous pouvez donc télécharger Keil uvision4 en toute sécurité. site(). Certes, il y en a un MAIS - l'IDE est payant, mais un mode démo est disponible avec une limite de code de 32 Ko, ce qui nous suffit largement pour l'instant. Pour qui cela ne suffit pas, il y a un grand nombre de fissures pour Keil 😉 Tout est installé sans problème - nous poussons plus loin plusieurs fois et tout s'installe parfaitement et fonctionne sans danses supplémentaires avec un tambourin.

En fait, c’est tout ce que je voulais vous dire ici, il est temps de passer des paroles aux actes, mais c’est dans le prochain article. Nous allons apprendre à programmer les microcontrôleurs STM32 à partir de zéro !

Cet article est le premier d'une série d'articles prévus sur l'étude de la programmation des microcontrôleurs. Étudier divers matériaux J'ai remarqué que presque tous commencent par le fait qu'il est demandé au débutant de télécharger (ou d'utiliser celle fournie avec l'environnement de développement) une bibliothèque pour travailler avec des périphériques et de l'utiliser pour écrire son premier programme (généralement une LED clignotante ).

Cela m'a beaucoup surpris. Si vous en croyez ces articles, vous n’avez même pas besoin de lire la documentation de l’automate programmable pour programmer. On m'a enseigné la sagesse "programmation matérielle" complètement différent.

Dans cet article, le chemin de la phrase « Oui, je veux essayer ! » jusqu'à ce que le clin d'œil joyeux de la LED soit bien plus long que celui des autres auteurs. Je vais essayer de révéler les aspects de la programmation des microcontrôleurs qui se cachent derrière l'utilisation de fonctions de bibliothèque et d'exemples prêts à l'emploi.
Si vous avez l'intention d'étudier sérieusement la programmation des microcontrôleurs, cet article est fait pour vous. Peut-être que cela pourrait également intéresser ceux qui ont suffisamment joué avec Arduino et souhaitent mettre la main sur toutes les capacités matérielles du matériel.

Sélection d'un microcontrôleur

Beaucoup diront peut-être qu'il est préférable de commencer à apprendre les microcontrôleurs avec AVR, PIC, 8051 ou autre chose. La question est multiple et controversée. Je connais suffisamment d'exemples où des gens, ayant étudié Cortex-M, ont programmé AVR, ARM7, etc. J'ai moi-même commencé avec Cortex-M3. Si vous êtes confronté à une tâche spécifique, il existe de nombreuses informations sur Internet avec des comparaisons divers types microcontrôleurs et tâches résolues avec leur aide. Cette question s’est également posée à propos de Habré, par exemple.

Nous supposerons que nous avons déterminé le type de microcontrôleur. Mais le marché propose une vaste gamme de modifications différentes provenant de différents fabricants. Ils diffèrent par de nombreux paramètres - de la taille de la mémoire flash au nombre d'entrées analogiques. Pour chaque tâche, le choix doit être fait individuellement. Il n’y a pas et ne peut pas y avoir de recommandations générales ici. Je noterai seulement qu'il vaut la peine de commencer votre étude auprès des fabricants de MK qui disposent de la gamme la plus large possible. Ensuite, lorsque vous choisissez un MK pour une tâche spécifique, il y a de fortes chances que quelque chose de la gamme présentée vous convienne.

J'ai choisi STM32(même si je pense qu'il vaut mieux commencer à étudier avec MK de TexasInstruments - la documentation est très bien compilée), car ils sont répandus parmi les développeurs d'électronique russes. Si vous avez des problèmes ou des questions, vous pouvez facilement trouver des solutions sur les forums. Un autre avantage est le large choix de cartes de démonstration provenant à la fois du fabricant et d'organisations tierces.

Que devez-vous étudier ?

Malheureusement, pour commencer à programmer un MK, un simple PC ne suffit pas. Vous devrez vous procurer une carte de démonstration et un programmeur quelque part. Bien que cela réduise la concurrence sur le marché du travail.

J'utilise moi-même une carte de démonstration. STM3220G-EVAL et programmeur J-Link PRO. Mais pour commencer, ce sera largement suffisant DÉCOUVERTE STM32F4, qui peut être acheté sans problème pour une petite somme.

Tous les exemples seront spécifiquement destinés à la carte de débogage DÉCOUVERTE STM32F4. À ce stade, il ne sera pas du tout important pour nous que cette carte dispose d'un MCU basé sur le cœur Cortex-M4. Nous n'utiliserons pas ses fonctionnalités et avantages par rapport au Cortex-M3 dans un avenir proche. Nous verrons ce qui se passera ensuite.

Si vous possédez une autre carte basée sur STM32F2xx/STM32F4xx, vous pouvez travailler avec elle. En présentant le matériel, j'essaierai de le décrire de manière aussi détaillée que possible. Pourquoi nous le faisons de cette façon et pas autrement. J'espère que personne n'aura de problèmes pour transférer des exemples vers d'autres matériels.

Environnement de développement

Comme cela a déjà été mentionné à plusieurs reprises, il existe un nombre suffisant d'environnements de développement pour les microcontrôleurs ARM, payants ou moins. Et encore une fois, je voudrais omettre la controverse à ce sujet. J'utilise IAR Embedded Workbench pour ARM 6.60. Tous les exemples seront dans cet environnement. Si vous aimez (ou si votre organisation utilise) autre chose (Keil, Eclipse, CCS, CooCoc, etc.), cela ne vous fera pas de mal non plus. J'accorderai une attention particulière aux fonctionnalités liées spécifiquement à l'environnement de développement.

Pourquoi un environnement de développement payant ?

Peut-être que quelqu'un ne sera pas entièrement satisfait du fait que je suggère d'utiliser un environnement de développement payant, mais dans IAR, il est possible d'obtenir une licence temporaire sans restrictions de fonctionnalités, ou une licence illimitée avec une limite de taille de code (32 Ko pour MK, c'est beaucoup ).
De plus, je noterai tout de suite que pour certains MK il n'existe pas d'environnements de développement gratuits. Et malheureusement, ces députés sont irremplaçables dans certains domaines.


Je ne décrirai pas le processus d'installation.

Où commencer?

Créer un projet
Tout d’abord, créons un projet vide. IAR vous permet de créer des projets en ASM, C et C++. Nous utiliserons C.

Un projet vide avec un fichier principal apparaîtra devant nous.

Vous devez maintenant configurer le projet pour commencer à travailler avec « notre » MK et notre débogueur. MK installé sur la carte STM32F4DISCOVERY STM32F407VG. Il doit être sélectionné dans les propriétés du projet (Options générales->Cible->Périphérique) :

Lorsque vous sélectionnez un processeur programmable cible, sa description est chargée, ce qui offre de nombreuses possibilités de débogage (ceci sera discuté ci-dessous). De plus, un fichier de configuration décrivant l'espace d'adressage disponible pour l'éditeur de liens est automatiquement joint. Si nécessaire, nous aborderons le sujet du fichier de configuration de l’éditeur de liens dans les prochains articles.

Après cela, vous devez configurer le débogueur. Le débogage du programme s'effectue directement « dans le matériel ». Cela se fait à l'aide d'un débogueur JTAG. Vous pouvez en savoir plus sur la façon dont cela se produit sur Wikipédia. Le débogueur ST-LINK/V2 est intégré sur la carte STM32F4DISCOVERY. Pour travailler avec le débogueur, vous devez sélectionner son pilote dans le menu Débogueur->Configuration->Pilote. Il faut également indiquer que le débogage doit être effectué directement dans le matériel. Pour ce faire, vous devez définir le drapeau Débogueur->Télécharger->Utiliser le(s) chargeur(s) Flash


Pour ceux qui ont vu le mot Simulator

En théorie, IAR permet de déboguer des programmes à l'aide d'un simulateur. Mais je ne l'ai jamais vu utilisé en pratique.

Le projet est maintenant prêt à fonctionner (programmation, remplissage et débogage).

"TZ" pour le premier projet
Résumons : Le MK et la carte de débogage ont été sélectionnés, le projet a été préparé. Il est temps de décider de la tâche.

Ne nous écartons pas des classiques. Le premier projet sera une LED clignotante. Heureusement, il y en a beaucoup sur le tableau, qu'est-ce que cela signifie d'un point de vue programmation ? La première chose à faire est d'étudier le schéma de circuit de la carte de démonstration et de comprendre comment la LED « démarre ».
disponible sur le site du fabricant. DANS cette description il y a même une section séparée sur les LED sur la carte - 4.4 LED. Par exemple, nous utiliserons Utilisateur LD3. Trouvons-le dans le schéma :

L'analyse la plus simple du circuit suggère que pour « allumer » la LED, il faut appliquer « 1 » sur la broche MK (qui pour ce MK correspond à 3,3V). L'extinction se fait en appliquant « 0 » sur cette broche. Dans le schéma, cette broche est désignée PD13(c'est probablement l'information la plus importante de ce document).

En conséquence, nous pouvons écrire « TK » pour notre premier programme :
Le programme pour le MK doit transférer l'état de la broche MK PD13 de l'état « 0 » à l'état « 1 » et inversement avec une certaine périodicité perceptible à l'œil humain (une remarque importante, si la LED clignote trop souvent, l'œil humain ne sera peut-être pas en mesure de le distinguer).

Avant de commencer la programmation, ou un peu de théorie
Avant de commencer à mettre en œuvre nos spécifications techniques, il est nécessaire de comprendre comment MK est géré.

Commençons par le fait que tout MK comprend un cœur, une mémoire et des unités périphériques. Je pense qu'avec la mémoire, tout est clair pour l'instant. Permettez-moi juste de mentionner que le STM32 dispose d'une mémoire flash dans laquelle le programme MK est stocké (en général, ce n'est pas une affirmation vraie, le programme peut être stocké dans une mémoire externe non volatile, mais nous l'ignorerons pour l'instant) et d'autres données, y compris les données des utilisateurs. Il existe également SRAM - mémoire vive.

Le cœur est la partie du microcontrôleur qui exécute un flux de commandes. Dans notre MK, le type de noyau est Cortex-M4. Le cœur MK peut être comparé au processeur d’un PC. Il ne peut qu'exécuter des commandes et transférer des données vers d'autres unités (les processeurs avec accélérateurs graphiques intégrés ne sont pas pris en compte dans cette comparaison).
Dans le même temps, le constructeur MK ne développe pas le noyau. Le noyau est acheté auprès d'ARM Limited. La principale différence entre les différents députés réside dans la périphérie.

Les blocs périphériques sont des blocs qui interagissent avec le « monde extérieur » ou remplissent des fonctions spécifiques inaccessibles au noyau MK. Les MCU modernes (y compris STM32) contiennent une vaste gamme d'unités périphériques. Les blocs périphériques sont conçus pour résoudre divers problèmes, de la lecture de la valeur de tension de l'entrée analogique du MK à la transmission de données à des appareils externes via le bus SPI.
Contrairement au noyau MK, les unités périphériques n'exécutent pas d'instructions. Ils exécutent uniquement les commandes du noyau. Dans ce cas, la participation du noyau lors de l'exécution de la commande n'est pas requise.

Exemple

Un exemple est le bloc UART, conçu pour recevoir et transmettre des données du MK vers des appareils externes. Le noyau n'a qu'à configurer le bloc et à lui fournir les données à transmettre. Après cela, le noyau peut continuer à exécuter les instructions. L'unité périphérique est chargée de contrôler la sortie MK correspondante pour la transmission des données conformément au protocole. L'unité périphérique transfère elle-même la sortie MK à l'état requis « 0 » ou « 1 » au bon moment, effectuant la transmission.

Interaction du noyau avec l'unité périphérique
L'interaction du noyau MK avec l'unité périphérique s'effectue à l'aide de registres spéciaux (il existe également une interaction via le mécanisme d'interruption et le DMA, mais nous en parlerons davantage dans les articles suivants). Du point de vue du noyau, il s'agit simplement d'un morceau de mémoire avec une adresse spécifique, ce n'est tout simplement pas vrai. L'écriture de données dans un registre spécial équivaut à transmettre une commande ou des données à une unité périphérique. Lecture - recevoir des données d'un bloc ou lire son état. La description des blocs périphériques et de leurs registres spéciaux occupe la part du lion de la description MK.

IMPORTANT: Après avoir écrit des données dans un registre spécial puis les avoir lues, vous pouvez obtenir des données complètement différentes. Par exemple, l'envoi de données à un bloc UART à envoyer et la lecture des données reçues par le bloc depuis un périphérique externe sont effectués à l'aide du même registre.

Les registres spéciaux sont généralement divisés en champs de bits. Un (ou plusieurs) bits contrôlent un paramètre spécifique du bloc périphérique, généralement indépendamment. Par exemple, différents bits d'un registre contrôlent l'état des différentes sorties MK.

Rappelez-vous C
Si vous êtes un gourou du langage C, vous pouvez ignorer cette section en toute sécurité. Il s'adresse principalement à ceux qui ont appris (ou ont appris eux-mêmes) à programmer pour un PC. L'expérience montre que les gens ne se souviennent souvent pas des commandes importantes. Ici, je vais vous rappeler brièvement les opérations au niveau du bit et le travail directement avec la mémoire à son adresse.

Écrire des données sur une adresse mémoire

Supposons qu'en lisant la description du bloc périphérique, nous nous soyons rendu compte que pour qu'il fonctionne correctement, il faut y inscrire le nombre 0x3B. L'adresse du registre spécial est 0x60004012. Le registre est de 32 bits.
Si vous ne savez pas immédiatement comment procéder, je vais essayer de décrire la chaîne de raisonnement pour obtenir la bonne commande.

La valeur 0x60004012 n'est rien de plus que la valeur d'un pointeur vers un emplacement mémoire. C'est exactement ce que nous devons indiquer dans notre programme, c'est-à-dire faire une conversion de type selon la syntaxe du langage C :

(long non signé*)(0x60004012)

Nous avons donc un pointeur vers un élément. Vous devez maintenant écrire la valeur requise dans cet élément. Cela se fait en déréférençant le pointeur. On obtient donc la bonne commande :

*(long non signé*)(0x60004012) = 0x3B;

Définir des bits arbitraires sur 1

Supposons que vous souhaitiez définir les bits 7 et 1 de l'adresse 0x60004012 sur « 1 » sans modifier la valeur de tous les autres bits du registre. Pour ce faire, vous devez utiliser l'opération binaire |. Je vais vous donner la bonne réponse tout de suite :

*(long non signé*)(0x60004012) |= 0x82;

Faites attention à 2 faits. Les bits sont comptés à partir de zéro et non à partir du premier. Cette opération en fait, cela prend au moins 3 cycles d'horloge - lire la valeur, la modifier, l'écrire. Parfois, cela n'est pas acceptable car entre la lecture et l'écriture, la valeur d'un des bits que nous ne sommes pas autorisés à modifier peut avoir été modifiée par l'unité périphérique. N'oubliez pas cette fonctionnalité, sinon des bugs extrêmement difficiles à détecter pourraient apparaître.

Mettre des bits arbitraires à 0

Supposons que nous souhaitions définir les bits 7 et 1 de l'adresse 0x60004012 sur "0" sans modifier la valeur de tous les autres bits du registre. Pour ce faire, vous devez utiliser l'opérateur binaire &. Je vais vous donner la bonne réponse tout de suite :

*(long non signé*)(0x60004012) &= 0xFFFFFF7D;

Ou sa notation plus simple (ne vous inquiétez pas de l'opération supplémentaire, le compilateur calculera tout à l'avance même avec une optimisation minimale) :

*(long non signé*)(0x60004012) &= (~0x82);

Quelques fonctionnalités des programmes pour MK
Ici, je vais essayer de décrire certaines fonctionnalités des programmes pour MK qu'il est important de retenir. Les choses sont assez évidentes, mais quand même.
Le programme n'a pas de fin
Contrairement à la plupart des programmes PC, le programme MK ne devrait jamais se terminer, JAMAIS ! Que devra faire exactement MK après avoir terminé votre programme ? La question est pratiquement rhétorique. N’oubliez donc pas de vous assurer que vous n’avez pas oublié le cycle éternel. Si vous le souhaitez, vous pouvez mettre le MK en mode veille.
Utiliser des variables entières
Malgré le fait que nous utilisons un microcontrôleur avec un cœur Cortex-M4, qui effectue des opérations sur les nombres à virgule flottante dans le matériel, je vous déconseille de les utiliser. Dans un microcontrôleur sans prise en charge de telles opérations, le temps de calcul sera tout simplement énorme.
Évitez l’allocation dynamique de mémoire
Ceci n'est qu'un conseil. La raison est simple : il n'y a pas assez de mémoire. J'ai souvent rencontré des bibliothèques qui présentaient des fuites de mémoire « lentes ». C'était très désagréable quand, après plusieurs semaines de fonctionnement stable, le MK tombait en panne avec une erreur. Il est préférable de réfléchir à l'avance à l'architecture de votre programme afin de ne pas avoir à recourir à l'allocation dynamique de mémoire.
Si vous souhaitez toujours l'utiliser, étudiez attentivement le travail du gestionnaire de mémoire ou écrivez le vôtre.

Mettons-nous au travail!

Travailler sur un programme pour MK commence toujours par la lecture de la documentation. Pour notre MK, il est disponible sur le site du fabricant. Il y a beaucoup de pages, mais lisez-les toutes Au revoir pas besoin. Comme déjà mentionné, la majeure partie de la documentation consiste en une description des unités périphériques et de leurs registres. Je tiens également à attirer votre attention sur le fait que ce manuel de référence n'a pas été écrit pour un MK, mais pour plusieurs lignes. Cela suggère que le code sera portable lors du déplacement vers d'autres MK dans ces lignes (à moins, bien sûr, que vous n'essayiez d'utiliser des unités périphériques qui ne sont pas dans le MK que vous utilisez).

Tout d'abord, vous devez décider avec quels blocs travailler. Pour ce faire, il suffit d'étudier les sections Introduction Et Caractéristiques principales.

Le contrôle direct de l'état des broches MK s'effectue à l'aide du bloc GPIO. Comme indiqué dans la documentation, le MCU STM32 peut avoir jusqu'à 11 blocs GPIO indépendants. Divers blocs GPIO périphériques sont communément appelés ports. Les ports sont désignés par les lettres A à K. Chaque port peut contenir jusqu'à 16 broches. Comme nous l'avons noté précédemment, la LED est connectée à la broche PD13. Cela signifie que cette broche est contrôlée par le port GPIO D de l'unité périphérique. Broche numéro 13.

Cette fois, nous n'aurons besoin d'aucune autre unité périphérique.

Contrôle de l'horloge périphérique
Pour réduire la consommation électrique du MK, presque toutes les unités périphériques sont éteintes après la mise sous tension du MK. Le bloc est activé/désactivé en appliquant/arrêtant l'alimentation d'un signal d'horloge à son entrée. Pour un fonctionnement correct, il est nécessaire de configurer le contrôleur de signal d'horloge MK de manière à ce que l'unité périphérique requise reçoive un signal d'horloge.
Important: L'unité périphérique ne peut pas démarrer le fonctionnement tout de suite après l'activation du signal d'horloge. Vous devez attendre quelques ticks jusqu'à ce qu'il « démarre ». Les personnes utilisant des bibliothèques périphériques ne connaissent souvent même pas cette fonctionnalité.

Les registres sont chargés de permettre la synchronisation des unités périphériques Registre d'activation de l'horloge périphérique RCC XXX.A la place de XXX, il peut y avoir des pneus AHB1, AHB2, AHB3, APB1 et APB2. Après avoir soigneusement étudié la description des registres correspondants, nous pouvons conclure que la synchronisation du bloc périphérique GPIOD est activée en mettant « 1 » dans le troisième bit du registre. Registre d'activation de l'horloge périphérique RCC AHB1 (RCC_AHB1ENR):

Vous devez maintenant comprendre comment connaître l'adresse du registre lui-même RCC_AHB1ENR.

Commentaire: La description du système de synchronisation STM32 MK mérite un article séparé. Si les lecteurs le souhaitent, je couvrirai cette section plus en détail dans l’un des articles suivants.

Détermination des adresses de registres spéciaux
La détermination des adresses des registres spéciaux doit commencer par lire la section Carte mémoire dans Manuel de référence. Vous pouvez voir que chaque bloc se voit attribuer sa propre section de l'espace d'adressage. Par exemple, pour le bloc RCC il s'agit de la section 0x4002 3800 - 0x4002 3BFF :

Pour obtenir l'adresse du registre, il faut ajouter à la valeur initiale de l'espace d'adressage du bloc RCC Adr. compenser le registre requis. Adresses décalées est également indiqué dans la description du registre (voir capture d'écran ci-dessus).

En conséquence, nous avons déterminé l'adresse du registre RCC_AHB1ENR-0x4002 3830.

Bloc GPIO
Pour une compréhension générale du bloc GPIO, je recommande fortement de lire toute la section du manuel de référence. Pour l'instant, vous ne pouvez pas y prêter beaucoup d'attention Mode alternatif. Nous laisserons cela pour plus tard.

Notre tâche est maintenant d'apprendre à gérer l'état des broches MK. Passons directement à la description des registres GPIO.

Mode de fonctionnement
Tout d'abord, vous devez définir le mode de fonctionnement de la broche 13 du port D comme Mode de sortie à usage général, ce qui signifie que le bloc GPIO contrôlera l'état de la broche MK. Le mode de fonctionnement des broches MK est contrôlé à l'aide d'un registre Registre de mode de port GPIO (GPIOx_MODER) (x = A..I/J/K):

Comme le montre la description, pour effectuer l'ajustement dont nous avons besoin, nous devons écrire la valeur 01b dans 26-27 bits du registre. GPIOx_MODER. L'adresse du registre peut être déterminée en utilisant la même méthode que celle décrite ci-dessus.

Configuration des paramètres de fonctionnement des broches de sortie du port GPIO
Le bloc GPIO vous permet d'appliquer des paramètres supplémentaires pour les broches de sortie du port. Ces réglages sont effectués dans les registres :
  • Registre de type de sortie du port GPIO (GPIOx_OTYPER)- définir le type de sortie push-pull ou open-drain
  • Registre de vitesse de sortie du port GPIO (GPIOx_OSPEEDR)- régler la vitesse de sortie
Nous ne modifierons pas ces paramètres, car nous sommes assez satisfaits des valeurs par défaut.
Définition de la valeur sur la broche MK
Enfin, nous sommes arrivés au moment de contrôler l'état de sortie du MK. Il existe deux méthodes pour définir la valeur de sortie sur une broche MK spécifique.

Nous utilisons le registre de définition/réinitialisation des bits du port GPIO (GPIOx_BSRR)

L'écriture d'un « 0 » ou d'un « 1 » sur les bits 0 à 16 provoque un changement correspondant dans l'état des broches du port. Afin de fixer une certaine valeur à la sortie d'une ou plusieurs broches MK et de ne pas changer l'état des autres, il faudra utiliser l'opération de modification des bits individuels. Cette opération s'effectue en au moins 3 cycles. S'il est nécessaire d'écrire des 1 sur certains bits et des 0 sur d'autres, alors au moins 4 cycles d'horloge seront nécessaires. Cette méthode Utilisé de préférence pour inverser l’état d’une sortie si son état d’origine est inconnu.

Registre de définition/réinitialisation des bits du port GPIO (GPIOx_BSRR)

Contrairement à la méthode précédente, écrire 0 sur n’importe lequel des bits de ce registre ne mènera à rien (et en général, tous les bits sont en écriture seule !). L'écriture de 1 sur les bits 0 à 15 entraînera la définition d'un « 1 » à la sortie correspondante du MK. L'écriture de 1 sur les bits 16 à 31 définira « 0 » sur la sortie correspondante du MK. Cette méthode est préférable à la précédente si vous devez définir une valeur spécifique sur la broche « MK » plutôt que de la modifier.

Allumons la LED !
Après avoir trouvé les adresses de tous les registres nécessaires, vous pouvez écrire un programme qui allume la LED :
void main() ( //Activer la synchronisation du port D *(unsigned long*)(0x40023830) |= 0x8; //petit délai pour GPIOD préparez-vous volatile unsigned long i=0; i++; i++; i++; i=0; / /Définissez PD13 comme sortie à usage général *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); //Allumez la LED ! *(unsigned long*) (0x40020C14) |= 0x2000; tandis que(1); )
Peut être compilé ( Projet->Compiler) et remplissez ( Projet->Télécharger->Télécharger l'application active). Ou exécutez le débogage ( Projet->Dpwnload et débogage) et lancez l'exécution (F5).
La LED s'est allumée !
LED clignotante
Le clignotement de la LED n'est rien de plus qu'une alternance d'allumage et d'extinction avec un délai entre ces actions. Le plus simple est de mettre les on et off dans une boucle éternelle, et d'insérer un délai entre eux.
void main() ( //Activer la synchronisation du port D *(unsigned long*)(0x40023830) |= 0x8; //petit délai pour GPIOD préparez-vous volatile unsigned long i=0; i++; i++; i++; i=0; / /Définissez PD13 comme sortie à usage général *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); while(1) ( //Allumer la LED *( unsigned long*)(0x40020C14) |= 0x2000; //Délai pour (i=0; i<1000000 ;++i); //Turn LED OFF *(unsigned long*)(0x40020C14) &= ~0x2000; //Delay for(i=0; i<1000000 ;++i); } }
La valeur de retard de 1 000 000 a été sélectionnée expérimentalement de manière à ce que la période de clignotement de la LED soit visible à l'œil nu, mais ne soit pas trop longue.
Optimisation de l'algorithme
L'inconvénient de l'approche choisie pour le clignotement des LED est que le noyau MK passe la plupart de son temps dans des boucles vides, même s'il pourrait faire quelque chose d'utile (dans notre exemple, il n'y a pas d'autres tâches, mais elles apparaîtront dans le futur).

Afin d'éviter cela, un compteur de cycles est généralement utilisé et l'état de la broche MK change lorsque le programme passe par un certain nombre de cycles.
void main() ( //Activer la synchronisation du port D *(unsigned long*)(0x40023830) |= 0x8; //petit délai pour GPIOD préparez-vous volatile unsigned long i=0; i++; i++; i++; i=0; / /Définissez PD13 comme sortie à usage général *(unsigned long*)(0x40020C00) = (*(unsigned long*)(0x40020C00)& (~0x0C000000)) | (0x04000000); while(1) ( i++; if(!(i %2000000)) ( //Allumer la LED *(unsigned long*)(0x40020С14) |= 0x2020; ) else if(!(i%1000000)) ( //Éteindre la LED *(unsigned long*)(0x40020С14) & = ~0x2000; ) ) )
Mais même ici, cela ne sera pas sans problèmes : avec un changement dans le nombre de commandes exécutées dans le cycle, la période de clignotement de la LED (ou la période d'exécution des autres commandes dans le cycle) changera. Mais à ce stade, nous ne pouvons pas lutter contre cela.

Un peu sur le débogage
IAR permet de déboguer une application directement sur le matériel. Tout ressemble presque au débogage d’une application PC. Il existe un mode d'exécution pas à pas, de saisie d'une fonction, de visualisation des valeurs des variables (En mode débogage Affichage->Regarder->Regarder1/4).

Mais en plus de cela, il est possible de visualiser les valeurs des registres du noyau, des registres spéciaux des unités périphériques (View->Register), etc.
Je vous recommande fortement de vous familiariser avec les capacités du débogueur tout en apprenant la programmation MK.

Quelques mots en conclusion

Beaucoup diront peut-être qu'écrire manuellement des adresses dans un programme n'est pas correct, car le fabricant fournit des fichiers avec des définitions de registres et de champs de bits, des bibliothèques pour travailler avec des périphériques et d'autres outils qui facilitent la vie du développeur. Je suis entièrement d'accord avec cela, mais je crois toujours que les premières étapes de la programmation d'un MK doivent être faites en parcourant manuellement la documentation, en déterminant indépendamment les registres et les champs de bits nécessaires. Vous n’êtes pas obligé de l’utiliser à l’avenir, mais vous devez absolument savoir comment le faire.
Voici quelques raisons pour cette affirmation :
  • Parfois, les bibliothèques du fabricant contiennent des erreurs ! Une fois, j'ai failli rater la date limite d'un projet à cause de cela. J'ai ressoudé la puce plusieurs fois, pensant que le cristal avait été endommagé lors de la soudure (cela s'était déjà produit). Le problème était que l’adresse du registre spécial était mal saisie dans la bibliothèque. Cela se produit généralement avec les lignes MK ou MK qui viennent d'entrer sur le marché.
  • Les bibliothèques permettant de travailler avec des périphériques de certains fabricants n'implémentent pas toutes les capacités des unités périphériques. J'ai particulièrement péché avec ça Luminaire Micro, qui ont ensuite été rachetés par TI. J'ai dû écrire l'initialisation des périphériques manuellement.
  • Beaucoup de gens s'habituent à démarrer la programmation MK en étudiant des exemples. Je pense que vous devez d'abord décider de ce qui vous permet de mettre en œuvre MK. Cela ne peut être compris qu'en lisant la documentation. Si quelque chose ne figure pas dans les exemples, cela ne signifie pas que le matériel ne le prend pas en charge. Le dernier exemple est la prise en charge matérielle PTP STM32. Bien sûr, vous pouvez trouver quelque chose en ligne, mais cela n'est pas inclus dans l'ensemble standard du fabricant.
  • Les pilotes des unités périphériques de certains fabricants sont si peu optimisés que changer l'état d'une broche à l'aide de la bibliothèque prend jusqu'à 20 cycles d'horloge. C'est un luxe inabordable pour certaines tâches.

Merci à tous ceux qui ont lu mon message, il s'est avéré bien plus que ce à quoi je m'attendais au début.
J'attends avec impatience vos commentaires et critiques motivées. Si ceux qui le lisent en ont envie, j'essaierai de continuer la série d'articles. Peut-être que quelqu'un a des idées sur des sujets qui mériteraient d'être abordés - je serais heureux de les entendre.