Programmation des microcontrôleurs modernes: leçon 1

Résumé de la première conférence sur la programmation de microcontrôleurs modernes en utilisant l'exemple de STM32 et du système d'exploitation RIOT. Les conférences sont données au MIREA Institute of Information Technology le samedi, à partir de 12h50 dans l'auditorium du 4ème étage du bâtiment D.Les cours consacrent 1,5 heure à la conférence elle-même et 3 heures aux cours pratiques du laboratoire IoT de la Samsung Academy sur le thème de la conférence.

Bonjour Giktayms! Comme nous l'avions promis, nous commençons à publier des notes de cours qui sont livrées au MIREA IT Institute. Selon les résultats de la première conférence d'introduction, nous avons décidé de modifier légèrement la structure du cours - au lieu des deux volets prévus de 5 leçons, il y aura un volet pour 7 leçons. Cela permettra de trier un certain nombre de questions de soutien à un rythme plus détendu, ainsi que des articles abstraits apparaîtront sur le GT chaque semaine en mars et avril, et non dans une semaine, comme prévu précédemment.

Néanmoins, dans sept conférences, il est impossible de couvrir complètement un sujet aussi vaste, de sorte que la présentation sera une thèse à certains endroits - bien que pour compenser cela, nous essaierons d'indiquer dans quelle direction ceux qui veulent examiner de manière indépendante plus en profondeur telle ou telle question se penchera.

Le cours est conçu pour les étudiants de deuxième et troisième année qui sont familiers avec le langage C et les concepts de base de l'électronique et de l'électrotechnique. Une connaissance préalable des microcontrôleurs n'est pas requise.

L'objectif du cours est le développement de compétences qui vous permettent de travailler librement avec des microcontrôleurs sur le noyau ARM Cortex-M au niveau moderne et, si tel est le cas, de progresser vers un approfondissement de vos connaissances.



La conférence d'aujourd'hui est la première, donc elle comprendra les concepts généraux: qu'est-ce qu'un microcontrôleur en général et pourquoi est-il nécessaire, quel est le firmware et comment est-il obtenu, pourquoi avons-nous besoin d'un système d'exploitation et enfin, comment travailler avec git. Le résultat de cette leçon est votre propre référentiel GitHub avec les codes sources du système d'exploitation, ainsi qu'un environnement de génération correctement configuré sur l'ordinateur local.

Microcontrôleur


En bref, le microcontrôleur est un exemple classique de «système sur puce», qui comprend à la fois le cœur du processeur et un ensemble de dispositifs auxiliaires et périphériques, ce qui permet au microcontrôleur dans de nombreux cas d'être complètement autosuffisant.



Dans un microprocesseur typique, semblable à celui de n'importe quel PC ou smartphone, presque tous les modules qui peuvent être attribués à des auxiliaires (alimentation, horloge, même périphériques de base) sont déplacés à l'extérieur de la puce elle-même, malgré le fait que le microprocesseur fonctionne sans eux. ne peut pas.

Dans le microcontrôleur, au contraire, sur la même puce avec le cœur, non seulement les sous-systèmes nécessaires à son fonctionnement sont mis en œuvre, mais également la masse des périphériques qui peuvent être nécessaires dans diverses tâches pratiques. De plus, de nombreux fabricants de microcontrôleurs rivalisent non pas en termes de performances de base ou de capacité de mémoire, mais en termes d'abondance et de fonctions des périphériques.

Les microcontrôleurs se développent en parallèle avec les microprocesseurs depuis un certain temps - par exemple, l'architecture Intel 8051 encore présente dans les produits industriels a été développée en 1980. À certains moments, les lignes de leur développement commencent à se croiser avec les microprocesseurs - par exemple, les anciens modèles de microcontrôleurs ont des interfaces pour la RAM externe, et les fabricants de microprocesseurs intègrent de plus en plus de périphériques sur la puce (il suffit de rappeler qu'à l'aube des "ordinateurs personnels" même le cache externe a été composé. microcircuits) - mais en tout cas, ils restent deux branches de développement significativement différentes.

En fait, l'objectif de créer des microcontrôleurs était de réduire le coût et la miniaturisation de divers appareils nécessitant une petite puissance de calcul: l'utilisation d'une seule puce, pour laquelle il suffit d'alimenter son fonctionnement, simplifie considérablement la conception et la fabrication d'une carte de circuit imprimé par rapport à un ensemble de 4-5 puces séparées .

Bien sûr, le microcontrôleur a ses propres limites - il est techniquement impossible d'emballer dans une seule puce ce qui dans un grand PC occupe la moitié d'une carte assez grande.

  • Les fréquences de fonctionnement dépassent rarement 200 MHz et sont plus souvent de l'ordre de dizaines de mégahertz.
  • La quantité de RAM est de l'ordre de mégaoctets, et plus souvent de l'ordre de dizaines de kilo-octets.
  • La quantité de mémoire du programme est de l'ordre de mégaoctets, et plus souvent de l'ordre de dizaines à centaines de kilo-octets.

