Micro-contrôleur – 1/ Architecture

Micro-contrôleur – 1/ Architecture

Introduction

Pour le vulgariser, le microcontrôleur est un « mini ordinateur » ; il est à l’échelle d’une carte électronique grâce à sa forte intégration (micro-électronique).

Exemple de micro-contrôleur que nous suivront dans ce tutoriel : le AVR le ATMEGA2560 :

Le voici en boîtier « 100A »  16mm² :

atmega2560-8au-500x500

atmega2560_pinout

 

 

 

 

 

 

Le voici en boitier « 100C1 » 7.2mm²

100c_package

 

atmega2560_pinout_2

Comme un ordinateur, il est donc principalement composé de :

  • A) Micro-processeur (unité de calcul)
  • B) Différent types de mémoires
  • C) Périphériques d’entrée sortie

Le Processeur

Autant commencer par le plus difficile : le processeur.

Niveau débutant

Le processeur exécute les « instructions machine ».
Les « instructions machines » c’est votre code ! Les outils de développement moderne nous permettent de programmer des instructions en langage haut niveau comme le C/C++ par exemple.
Ces outils de développement sont les logiciels de programmation fournis par les fabricants, ils auront alors pour charge de convertir du code en C/C++ en langage « assembleur ». C’est à dire, en instructions bas niveau, exécutable par le processeur ciblé. A noter que  chaque fabricant de micro-processeur a son propre code assembleur.

Niveau intermédiaire

L’image ci dessous montre un exemple de cette conversion du langage C vers un un langage assembleur:Dans l’exemple ci dessous le code C nous permet de lire facilement l’évolution des variable ax, bx et cx.c_assembleurLe code assembleur lui, est plus « détaillé ».
Le « CMP » signifie qu’on COMPARE  AX à la valeur 1, ensuite on « JNZ » (Jump if Not Zero) au « Else ».
C’est à dire que si la comparaison de AX et de 1 ne renvoi pas un Zéro (donc elle est fausse), le microprocesseur doit « JUMP » (donc sauter) à la ligne du Else. Si ce n’est pas le cas (la comparaison de AX et de 1 renvoi un Zéro), il continue normalement à exécuter la ligne suivante. Ensuite il affecte des valeurs aux variables avec l’opération « MOV » pour MOVE (bouger). Les variables déclarées en C, que vous nommez comme bon vous semble doivent passer dans les registres du microprocesseur pour être modifiées.
Si vous nommé dans votre code C, une variable « TOTO », la conversion de votre code C en assembleur fera apparaitre que votre variable « TOTO » passera dans le registre Accumulateur pour être modifié par le micro-processeur.Les registres AX, BX, CX et DX sont les registres les plus utilisés pour les calculs :
  • Le registre AX sert à effectuer des calculs arithmétiques ou à envoyer un paramètre à une interruption
  • Le registre BX sert à effectuer des calculs arithmétiques ou bien des calculs sur les adresses
  • Le registre CX sert généralement comme compteur dans des boucles
  • Le registre DX sert à stocker des données destinées à des fonctions

A mon humble avis, il n’est pas absolument nécessaire d’un connaitre plus sur le processeur pour commencer à  programmer un micro-contrôleur. Vous pouvez le considérer comme une entité capable d’exécuter des instructions assembleur.
Si toute fois, vous souhaitez en savoir un peu plus sur les structures internes, je vous propose d’aller un peu plus loin dans le paragraphe ci dessous.


Pour aller plus loin…

Examinons maintenant la structure interne et les éléments de base d’un processeur.