Dans le cadre du cours, nous travaillerons avec des microcontrôleurs STM32L151CC qui ont 32 Ko de RAM, 256 Ko de ROM et une fréquence de fonctionnement maximale de 32 MHz (des puces légèrement plus sérieuses se trouvent sur les cartes Nucleo-L152RE - 80 Ko de RAM et 512 Ko de ROM).

La mémoire


En général, il peut y avoir quatre types de mémoire à l'intérieur d'un microcontrôleur:

  1. La mémoire permanente ( mémoire flash) est utilisée pour stocker les programmes utilisateur et, parfois, certains paramètres du microcontrôleur lui-même. Si, lors de la spécification des caractéristiques du microcontrôleur, ils écrivent la quantité de mémoire sans spécifier laquelle - en règle générale, il s'agit de flash. Le contenu du flash n'est pas réinitialisé en cas de panne de courant, la durée de stockage des informations qu'il contient dans des conditions normales est généralement d'au moins 10 ans.
  2. La RAM est utilisée pour exécuter un programme utilisateur et stocker des données «momentanées». La RAM est toujours réinitialisée lorsque vous redémarrez ou éteignez, et peut également ne pas être enregistrée lorsque vous entrez dans certains modes de veille. Dans les microcontrôleurs, il n'y a souvent pas de séparation claire entre la mémoire du programme et la mémoire des données - en conséquence, le terme «exécution à partir de la RAM» peut être trouvé, ce qui signifie qu'en RAM, il n'y a pas seulement des données, mais aussi le programme lui-même; cependant, ce sont des cas assez exotiques.
  3. EEPROM . Il fait également référence à la mémoire morte, mais diffère considérablement de la mémoire flash dans ses caractéristiques. Le flash a deux gros inconvénients qui rendent très difficile l'enregistrement de certaines données actuelles du programme - premièrement, le flash a un nombre limité de remplacements de la même cellule, et deuxièmement, il est souvent possible de travailler avec le flash uniquement sur des pages entières, ce qui sont des centaines d'octets, même si vous avez besoin d'écraser un seul octet. L'EEPROM ne présente pas ces inconvénients - sa durée de vie est généralement dix fois plus longue (de 100 000 à 1 million d'écrasements) et il est possible d'y travailler avec chaque octet individuellement. Pour cette raison, l'EEPROM est utilisée pour stocker en permanence les données générées par le programme lui-même (archives de mesure, paramètres du programme, etc.), son volume typique est des unités de kilo-octets, mais il n'est pas dans tous les contrôleurs.
  4. Mémoire système Zones de mémoire morte, inaccessibles à l'utilisateur pour l'enregistrement, mais enregistrées dans la production du microcontrôleur. Habituellement, ils contiennent le code exécutable du chargeur de démarrage (à ce sujet ci-dessous), mais certaines constantes d'étalonnage, numéros de série ou même des bibliothèques auxiliaires pour travailler avec des périphériques peuvent également être stockés

Vous pouvez consulter l'organisation de la mémoire d'un contrôleur spécifique dans sa fiche technique. Voici, par exemple, une fiche technique du STM32L151CC , à la page 51 dont une carte mémoire de cette famille est présentée.

Il est facile de remarquer que les quatre types de mémoire, dont nous avons parlé, occupent un très petit morceau de la carte - et sur la plupart de l'image, il y a une liste de tous les périphériques disponibles dans le contrôleur.

Registres


Le fait est que tout - en général tout - la communication avec tous les périphériques du microcontrôleur et tous ses réglages s'effectue en seulement deux opérations:

  • lire la valeur à l'adresse indiquée
  • écrire la valeur à l'adresse donnée

Tout ce qui se trouve à l'intérieur du microcontrôleur est nécessairement mappé à une adresse. Ces adresses sont appelées registres (ne pas confondre avec les registres de processeur - les registres des processeurs contiennent des données sur lesquelles le processeur effectue des opérations; les registres dont nous parlons contiennent des données spéciales qui correspondent spécifiquement à l'état de diverses unités matérielles du microcontrôleur).

Ainsi, par exemple, si nous voulons que «1» apparaisse sur la troisième branche du port A du microcontrôleur (PA2, la numérotation est à partir de zéro), nous devons écrire «1» dans le troisième bit du registre situé à 0x4002014. Et si cette jambe est configurée en entrée et, au contraire, nous voulons savoir quelle est la valeur, nous devons lire le troisième bit du registre à l'adresse 0x40020010.

Oui, pour indiquer au contrôleur que cette jambe est l'entrée ou la sortie - vous devez écrire les valeurs correspondantes dans les bits correspondants à l'adresse 0x40020000.

C'est un point important pour comprendre le fonctionnement du microcontrôleur: absolument tout ce qui n'est pas des opérations de calcul, dont le cœur du processeur est lui-même responsable, se fait en écrivant ou en lisant tel ou tel registre. Quelles que soient les bibliothèques qui sont piégées dans votre programme par le haut - au final, tout se résume aux registres.

Bien sûr, travailler avec des adresses numériques est plutôt gênant, donc pour chaque microcontrôleur sur le noyau Cortex-M, il y a une bibliothèque CMSIS (Cortex Microcontroller Software Interface Standard), dont le composant le plus important pour nous est le fichier d'en-tête décrivant les registres disponibles dans un contrôleur particulier et leur donnant relativement lisibles par l'homme les noms.

En utilisant CMSIS, les opérations décrites ci-dessus avec le pied PA ressembleront à ceci:

int pin_num = 2; /* PA2*/
GPIOA->MODER &= ~(0b11 << (pin_num*2)); /*     PA2    */
GPIOA->MODER |= 0b01 << (pin_num*2); /*     PA2  01 —  */
GPIOA->ODR |= 1 << pin_num; /*   PA2  1 */

GPIOA->MODER &= ~(0b11 << (pin_num*2)); /*     PA2,    */
uint32_t pa2_value = GPIOA->IDR & (1 << pin_num); /*    PA2 */

, — Reference Manual (, , , RM0038, STM32L1). , 900 RM0038 —  , 1500-2000 . -, , —  .

, — . , , «» .

, , — , - ( 1 , , , 1 , , ), .

STM32 Standard Peripherals Library, StdPeriphLib, SPL. , ST LL, — , LibOpenCM3. , STM32 .

, SPL , , , GPIO_Init GPIO_Write.

, , SPL — .

, SPL «» , , STM32 CubeMX. (, , ) STM32.

, , « , - » — « , ». SPL, , , , SPL , —  SPL , . , .

, , , - , , , STM32L1 ATSAMD21 , SPL, .

SPL — , , , SPL.

, SPL —  «» . , :

  • . , (RTC), — - , ( ) (, ), . -, .
  • . , . Arduino loop() , . loop() , , . ( , ).
  • . , , — , : -, , , . - —  , , , , . , API.

—  —  .

, ( 5-20 ), , 70 % .



, , SPL. RIOT OS, STM32 —  SPL .

: , , , , SPL . , SPL , , STM32, , .


, :



  • — , ;
  • — , , : , , ;
  • —  .

, RIOT OS - (IDE) — , , IDE, (, , Arduino IDE —  ; , , ).

, , , , « , , ».

, , Arduino IDE, IDE, — .



, RIOT OS , : HAL cpu ( , , AVR PIC32), — boards, — drivers, — core, — sys, — examples.

, — , ( ) , , , , . — , , .


https://github.com/unwireddevices/RIOT/tree/mirea — RIOT OS, Unwired Devices STM32L1, , , , .

Github, «Clone/Download» «Download ZIP», . GitHub, «Fork» — , .

GitHub Git —  , .


, , - , «Hello world» :

#include <stdio.h>
int main(void)
{
    puts("Hello World!");
    printf("You are running RIOT on a(n) %s board.\n", RIOT_BOARD);
    printf("This board features a(n) %s MCU.\n", RIOT_MCU);
    return 0;
}

example/hello-world main.c ( ).

, , , . - .

1. Windows 8 . , MinGW, . . , Git/GitHub Git for Windows, MinGW. MinGW, MinGW .

, Windows 7 Windows 8, , .

2. Windows 10. Microsoft Store, Ubuntu . Ubuntu Windows, « Windows», « Windows Linux» .

Ubuntu, , MinGW.

(: 64- Linux!), Ubuntu, :

cd /opt
sudo tar xf /mnt/c/Users/vasya/Downloads/gcc-arm-none-eabi-7-2017-q4-major-linux.tar.bz2
export PATH=/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/:$PATH
export PATH=/opt/gcc-arm-none-eabi-7-2017-q4-major/arm-none-eabi/bin/:$PATH
echo "export PATH=/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/:\$PATH" >> ~/.bashrc
echo "export PATH=/opt/gcc-arm-none-eabi-7-2017-q4-major/arm-none-eabi/bin/:\$PATH" >> ~/.bashrc

.bashrc, Ubuntu. $ >> —  , ( ) .bashrc.

arm-none-eabi-gcc --version , , — 7.2.1 ( ).

Git ssh-keygen, ( Ubuntu Windows cat ~/.ssh/id_rsa.pub, Enter — ) GitHub. GitHub git.

NB: Linux, : , Tab ( cd /opt/gcc- cd /opt/gcc-arm-none-eabi-7-2017-q4-major). , — , . , Tab .

NB: Windows , , Windows, Documents/git/RIOT. - MinGW /c/Users/vasya/Documents/git/RIOT, - Ubuntu — /mnt/c/Users/vasya/Documents/git/RIOT. , , , Windows, Notepad++.

3. Linux. Windows 10, , Microsoft Store . gcc-arm-none-eabi — .

, RIOT examples/hello-world, make.

, , unzip ( Windows 10 ), make . Windows 10 ( ):

sudo apt-get install unzip make

make — , «make clean && make»: , . , - , —  , .

NB: RIOT hello-world native, , , x86. unwd-range-l1-r3, stm32,

Building application "mirea" for "unwd-range-l1-r3" with MCU "stm32l1".

- , make — . mirea.elf ( - ).

- :



, , , , , .

, GPIO, — , , — , .

P.S. — 360- ( : « » , , - ):



Source: https://habr.com/ru/post/fr411143/


All Articles