processeur_

  • Les registres sont des petites mémoires internes très rapides, pouvant être accédées facilement. Parmi les registres on trouve notamment
    • l’accumulateur qui sert à stocker les données traitées par l’UAL (l’unité de calcul arithmétique et logique, ALU en anglais)
    • compteur ordinal ou PC (Program Counter) donne l’adresse mémoire de la prochaine instruction
    • le pointeur de pile : il sert à stocker l’adresse des structures de données généralement utilisées pour gérer des appels de sous-programmes
    • le registre d’instruction : il permet quant à lui de stocker l’instruction en cours de traitement,
    • le registre d’état : il est composé de plusieurs bits, appelés drapeaux (flags), servant à stocker des informations concernant le résultat de la dernière instruction exécutée
    • les registres généraux, qui servent à stocker les données allant être utilisées (ce qui permet d’économiser des aller-retours avec la mémoire RAM).
  • L’unité de contrôle, se charge de gérer le processeur. Il peut décoder les instructions, choisir les registres à utiliser, gérer les interruptions ou initialiser les registres au démarrage.
  • L’UAL (Unité Arithmétique et Logique) est chargée de faire l’opération. on trouve différents types d’UAL :
    • Les UAL élémentaires calculent sur des nombres entiers, et peuvent effectuer les opérations communes, que l’on peut séparer en 4 groupes :
      • Les opérations arithmétiques : addition, soustraction, changement de signe, etc.
      • les opérations logiques : compléments à un, à deux, et, ou, ou-exclusif, non, non-et, etc.
      • les comparaisons : test d’égalité, supérieur, inférieur, et leur équivalents « ou égal ».
      • éventuellement des décalages et rotations (mais parfois ces opérations sont externalisées).
    • Les  UAL spécialisées dans la manipulation des nombres à virgule flottante, en simple ou double précision (on parle d’unité de calcul en virgule flottante (UVF, en anglais floating-point unit, FPU) ou dans les calculs vectoriels. Typiquement, ces unités savent accomplir les opérations suivantes :
      • additions, soustractions, changement de signe ;multiplications, divisions ;
      • comparaisons ;
      • modulos.
  • 3 Types de bus de communications sont utilisés:
    • bus de données, pour les accès à la mémoire, la taille de ce bus conditionne la taille des données en entrés/sorties
    • bus d’adresse, qui permet, lors d’une lecture ou d’une écriture, de sélectionner le registre à configurer, la taille de ce bus conditionne le nombre de cases mémoire accessibles ;
    • bus de contrôle, qui permet la gestion du matériel, via les interruptions.

Regardons ce qui se passe dans le processeur lors de l’exécution d’une instruction assembleur.

Les instructions sont décomposées en micro-instructions, souvent on trouve 4 étapes pilotées par l’unité de contrôle :

  • Fetch, recherche de l’instruction dans la mémoire flash du µC, à l’aide du PC (Conteur programme ou conteur ordinal) qui stocke l’adresse de la prochaine instruction
  • Decode, interprétation de l’instruction (opération et opérandes). Découpe l’instruction en plusieurs parties telles qu’elles puissent être utilisées par d’autres parties du processeur.  Souvent, une partie d’une instruction, appelée opcode (code d’opération), indique l’opération à effectuer, par exemple une addition.
  • Execute, exécution de l’instruction, met en relation différentes parties du processeur pour réaliser l’opération souhaitée. Par exemple, pour une addition, l’unité arithmétique et logique (ALU) sera connectée à des entrées et une sortie
  • Writeback, écriture du résultat, écrit les résultats de l’étape d’exécution en mémoire.

Appliquons cette exemple à une instruction d’addition simple,

add_micro_instruction
Le « Fetch » va chercher dans la mémoire flash (la mémoire qui contient les instructions) la ligne d’assembleur : 

« ADDI  &r1, &r2, 350 »  : on souhaite rajouter 350 à la valeur dans le registre R2 et enregistrer ce résultat dans le registre r1
Le « Decode » va donner un « Opération code » par exemple « 001000 » pour l’addition et interpréter les adresses des registres demandés (00001 pour r1 et 00010 pour r2)

Le « Execute » envoi les données à l’ALU (qui effectue l’opération)

Le « Writeback« , écriture du résultat de l’étape d’exécution en mémoire (de l’ALU vers r1)
C’était un exemple pour une instruction utilisant l’ALU mais certains types d’instructions manipulent le compteur de programme (registre PC) plutôt que de produire directement des données de résultat. Ces instructions sont appelées des branchements (branch) et permettent de réaliser des boucles (loops), des programmes à exécution conditionnelle ou des fonctions (sous-programmes) dans des programmes…

Comment optimiser les temps d’exécutions ? Quelle architecture interne ?

Le processeur est cadencé par son horloge. Pour simplifier, on peut imaginer qu’une de ces micro-instructions est exécutée à chaque coup d’horloge.
Pour notre exemple du ATMEGA2560, on peut le cadencer à 16MHz soit un coup d’horloge toute les 62.5 nanosecondes …
Sur une génération plus récente en architecture ARM  comme par exemple le « Atmel SAM3X8E ARM Cortex-M3 » on atteint 84 MHz soit une horloge 5.25 fois plus rapide.
Au fil des générations, les constructeurs ont trouvé des méthodes permettant d’augmenter la cadence des processeurs.
L’une de ces innovation est l’architecture RISC (en anglais Reduced Instruction Set Computer) : « processeur à jeux d’instructions réduit ». Cette stratégie était bien adaptée à la réalisation des microprocesseurs. À la fin des années 1980 et au début des années 1990, elle concurrençait des architectures traditionnelles plus lourdes CISC (complex instruction-set computer).
En effet, les grandes différences de taille, de temps de décodage comme de temps d’exécution s’opposaient à des optimisations de type « pipe-line »
L’efficacité de l’architecture RISC est lié au principe du « pipe-line ».

Principe du « pipe-line » sur une chaine de montage de voiture

Le pipeline est un concept s’inspirant du fonctionnement d’une ligne de montage. Considérons que l’assemblage d’un véhicule se compose en trois étapes :

  1. Installation du moteur (20 minutes)
  2. Installation du capot (5 minutes)
  3. Pose des pneumatiques (10minutes)

Un véhicule dans cette ligne de montage ne peut se trouver que dans une seule position à la fois.  

Cas numéros 1 :

Si l’installation du moteur, du capot et des roues prennent respectivement 20, 5 et 10 minutes, la réalisation de trois véhicules prendra, s’ils occupent un à un toute la chaîne de production,  (20 + 5 + 10) × 3=105 minutes.

Cas numéros 2 (pipeline) :

Si on place un véhicule dans la chaîne de production dès que l’étage auquel le véhicule doit accéder est libre (principe du pipelining), le temps total pour réaliser les trois véhicules est de 75 minutes.

Principe du « pipe-line » appliqué au processeur

Reprenons un cycle de micro-instructions :
IF (Instruction Fetch)
ID (Instruction Decode)
EX (Execute)
MEM (Memory), dénote un transfert depuis un registre vers la mémoire
WB (Write Back)

Appliquons le principe du « pipe-line » avec : un cycle d’horloge= une micro-instruction.

nopipeline
Sans Pipe-line
fivestagespipeline
Avec Pipe-line (5 étages)

Sur l’exemple ci dessus, en moyenne, ou passe de 5 cycles pour une instruction  à 1.8 cycles pour une instruction avec un pipeline de 5 étages.

Dans le cas de notre µC ATMEGA2560, le processeur utilise bien le pipeline mais sur un seul étage.
Une génération plus récente de µC comme le  Atmel SAM3X8E ARM Cortex-M3 utilise un pipe-line de 3 étages.
Enfin un processeur de PC comme le Intel Pentium 4 Prescott a 31 étages.

L’architecture RISC, avec son jeux d’instruction réduit, permet des cycles d’horloge beaucoup plus court pour exécuter une micro-instruction. Combiné avec le principe du pipeline, elle contribue a l’augmentation  de la cadence des processeur et donc de leur puissance de calcul.

sources : https://fr.wikipedia.org/wiki/Processeur
https://fr.wikipedia.org/wiki/Pipeline_(architecture_des_processeurs)

Ce qu’il faut retenir :

Votre code écrit en langage haut niveau (C/C++) sera compilé par les outils logiciel du fabricant pour une certaine cible de micro-contrôleur afin de générer des instructions assembleurs. Les instructions assembleur décrivent le code bas-niveau c’est à dire le déplacement des variables, des entrés/sorties, le parcours de la mémoire de programme… Le micro-processeur, par lecture et exécution du code assembleur, fait le lien entre les instructions (software) et l’état physique du microcontrôleur (hardware). 

Les mémoires

Reprenons l’analogie avec le PC. Le PC/tablette/Smartphone  sur le quel vous êtes en train de lire ce tutoriel possède plusieurs types de mémoire : Disque dur, RAM.

Le disque dur stocke les données à long terme tandis que la mémoire RAM  stocke les variables des programmes en cours d’exécution.
Les mémoires sont adaptées à leurs utilisations : la RAM est très rapide d’accès mais le prix au Go revient cher, c’est l’inverse pour le disque dur (lent d’accès et peu cher au Go).

Sur le micro-contrôleur on trouve 3 types de mémoire : RAM (identique PC), EEPROM (équivalent disque dur du PC), Flash (spécifique au microcontrôleur).

La RAM
Comme sur le PC, elle servira à stocker les variables du programme. Chaque fois que vous faites une nouvelle déclaration de variables, cette dernière se retrouvera dans cette mémoire. Une caractéristique à ne pas négliger, cette mémoire est entièrement effacée lorsque l’alimentation du micro-contrôleur est coupée (on dit qu’elle est « volatile »).

L’EEPROM
Ensuite, on trouve une mémoire dite morte, l’EEPROM (Electrically Erasable Programmable Read-Only Memory). Elle est capable de stocker des informations même lorsqu’elle n’est plus alimentée (on parle de mémoire morte). Cette dernière est similaire au disque dur de votre ordinateur par son comportement et ses caractéristiques. La vitesse d’accès est moins élevée que la RAM. Dans un programme, elle servira par exemple à conserver des données entre deux allumages du produit.

La FLASH
Enfin, une dernière mémoire est la Flash. Elle a un rôle un peu particulier, elle sert à stocker le programme que vous téléchargez dans le microcontrôleur (vous vous souvenez le : code machine assembleur).
Elle retient donc les informations même lorsque l’alimentation est coupée (pas besoin de flasher le programme à chaque allumage !). Elle stocke aussi le  boot loader, un petit bout de code qui agit comme le BIOS de votre PC.

Le boot loader détecte au démarrage  du micro-contrôleur si l’on tente de programmer la carte (via une liaison série ou un port ICSP…) le cas échéant copiera les données dans la mémoire FLASH. On n’y stocke pas de données pendant l’exécution du programme. Cette mémoire sera écrite lors du « flash » du micro-contrôleur et ne sera qu’en lecture lors de l’exécution du code.

Si l’on reprend l’exemple du micro-contrôleur de AVR le ATMEGA2560, on y trouve : Flash Memory 256 Ko (avec 8 KB utilisé par le bootloader), SRAM 8 Ko EEPROM 4 Ko

Ce qu’il faut retenir : lors de la compilation de votre programme, en fonction de la cible (microcontrôleur) choisie, le logiciel sera capable vous dire les pourcentage de chaque type de mémoire utilisé et donc de vous indiquer si votre programme est compatible avec la cible. Après avoir converti le code en assembleur, il calcule donc les ressources hardware (mémoire) utilisées par votre programme.

Les périphériques

Reprenons l’analogie avec le PC. Pour l’utiliser, vous devez y connecter : un écran, un clavier, une souris, une carte réseau, une carte graphique…. Ce sont des périphériques d’entrées/sorties. Ils sont reliés via des connecteurs (USB, SATA, PCI…) à la carte mère du PC.

C’est le même principe avec le micro-contrôleur, il intègre différents périphériques pour interagir avec son environnement. Nous allons maintenant nous pencher sur l’architecture interne du micro-contrôleur. Je vais vous présenter étape par étape, comment lire le schémas bloc fournit par AVR pour le ATMEGA2560, notre exemple.

Nous venons de voir le rôle du processeur et des mémoires.

avr_core1

Au centre le « AVR cpu » : c’est  le micro processeur (AVR CPU), il a directement accès à 3 éléments :

  • La mémoire Flash (dont nous avons parlé)  pour lire les instructions assembleur
  • La mémoire SRAM (pour gérer les variables lors de l’exécution du code)
  • Le BUS DMA (Direct Memory Access). (la flèche double tout autour de l’image) C’est un bus qui permet au CPU d’accéder à tous les registres de tous les périphériques. Comme il s’agit d’un bus 8 bit, le CPU travaille aussi en 8bit : on a donc un µC 8bit.

On voit, maintenant que ce bus DMA communique avec les périphériques suivant :

  • EEPROM (dont nous avons parlé)

    avr_core2

  • Convertisseur AD (Analogique/Digital) (lui même avec le « internal bandgad » en entrée)
  • Analog comparator (lui aussi avec le « internal bandgad » en entrée)
  • Des Timer/counter
    • 4 de 16 bits (T/C3, T/C4,T/C5,T/C1)
    • 2 de 8 bit (T/C0,T/C2)
  • Un périphérique SPI (communication SPI)
  • Un périphérique TWI (Two Wire Interface) souvent utilisé pour une communication I2C

Les périphériques les plus importants ( A/D Convertisseur, Timer/Counter et USART) seront détaillés dans la suite de ce tutoriel.


Enfin, le schémas bloc complet:

atmega2560

Par rapport au schéma précédent sont rajoutés :
Les Ports de A à L  (soit 12 ports de 8 bits) qui sont les interfaces hardware, avec l’extérieure du composant. Elle permettent à chaque pin d’être configurable en entrée/sortie et donc de fournir ou recevoir du courant.

Les USART (Universal Asynchronous Receiver Transmitter) qui permettent de gérer les communication numériques avec l’extérieur.

Le Power suppervision bloc et le Oscillator Clock Generator  qui permettent de mettre en forme les alimentations et l’horloge nécessaires au bon fonctionnement du micro-contrôleur.

Le Watchdog est un dispositif qui permet la surveillance du micro-contrôleur. Il est conçu pour envoyer régulièrement en signal lorsque les opération μ micro-contrôleur se déroule normalement. En cas de blocage/ plantage au niveau du processeur ou autre, le signal n’est plus émit, on peut alors (via un autre composant externe au micro contrôleur) activer un RESET du microcontrôleur. En clair, on le redémarre lorsqu’il plante (encore une analogie avec le PC). have-you-tried1

Ce qu’il faut retenir : le processeur vient lire et interpréter les instructions qui se trouvent dans la mémoire flash. Pour se faire, il gère des variables dans la mémoire RAM et il commande des périphériques via le bus DMA.

Pour conclure ce premier chapitre je vous propose de voir un exemple de tout ce trafic avec un smartphone.

Que se passe t-il dans le cerveaux numériques lorsque, par exemple, j’active le bluetooth ?

J’appuie sur l’icone bluetooth de mon écran tactile. Le périphérique du microcontrôleur en charge de la gestion de l’écran va écrire dans un coin de sa mémoire ( de son registre) « ici l’utilisateur a appuyé à la position x,y de l’écran ».

Pendant ce temps le processeur « fait sa vie » et est occupé à exécuter d’autres instructions android ou Iphone… C’est à dire qu’il lit et exécute les instructions présentes dans sa mémoire flash.

Sauf que les programmeurs du smartphone ont prévu dans leur code de venir vérifier régulièrement (toutes les 100 millisecondes par exemple) le périphérique qui gère l’écran tactile. Lorsque cette instruction arrive, le processeur accède au registre qui gère l’écran tactile (via le bus DMA) et lit la valeur de son registre. Il constate alors que l’utilisateur a appuyé à la position x,y de l’écran tactile et il range cette valeur dans sa mémoire RAM.

Le processeur passe à l’instruction suivante de sa mémoire flash. Cette instruction lui dit que si l’utilisateur a appuyé sur l ‘écran, alors il doit comparer la position ou l’utilisateur à appuyé avec la position de l’icone bluetooth (entre autres). Et il range le résultat dans sa mémoire RAM.

Le processeur passe à l’instruction suivante de sa mémoire flash. Cette instruction lui dit que si la position appuyée est celle de l’icône bluetooth, alors il faut activer le bluetooth.

Le processeur passe à l’instruction suivante de sa mémoire flash. Et active le bluetooth en appliquant la bonne valeur au registre bluetooth (via le bus DMA).

Dans la partie suivante, nous apprendrons à manipuler ces périphériques afin interagir avec le monde extérieur.

Les commentaires sont clos.
Scroll Up