24.06.2013 Views

Programmation proche du hardware avec le kit de développement ...

Programmation proche du hardware avec le kit de développement ...

Programmation proche du hardware avec le kit de développement ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Haute éco<strong>le</strong> spécialisée bernoise<br />

Haute éco<strong>le</strong> technique et informatique<br />

Section microtechnique<br />

Laboratoire <strong>de</strong> l’informatique technique<br />

<strong>Programmation</strong> <strong>proche</strong> <strong>du</strong> <strong>hardware</strong><br />

<strong>avec</strong> <strong>le</strong> <strong>kit</strong> <strong>de</strong> <strong>développement</strong> pour<br />

microcontrô<strong>le</strong>ur C8051F<br />

Ce manuscrit traite l’intro<strong>du</strong>ction <strong>de</strong> la programmation <strong>proche</strong> <strong>du</strong> <strong>hardware</strong> en<br />

C. Ce cours est basé sur <strong>le</strong> <strong>kit</strong> <strong>de</strong> <strong>développement</strong> pour microcontrô<strong>le</strong>ur <strong>de</strong><br />

C8051F, fourni par « Silicon Laboratories ». Des bonnes connaissances dans la<br />

programmation en C sont nécessaires pour la poursuite <strong>de</strong> ce cours.<br />

Nom <strong>du</strong> fichier: <strong>Programmation</strong>ProchHW.doc<br />

Définition <strong>le</strong> 16. mars 2007<br />

Définie par: Elham Firouzi<br />

Version 1


Tab<strong>le</strong> <strong>de</strong>s matières<br />

Hardwarenahe Programmierung in C<br />

1 Les microcontrô<strong>le</strong>urs.............................................................................................................................4<br />

1.1 Les différents types d’ordinateur .............................................................................................. 4<br />

1.1.1 Les ordinateurs universels (PC)......................................................................................... 4<br />

1.1.2 Les super ordinateurs......................................................................................................... 4<br />

1.1.3 Les micro ordinateurs ........................................................................................................ 4<br />

1.1.4 Ordinateur temps réels....................................................................................................... 4<br />

1.2 Le processus technique ............................................................................................................ 5<br />

1.3 Transfert <strong>de</strong> données entre l’ordinateur temps réels et <strong>le</strong> processus technique ........................ 6<br />

2 L’architecture <strong>de</strong>s microprocesseurs.................................................................................................7<br />

2.1 Structure d’un système à microprocesseur ............................................................................... 7<br />

2.2 Le Processeur............................................................................................................................ 8<br />

2.3 Le système <strong>de</strong> bus..................................................................................................................... 9<br />

2.3.1 Les bus d’adresse, <strong>de</strong> données et <strong>de</strong> contrô<strong>le</strong> .................................................................... 9<br />

2.4 Domaine d’adressage.............................................................................................................. 11<br />

2.4.1 Le déco<strong>de</strong>ur d’adresse ..................................................................................................... 12<br />

2.5 La mémoire............................................................................................................................. 13<br />

2.5.1 Les technologies .............................................................................................................. 13<br />

2.5.2 L’organisation <strong>de</strong> la mémoire.......................................................................................... 14<br />

2.5.3 Les modè<strong>le</strong> <strong>de</strong> stockage et <strong>le</strong>s formats <strong>de</strong>s données ........................................................ 14<br />

2.5.4 Litt<strong>le</strong> Endian / Big Endian............................................................................................... 15<br />

2.6 La périphérie........................................................................................................................... 16<br />

2.6.1 Les registres..................................................................................................................... 16<br />

2.6.2 Les amplificateurs <strong>de</strong> sortie............................................................................................. 17<br />

2.6.3 Les entrées et sorties digita<strong>le</strong>s ......................................................................................... 18<br />

2.6.4 L’interface sériel<strong>le</strong>........................................................................................................... 18<br />

2.6.5 Le port sériels RS232 ...................................................................................................... 19<br />

2.6.6 SPI ................................................................................................................................... 21<br />

2.7 Les convertisseurs A/D........................................................................................................... 22<br />

3 La famil<strong>le</strong> <strong>de</strong>s microcontrô<strong>le</strong>urs C8051F2xx..................................................................................24<br />

3.1 Le cœur <strong>du</strong> C8051F2xx .......................................................................................................... 25<br />

3.2 La mémoire <strong>du</strong> C08051F2xx .................................................................................................. 26<br />

3.3 L’interface JTAG.................................................................................................................... 27<br />

3.4 Les entrées et <strong>le</strong> sorties <strong>du</strong> C08051F2xx ................................................................................ 28<br />

3.5 Les ports sériels <strong>du</strong> C08051F2xx............................................................................................ 29<br />

3.6 Le convertisseur analogique - digita<strong>le</strong> <strong>du</strong> C08051F2xx ......................................................... 29<br />

4 La programmation <strong>proche</strong> <strong>du</strong> <strong>hardware</strong> ..........................................................................................30<br />

4.1 L’adressage direct ................................................................................................................... 30<br />

4.2 L’adressage indirect................................................................................................................ 31<br />

4.3 Mise à un et mise à zéro <strong>de</strong>s bits dans <strong>le</strong>s registres ................................................................ 32<br />

4.4 Désactivation <strong>de</strong>s optimisations <strong>du</strong> compilateur..................................................................... 32<br />

4.4.1 Exemp<strong>le</strong>........................................................................................................................... 32<br />

4.5 Déviation <strong>de</strong>s fonctions d’entrée et <strong>de</strong> sortie.......................................................................... 34<br />

4.6 Adaptation supplémentaire <strong>de</strong> la bibliothèque standard ......................................................... 35<br />

5 Les interruptions .............................................................................................................................36<br />

5.1 Définition d’une routine d’interruption .................................................................................. 36<br />

5.2 Blocage <strong>de</strong>s interruptions........................................................................................................ 37<br />

5.3 Traitement <strong>de</strong>s interruptions <strong>avec</strong> <strong>le</strong> contrô<strong>le</strong>ur C8051F........................................................ 39<br />

5.3.1 Les vecteurs d’interruption.............................................................................................. 39<br />

2 / 41


Hardwarenahe Programmierung in C<br />

6 Le co<strong>de</strong> <strong>de</strong> démarrage .....................................................................................................................41<br />

3 / 41


1 Les microcontrô<strong>le</strong>urs<br />

Hardwarenahe Programmierung in C<br />

1.1 Les différents types d’ordinateur<br />

1.1.1 Les ordinateurs universels (PC)<br />

Les ordinateurs universels sont utilisés pour <strong>de</strong>s applications <strong>de</strong> tous <strong>le</strong>s jours. Ces <strong>de</strong>rniers sont<br />

standardisés et sont pro<strong>du</strong>its en très gran<strong>de</strong> quantité. Il existe <strong>de</strong>s programmes très variés pour ce type<br />

d’ordinateur (traitement <strong>de</strong> texte, tabulateur, environnement <strong>de</strong> <strong>développement</strong>, jeux etc.).<br />

1.1.2 Les super ordinateurs<br />

Les super ordinateurs sont utilisés pour <strong>de</strong>s travaux qui exigent <strong>de</strong>s puissances <strong>de</strong> calcul é<strong>le</strong>vées<br />

(météo, modélisation <strong>de</strong>s processus physiques etc.). Ces <strong>de</strong>rniers sont pro<strong>du</strong>its en très petite quantité et<br />

ne disposent pas <strong>de</strong> programmes déjà existants. Ces ordinateurs, ainsi que <strong>le</strong>s programmes qui doivent<br />

y être exécutés, sont pro<strong>du</strong>its pour <strong>de</strong>s applications très spécifiques.<br />

1.1.3 Les micro ordinateurs<br />

Les micro-ordinateurs sont <strong>de</strong>s petits ordinateurs, qui sont utilisés pour <strong>de</strong>s applications <strong>de</strong> contrô<strong>le</strong>.<br />

Ces <strong>de</strong>rniers possè<strong>de</strong>nt souvent <strong>de</strong>s entrés et <strong>de</strong>s sorties supplémentaires, afin <strong>de</strong> pouvoir réaliser ces<br />

opérations <strong>de</strong> contrô<strong>le</strong>. Ces ordinateurs sont fournis sous forme <strong>de</strong> carte é<strong>le</strong>ctronique ou <strong>de</strong> mo<strong>du</strong><strong>le</strong><br />

(<strong>avec</strong> ou sans boîtiers in<strong>du</strong>striels). Les composants, qui ne sont pas nécessaires, comme par exemp<strong>le</strong> la<br />

carte graphique, <strong>le</strong> clavier, <strong>le</strong> disque <strong>du</strong>re etc., ne sont pas disponib<strong>le</strong>s. Toutefois, certain système<br />

permettent d’ajouter ces <strong>de</strong>rniers sous forme d’option. Le principe ici est la simplicité avant tout.<br />

1.1.4 Ordinateur temps réels<br />

Les ordinateurs temps réels sont utilisés pour piloter <strong>de</strong>s processus techniques. Ces ordinateurs doivent<br />

respecter <strong>le</strong>s critères suivants :<br />

• Maintient <strong>de</strong> l’ordre temporel<br />

• Temps <strong>de</strong> réaction et <strong>de</strong> traitement rapi<strong>de</strong> et prédéfinie<br />

• Comportement temporel repro<strong>du</strong>ctib<strong>le</strong> et prédéfinie<br />

Les catégories d’ordinateur dépen<strong>de</strong>nt <strong>de</strong> la comp<strong>le</strong>xité <strong>du</strong> processus technique:<br />

• Super ordinateur<br />

• PC / SPS<br />

• Microcontrô<strong>le</strong>ur<br />

Les micros ordinateurs peuvent être répartis dans <strong>de</strong>ux catégories :<br />

• Sing<strong>le</strong> Chip μC (intégration sur un seul chip)<br />

• Sing<strong>le</strong> Board μC (circuit intégré <strong>avec</strong> <strong>de</strong>s éléments périphériques)<br />

Contrairement aux ordinateurs temps réels, <strong>le</strong>s ordinateurs standard (comme par exemp<strong>le</strong> PC <strong>avec</strong><br />

traitement <strong>de</strong> texte Microsoft) ne remplissent pas <strong>le</strong>s critères temps réels définis ci <strong>de</strong>ssus. Cela résulte<br />

<strong>du</strong> système d’exploitation.<br />

Ce cours traite uniquement <strong>le</strong>s micro-ordinateurs, qui sont utilisés dans <strong>le</strong>s applications suivantes :<br />

• Télécommunication (centra<strong>le</strong>, terminaux...)<br />

4 / 41


Hardwarenahe Programmierung in C<br />

• Technique médicina<strong>le</strong> (mesure <strong>du</strong> sucre, appareil auditif etc.)<br />

• Sécurité (équipement d’a<strong>le</strong>rte incendie, traverse <strong>de</strong> chemin <strong>de</strong> fer etc.)<br />

• Automatisation in<strong>du</strong>striel<strong>le</strong> (senseur, actuateur, équipement <strong>de</strong> pilotage etc.)<br />

• In<strong>du</strong>strie automobi<strong>le</strong>, chemin <strong>de</strong> fer, avion<br />

• E<strong>le</strong>ctronique <strong>de</strong> consommation (appareil photo, imprimante, hi fi etc.)<br />

Les micro-ordinateurs, qui sont utilisés dans <strong>le</strong>s applications <strong>de</strong> ci-<strong>de</strong>ssus, sont souvent qualifiés <strong>de</strong><br />

contrô<strong>le</strong>urs embarqués. En effet, ces <strong>de</strong>rniers sont « embarqués » dans un équipement.<br />

1.2 Le processus technique<br />

La figure suivante illustre l’interface entre l’ordinateur temps réel et <strong>le</strong> processus technique.<br />

Processus<br />

technique<br />

Senseur<br />

Actuateur<br />

5 / 41<br />

Ordinateur<br />

temps<br />

réels<br />

Interface<br />

utilisateur<br />

Figure 1 : Interface entre l’ordinateur temps réel et <strong>le</strong> processus technique<br />

Le processus technique est la source et la <strong>de</strong>stination <strong>de</strong>s données techniques. L’ordinateur lit l’état <strong>du</strong><br />

processus à l’ai<strong>de</strong> <strong>de</strong>s senseurs et il influence cet état à l’ai<strong>de</strong> <strong>de</strong>s actuateurs. L’utilisateur a la<br />

possibilité d’influencer <strong>le</strong> processus technique à l’ai<strong>de</strong> <strong>de</strong> l’interface utilisateur (configuration,<br />

paramétrisation). Il peut éga<strong>le</strong>ment se renseigner sur l’état <strong>du</strong> processus technique à l’ai<strong>de</strong> <strong>de</strong> cette<br />

interface.<br />

Exemp<strong>le</strong> <strong>de</strong> senseur :<br />

• Interrupteur mécanique, in<strong>du</strong>ctive ou optique<br />

• Convertisseur A/D<br />

• Son<strong>de</strong> <strong>de</strong> température, son<strong>de</strong> <strong>de</strong> pression<br />

Exemp<strong>le</strong> d’actuateur :<br />

• Soupape<br />

• Moteur<br />

• Ecran, LED<br />

• Relais<br />

• Convertisseur D/A


Hardwarenahe Programmierung in C<br />

1.3 Transfert <strong>de</strong> données entre l’ordinateur temps réels et<br />

<strong>le</strong> processus technique<br />

La figure suivante montre en détail <strong>le</strong>s transferts <strong>de</strong> données entre l’ordinateur temps réels et <strong>le</strong><br />

processus technique.<br />

Données <strong>de</strong><br />

sortie<br />

Va<strong>le</strong>urs <strong>de</strong><br />

contrô<strong>le</strong><br />

Entrée <strong>du</strong><br />

processus<br />

Algorithme <strong>de</strong> contrô<strong>le</strong><br />

Va<strong>le</strong>urs <strong>de</strong><br />

dérangement<br />

Ordinateur temps réels<br />

Paramètres<br />

caractéristiques<br />

Processus technique<br />

6 / 41<br />

Analyse <strong>du</strong> processus<br />

Données<br />

d’entrée<br />

Va<strong>le</strong>urs<br />

<strong>de</strong> mesure<br />

Contre<br />

réactions<br />

Evénement<br />

Evénement<br />

discret<br />

Sortie <strong>du</strong><br />

processus<br />

Figure 2 : Transfert <strong>de</strong> données entre un ordinateur temps réels et <strong>le</strong> processus technique<br />

Le processus technique possè<strong>de</strong> <strong>de</strong>s entrées et <strong>de</strong>s sorties, qui peuvent être soit <strong>de</strong> l’information ou <strong>du</strong><br />

matériel. Les contre réactions ou <strong>le</strong>s va<strong>le</strong>urs <strong>de</strong> dérangement influencent éga<strong>le</strong>ment <strong>le</strong> processus<br />

technique. Des paramètres caractéristiques peuvent être transmis au processus technique. L’ordinateur<br />

temps réels analyse <strong>le</strong> processus technique en lisant <strong>le</strong>s va<strong>le</strong>urs <strong>de</strong> mesure à <strong>de</strong>s instants précis, qui<br />

sont définis par <strong>le</strong>s occurrences <strong>de</strong>s événements. Les algorithmes <strong>de</strong> contrô<strong>le</strong> permettent alors <strong>de</strong><br />

définir <strong>de</strong>s va<strong>le</strong>urs <strong>de</strong> contrô<strong>le</strong> afin d’assurer <strong>le</strong> fonctionnement correct <strong>du</strong> processus technique.


Hardwarenahe Programmierung in C<br />

2 L’architecture <strong>de</strong>s microprocesseurs<br />

2.1 Structure d’un système à microprocesseur<br />

Un système à microprocesseur comprend un processeur (Central Processing Unit : CPU), une mémoire<br />

programme pour <strong>le</strong> stockage <strong>de</strong>s instructions à exécuter (Read Only Memory : ROM), une mémoire<br />

<strong>de</strong>s données pour <strong>le</strong> stockage <strong>de</strong>s variab<strong>le</strong>s (Random Access Memory : RAM) et <strong>le</strong>s éléments<br />

périphériques (voir Figure 3).<br />

Le processeur accè<strong>de</strong> à ces composants à l’ai<strong>de</strong> d’un système <strong>de</strong> bus unique. Les instructions et <strong>le</strong>s<br />

données doivent donc être chargées <strong>de</strong> façon séquentiel<strong>le</strong>. C'est-à-dire qu’il faut au moins <strong>de</strong>ux cyc<strong>le</strong>s<br />

d’horloge pour lire une instruction et <strong>le</strong>s données à traiter.<br />

CPU<br />

Bus pour <strong>le</strong>s instructions et <strong>le</strong>s données<br />

7 / 41<br />

Mémoire<br />

programme<br />

Mémoire <strong>de</strong>s<br />

données<br />

Périphérie<br />

Figure 3 : Architecture <strong>de</strong> Von Neumann<br />

La mémoire programme contient <strong>le</strong>s instructions <strong>du</strong> programme. Cette <strong>de</strong>rnière est en généra<strong>le</strong> non<br />

volati<strong>le</strong>, c’est à dire que son contenu n’est pas per<strong>du</strong> lorsque l’alimentation est coupée. Quant à la<br />

mémoire <strong>de</strong>s données, el<strong>le</strong> contient <strong>le</strong>s variab<strong>le</strong>s <strong>du</strong> programme et est en généra<strong>le</strong> volati<strong>le</strong>.<br />

Le CPU lit <strong>le</strong>s instructions à partir <strong>de</strong> la mémoire programme et, en fonction <strong>de</strong> ces <strong>de</strong>rnières, traite <strong>le</strong>s<br />

variab<strong>le</strong>s (<strong>le</strong>cture et écriture), qui sont stockées dans la mémoire <strong>de</strong>s données ou <strong>le</strong>s composants<br />

périphériques.


2.2 Le Processeur<br />

Hardwarenahe Programmierung in C<br />

Le Processeur (CPU) est <strong>le</strong> cœur <strong>de</strong> l’ordinateur. Il contrô<strong>le</strong> <strong>le</strong> dérou<strong>le</strong>ment <strong>du</strong> programme et traite <strong>le</strong>s<br />

données. La Figure 4 illustre la structure généra<strong>le</strong> <strong>du</strong> CPU. Ce <strong>de</strong>rnier peut varier en fonction <strong>du</strong> type<br />

et <strong>du</strong> fabriquant <strong>de</strong> l’ordinateur.<br />

Bus <strong>de</strong> contrô<strong>le</strong><br />

Program-Counter<br />

Instruction<br />

Unit<br />

Unité <strong>de</strong> contrô<strong>le</strong><br />

Bus d’adresse<br />

Interface <strong>du</strong> bus<br />

Bus interne<br />

Figure 4 : Structure <strong>du</strong> CPU<br />

8 / 41<br />

Bus <strong>de</strong>s données<br />

Register<br />

Opéran<strong>de</strong><br />

ALU<br />

Résultat<br />

Unité <strong>de</strong> calcul<br />

L’unité <strong>de</strong> contrô<strong>le</strong> est responsab<strong>le</strong> <strong>de</strong> l’exécution <strong>du</strong> programme. Il est composé <strong>de</strong>s éléments<br />

suivants :<br />

• Instruction Unit (dispositif <strong>de</strong> comman<strong>de</strong>) : Il interprète <strong>le</strong>s instructions et est responsab<strong>le</strong> <strong>de</strong> <strong>le</strong>urs<br />

exécutions.<br />

• Program-Counter (PC): Il contient l’adresse <strong>de</strong> l’instruction suivante à exécuter, qui est stockée<br />

dans la mémoire programme.<br />

L’unité <strong>de</strong> calcul est responsab<strong>le</strong> <strong>du</strong> traitement <strong>de</strong>s données. Il contient <strong>le</strong>s composants suivants :<br />

• ALU (Arithmetic Logical Unit), qui exécute <strong>le</strong>s opérations arithmétiques et logiques. L’ALU<br />

n’exécute que <strong>de</strong>s opérations <strong>avec</strong> <strong>de</strong>s nombres entiers. Pour <strong>de</strong>s instructions à virgu<strong>le</strong> flottante ou<br />

<strong>de</strong>s instructions mathématiques plus comp<strong>le</strong>xes on emplois souvent un FPU (Floating Point Unit).<br />

• Les registres <strong>de</strong> données, qui sont <strong>de</strong>stinés aux stockages <strong>de</strong>s opéran<strong>de</strong>s et <strong>de</strong>s résultats <strong>de</strong>s<br />

opérations (accumulateur). Un registre est une case mémoire rapi<strong>de</strong>, qui se trouve à l’intérieure <strong>du</strong><br />

processeur. Ce <strong>de</strong>rnier peut être accédé directement, c’est à dire sans système <strong>de</strong> bus, par <strong>le</strong> CPU.<br />

Le bus interne relie <strong>le</strong>s unités <strong>de</strong> contrô<strong>le</strong>, <strong>de</strong> calcul et l’interface <strong>du</strong> bus. Les opérations, qui doivent<br />

être exécutés dans l’unité <strong>de</strong> calcul, sont définies par l’unité <strong>de</strong> contrô<strong>le</strong>. L’unité <strong>de</strong> calcul livre à son<br />

tour <strong>de</strong>s informations sur son état actuel à l’unité <strong>de</strong> contrô<strong>le</strong>. L’interface <strong>du</strong> bus est responsab<strong>le</strong> <strong>du</strong><br />

contrô<strong>le</strong> <strong>de</strong>s unités externes (mémoire et périphérie).


2.3 Le système <strong>de</strong> bus<br />

Hardwarenahe Programmierung in C<br />

2.3.1 Les bus d’adresse, <strong>de</strong> données et <strong>de</strong> contrô<strong>le</strong><br />

Différents bus relient <strong>le</strong> CPU aux composants externes. Ces bus permettent d’échanger <strong>de</strong>s<br />

informations concernant l’adresse et <strong>le</strong>s données <strong>de</strong>s variab<strong>le</strong>s.<br />

CPU<br />

Mémoire<br />

programme<br />

Bus d’adresse<br />

Bus <strong>de</strong> contrô<strong>le</strong><br />

Bus <strong>de</strong> données<br />

9 / 41<br />

Mémoire <strong>de</strong>s<br />

données<br />

Figure 5 : Bus d’adresse, <strong>de</strong> données et <strong>de</strong> contrô<strong>le</strong><br />

Périphérie<br />

Le bus d’adresse permet <strong>de</strong> transmettre <strong>le</strong>s adresses (pour la sé<strong>le</strong>ction <strong>de</strong>s cases<br />

mémoires) aux composants externes (mémoire et périphérie), qui sont connectés à <strong>le</strong><br />

CPU. Ces adresses sont déterminées par l’unité <strong>de</strong> contrô<strong>le</strong> <strong>de</strong> <strong>le</strong> CPU.<br />

Le bus <strong>de</strong> données permet <strong>de</strong> transmettre <strong>le</strong>s instructions et <strong>le</strong>s données <strong>du</strong><br />

programme. Ces <strong>de</strong>rnières sont<br />

a) lues par <strong>le</strong> CPU à partir <strong>de</strong>s composants <strong>de</strong> stockage externes (RAM ou ROM)<br />

ou périphériques.<br />

b) générées par <strong>le</strong> CPU et écrites dans <strong>le</strong>s composants <strong>de</strong> stockage externes ou<br />

périphériques.<br />

Le bus <strong>de</strong> contrô<strong>le</strong> permet <strong>de</strong> transmettre <strong>de</strong>s informations supplémentaires pour la<br />

gestion <strong>de</strong> la communication (read/write, reset, interrupts, requests et acknow<strong>le</strong>dge,<br />

handshake etc.).<br />

Avec qui?<br />

quoi?<br />

comment?<br />

Exemp<strong>le</strong> :<br />

Le fonctionnent <strong>du</strong> système <strong>de</strong> bus peut être illustré plus en détail, à l’ai<strong>de</strong> d’un transfert <strong>de</strong> données<br />

<strong>de</strong>puis la périphérie, en passant par <strong>le</strong> CPU, à la mémoire <strong>de</strong>s données. Exemp<strong>le</strong> : <strong>le</strong>cture <strong>de</strong> la<br />

température à l’ai<strong>de</strong> d’une son<strong>de</strong> x (périphéries) et stockage <strong>de</strong> cette <strong>de</strong>rnière dans la variab<strong>le</strong> "temp",<br />

qui se situe dans <strong>le</strong> RAM. En C cella serait définie <strong>de</strong> la manière suivante :<br />

int temp = Temperatur_Sensor_x;<br />

1) Le CPU dépose l’adresse <strong>de</strong> l’instruction à lire sur <strong>le</strong> bus d’adresse. Cette adresse est stockée dans<br />

<strong>le</strong> compteur <strong>de</strong> programme (Program counter).


Hardwarenahe Programmierung in C<br />

2) Le CPU fixe <strong>le</strong> sens <strong>du</strong> transfert « <strong>le</strong>cture », à l’ai<strong>de</strong> <strong>du</strong> bus <strong>de</strong> contrô<strong>le</strong>.<br />

3) La mémoire programme fournit l’instruction stockée dans la case mémoire, qui est sé<strong>le</strong>ctionnée<br />

par <strong>le</strong> bus d’adresse, sur <strong>le</strong> bus <strong>de</strong> donnée.<br />

4) Le CPU lit cette instruction.<br />

5) Le CPU fournit l’adresse <strong>du</strong> composant périphérique, à partir <strong>de</strong> laquel<strong>le</strong> <strong>le</strong>s données doivent être<br />

lues, sur <strong>le</strong> bus d’adresse.<br />

6) Le CPU fixe <strong>le</strong> sens <strong>du</strong> transfert « <strong>le</strong>cture », à l’ai<strong>de</strong> <strong>du</strong> bus <strong>de</strong> contrô<strong>le</strong>.<br />

7) La périphérie fournit l’information, contenue dans la case mémoire sé<strong>le</strong>ctionnée, sur <strong>le</strong> bus <strong>de</strong><br />

données.<br />

8) Le CPU lit <strong>le</strong>s données.<br />

9) Le CPU sé<strong>le</strong>ctionne la case <strong>de</strong> <strong>de</strong>stination « temp » dans la mémoire <strong>de</strong> donnée, à l’ai<strong>de</strong> <strong>du</strong> bus<br />

d’adresse.<br />

10) Le CPU fournit <strong>le</strong>s données sur <strong>le</strong> bus <strong>de</strong> données.<br />

11) Le CPU fixe <strong>le</strong> sens <strong>du</strong> transfert « écriture », à l’ai<strong>de</strong> <strong>du</strong> bus <strong>de</strong> contrô<strong>le</strong>.<br />

12) La mémoire <strong>de</strong>s données saisit <strong>le</strong>s données sur <strong>le</strong> bus <strong>de</strong> données, et <strong>le</strong>s stocke dans la case<br />

mémoire sé<strong>le</strong>ctionnée par <strong>le</strong> bus d’adresse.<br />

Bus<br />

d’adresse<br />

Bus <strong>de</strong><br />

données<br />

Bus <strong>de</strong><br />

contrô<strong>le</strong><br />

AMP<br />

1)<br />

RD<br />

DMP<br />

APE<br />

RD<br />

2) 3) 4) 5) 6)<br />

10 / 41<br />

DPE<br />

Figure 6 : Le timing <strong>du</strong> bus<br />

Les abréviations suivantes ont été utilisées dans la Figure précé<strong>de</strong>nte :<br />

AMP : Adresse <strong>de</strong> la mémoire programme<br />

APE : Adresse <strong>de</strong> la périphérie<br />

AMD : Adresse <strong>de</strong> la mémoire <strong>de</strong>s données<br />

DMP : Donnée <strong>de</strong> la mémoire programme<br />

DPE : Donnée <strong>de</strong> la périphérie<br />

DMD : Donnée <strong>de</strong> la mémoire <strong>de</strong>s données<br />

RD : Read, lire<br />

WR : Write, écrire<br />

De plus <strong>le</strong>s notations suivantes illustrent l’état <strong>de</strong> la tension <strong>du</strong> bus :<br />

AMD<br />

DMD<br />

WR<br />

7) 8) 9) 10) 11) 12)<br />

La tension <strong>du</strong> bus est stab<strong>le</strong> et valab<strong>le</strong>, el<strong>le</strong> est soit high ou low<br />

La tension <strong>du</strong> bus n’est pas valab<strong>le</strong> ("don't care")<br />

La tension <strong>du</strong> bus change


2.4 Domaine d’adressage<br />

Hardwarenahe Programmierung in C<br />

La mémoire d’un processeur est composée d’un certain nombre <strong>de</strong> cases mémoire, dont la tail<strong>le</strong><br />

correspond à 1 byte (8 bits). Toutes ces cases mémoire possè<strong>de</strong>nt une adresse distincte, qui s’étend <strong>de</strong><br />

0 jusqu’à la tail<strong>le</strong> <strong>de</strong> la mémoire -1.<br />

L’adresse est transmise <strong>de</strong> façon binaire à l’ai<strong>de</strong> <strong>du</strong> bus d’adresse. La largeur <strong>du</strong> bus d’adresse limite<br />

par conséquence la zone d’adressage. Par exemp<strong>le</strong>, <strong>avec</strong> 16 bits, il n’est possib<strong>le</strong> <strong>de</strong> générer que <strong>de</strong>s<br />

va<strong>le</strong>urs allant <strong>de</strong> 0 à 2 16 - 1. Ce qui correspond à une zone d’adressage <strong>de</strong> 64 kilo bytes (en<br />

informatique 1 kilo représente 1024). Avec 24 bits cette limite atteint 16M bytes (1 Méga correspond à<br />

1024 kilo). Alors qu’<strong>avec</strong> 32 bit, il est possib<strong>le</strong> d’adresser 4G bytes (1 Giga correspond à 1024 Méga).<br />

Toutefois, toutes <strong>le</strong>s cases mémoires adressab<strong>le</strong>s ne sont pas forcément disponib<strong>le</strong>s, car la zone<br />

d’adressage peut contenir <strong>de</strong>s lacunes, ou il n’y a rien.<br />

L’attribution effective <strong>de</strong>s zones d’adressage à la RAM, à la ROM et aux composants périphériques<br />

est fixée par <strong>le</strong> circuit é<strong>le</strong>ctronique. Un plan <strong>de</strong> mémoire permet d’illustrer ces zones mémoires. Un<br />

système microprocesseur contient généra<strong>le</strong>ment une ROM (composant, qui permet <strong>de</strong> stocker <strong>le</strong>s<br />

instructions <strong>du</strong> programme), une RAM (composant, qui permet <strong>de</strong> stocker <strong>le</strong>s données et <strong>le</strong>s variab<strong>le</strong>s)<br />

et <strong>de</strong>s éléments périphériques (composants, qui permettent <strong>de</strong> communiquer <strong>avec</strong> <strong>le</strong> mon<strong>de</strong> extérieur).<br />

Le système peut éga<strong>le</strong>ment contenir <strong>de</strong>s zones d’adressage vi<strong>de</strong>s, qui sont prévues pour <strong>le</strong>s éventuel<strong>le</strong>s<br />

extensions.<br />

Exemp<strong>le</strong> d’un plan <strong>de</strong> mémoire<br />

0xFFFFFF<br />

0xF80000<br />

0xF7FFFF<br />

0xF00000<br />

0xEFFFFF<br />

0xEFFFE0<br />

0xEFFFDF<br />

0xEFFF80<br />

0xEFFF7F<br />

0x028000<br />

0x027FFF<br />

0x020000<br />

0x01FFFF<br />

0x000400<br />

0x0003FF<br />

0x000000<br />

ROM<br />

Non utilisé<br />

Timer<br />

UART<br />

Non utilisé<br />

RAM<br />

(Alimenté par accu)<br />

RAM<br />

RAM<br />

(Tab<strong>le</strong> <strong>de</strong>s vecteur)<br />

Figure 7: Plan <strong>de</strong> mémoire<br />

La représentation <strong>du</strong> plan <strong>de</strong> mémoire s’effectue généra<strong>le</strong>ment à partir <strong>du</strong> bas, en commençant par<br />

l’adresse 0. Mais <strong>le</strong> plan <strong>de</strong> mémoire peut être éga<strong>le</strong>ment représenté dans l’autre sens.<br />

11 / 41


2.4.1 Le déco<strong>de</strong>ur d’adresse<br />

Hardwarenahe Programmierung in C<br />

La tâche <strong>du</strong> déco<strong>de</strong>ur d’adresse est <strong>de</strong> sé<strong>le</strong>ctionner un <strong>de</strong>s composants externes. Admettons par<br />

exemp<strong>le</strong> qu’un système à microcontrô<strong>le</strong>ur soit composé <strong>de</strong> plusieurs composants <strong>de</strong> stockage (RAM et<br />

ROM). Dans ce système, <strong>du</strong> bus d’adresse ne suffit pas pour sé<strong>le</strong>ctionner un <strong>de</strong>s composants. Par<br />

conséquent, il faut utiliser <strong>de</strong>s signaux <strong>de</strong> sé<strong>le</strong>ction (Chip Se<strong>le</strong>ct, CS) supplémentaires. Ces signaux<br />

sont fournis par <strong>le</strong> déco<strong>de</strong>ur d’adresse en fonction <strong>de</strong>s bits <strong>de</strong> poids plus fort <strong>du</strong> bus d’adresse.<br />

Les décodages d’adresse simp<strong>le</strong>s sont réalisés <strong>avec</strong> <strong>de</strong> la logique discrète (AND, OR ou 1 of X<br />

<strong>de</strong>co<strong>de</strong>r). Les composants nécessaires pour réaliser ce genre <strong>de</strong> déco<strong>de</strong>ur ne sont pas très chers.<br />

Toutefois, la logique discrète nécessite plus <strong>de</strong> place sur la platine et el<strong>le</strong> n’est pas f<strong>le</strong>xib<strong>le</strong>. Par<br />

conséquent, <strong>le</strong>s erreurs <strong>de</strong> conception ou <strong>le</strong>s éventuel<strong>le</strong>s adaptations <strong>du</strong> plan <strong>de</strong> mémoire nécessitent<br />

souvent une nouvel<strong>le</strong> platine.<br />

A cause <strong>de</strong>s problèmes <strong>de</strong> la logique discrète décrits ci-<strong>de</strong>ssus, <strong>le</strong>s déco<strong>de</strong>urs d’adresse sont souvent<br />

réalisés à l’ai<strong>de</strong> <strong>de</strong> la logique programmab<strong>le</strong> (GAL, PAL, CPLD etc.). Le déco<strong>de</strong>ur d’adresse<br />

correspondant au plan <strong>de</strong> mémoire <strong>de</strong> la Feh<strong>le</strong>r! Verweisquel<strong>le</strong> konnte nicht gefun<strong>de</strong>n wer<strong>de</strong>n. peut<br />

être réalisé <strong>de</strong> la manière suivante :<br />

Adresse<br />

Logique<br />

program.<br />

CS0<br />

CS1<br />

CS2<br />

CS3<br />

12 / 41<br />

Flash<br />

RAM 1<br />

RAM 2<br />

Périphérie<br />

Figure 8 : Déco<strong>de</strong>ur d’adresse programmab<strong>le</strong>


2.5 La mémoire<br />

2.5.1 Les technologies<br />

Hardwarenahe Programmierung in C<br />

Fondamenta<strong>le</strong>ment il existe <strong>le</strong>s mémoires non volati<strong>le</strong>s, qui sont utilisée uniquement en <strong>le</strong>cture, et <strong>le</strong>s<br />

mémoires volati<strong>le</strong>s, qui peuvent être utilisées en <strong>le</strong>cture ou en écriture.<br />

Mémoires non volati<strong>le</strong>s<br />

Ces mémoires conservent <strong>le</strong>ur contenu, même si <strong>le</strong>ur alimentation est coupée. Les différents types <strong>de</strong><br />

mémoire non volati<strong>le</strong> sont <strong>le</strong>s suivants :<br />

• ROM (Read Only Memory) : <strong>Programmation</strong> par <strong>le</strong> fabriquant à l’ai<strong>de</strong> <strong>de</strong> masques.<br />

• EPROM (Erasab<strong>le</strong> Programmab<strong>le</strong> ROM) : Ces mémoires peuvent être programmées plusieurs fois<br />

par l’utilisateur (outils <strong>de</strong> programmation spécifique) et effacés à l’ai<strong>de</strong> <strong>de</strong> rayon UV.<br />

• OTP (ou OTP ROM, One Time Programmab<strong>le</strong> ROM) : Ces mémoires sont construites comme <strong>le</strong>s<br />

EPROM, toutefois sans fenêtre. Les OTP ne peuvent être programmées qu’une seu<strong>le</strong> fois par<br />

l’utilisateur.<br />

• EEPROM (E<strong>le</strong>ctrical Erasab<strong>le</strong> Programmab<strong>le</strong> ROM) : Ces mémoires peuvent être effacées et<br />

reprogrammées case par case <strong>du</strong>rant <strong>le</strong>ur fonctionnement. Les EEPROM ont une capacité ré<strong>du</strong>ite<br />

(quelques kilos bytes) et sont, par conséquent, utilisées pour stocker <strong>le</strong>s données <strong>de</strong> pro<strong>du</strong>ction,<br />

comme par exemp<strong>le</strong> <strong>le</strong>s numéros <strong>de</strong> série etc.<br />

• FLASH (la définition exacte est FLASH EEPROM) : Ces mémoires peuvent être effacés<br />

é<strong>le</strong>ctriquement par bloque <strong>du</strong>rant <strong>le</strong>ur fonctionnement (pas <strong>de</strong> possibilité d’effacer uniquement <strong>de</strong>s<br />

cases, comme <strong>avec</strong> <strong>le</strong>s EEPROM). Les FLASH possè<strong>de</strong>nt une gran<strong>de</strong> capacité <strong>de</strong> stockage<br />

(quelques Mégas bytes) et sont, par conséquent, souvent utilisées pour stocker <strong>le</strong> co<strong>de</strong> <strong>du</strong><br />

programme.<br />

Mémoire volati<strong>le</strong><br />

Ces mémoires per<strong>de</strong>nt <strong>le</strong>ur contenu dès que <strong>le</strong>ur alimentation est coupée. Ces mémoires sont en<br />

généra<strong>le</strong> qualifiées <strong>de</strong> RAM (Random Access Memory). Random veut dire que <strong>le</strong>s cases mémoires<br />

peuvent être accédées <strong>de</strong> façon aléatoire. Il existe <strong>le</strong>s catégories suivantes :<br />

• DRAM (Dynamic RAM) : Ces mémoires stockent l’information à l’ai<strong>de</strong> <strong>de</strong> con<strong>de</strong>nsateur et<br />

doivent, par conséquent, être rafraîchies périodiquement.<br />

• SRAM (Static RAM) : Ces mémoires possè<strong>de</strong>nt une structure plus comp<strong>le</strong>xe que <strong>le</strong>s mémoires<br />

DRAM mais, par contre, el<strong>le</strong>s ne doivent pas être rafraîchies périodiquement. Les SRAM sont plus<br />

rapi<strong>de</strong>, nécessitent moins <strong>de</strong> courant et sont plus cher que <strong>le</strong>s DRAM.<br />

• SDRAM (Synchronous Dynamic RAM) : Ces mémoires sont une version ca<strong>de</strong>ncée <strong>de</strong>s DRAM. La<br />

fréquence d’horloge est prédéfinie par <strong>le</strong> bus <strong>du</strong> système. Chez <strong>le</strong>s DDR-SDRAM (Doub<strong>le</strong> Data<br />

Rate SDRAM), <strong>le</strong>s accès mémoires sont possib<strong>le</strong>s aux flans montant et aux flans <strong>de</strong>scendants <strong>de</strong><br />

l’horloge.<br />

Aujourd’hui il est éga<strong>le</strong>ment possib<strong>le</strong> <strong>de</strong> travail<strong>le</strong>r <strong>avec</strong> <strong>de</strong>s technologies RAM non volati<strong>le</strong> (FeRAM,<br />

MRAM). Toutefois, ces <strong>de</strong>rnières possè<strong>de</strong>nt une faib<strong>le</strong> capacité <strong>de</strong> stockage et sont relativement<br />

chères.<br />

13 / 41


2.5.2 L’organisation <strong>de</strong> la mémoire<br />

Hardwarenahe Programmierung in C<br />

Les mémoires sont organisées comme un Tab<strong>le</strong>au, qui contient <strong>de</strong>s cases mémoires. La largeur <strong>de</strong> ces<br />

cases dépend <strong>du</strong> type <strong>de</strong> la mémoire et correspond à 1, 8 ou 16 bits.<br />

La Figure suivante montre la structure d’une mémoire organisée en byte :<br />

Mémoire<br />

Adresse<br />

Byte<br />

La plus petite adresse<br />

0<br />

0<br />

1 7 0 1<br />

MSB LSB<br />

~ ~<br />

La plus gran<strong>de</strong> adresse n n<br />

Largeur <strong>de</strong> la mémoire<br />

(ici byte)<br />

Figure 9 : Structure d’une mémoire organisée en byte<br />

Le nombre <strong>de</strong> bit d’adresses, qui sont utilisés pour adresser la mémoire, dépend <strong>de</strong> la tail<strong>le</strong> <strong>de</strong> la<br />

mémoire. Avec m bits d’adresse, il est possib<strong>le</strong> d’adresser 2 m cases mémoires. Par exemp<strong>le</strong> <strong>avec</strong> 16<br />

bits d’adresses, il est possib<strong>le</strong> d’adresser un do maire <strong>de</strong> 64 k (ce qui est souvent utilisé <strong>avec</strong> <strong>de</strong><br />

microcontrô<strong>le</strong>ur à 8 bits).<br />

2.5.3 Les modè<strong>le</strong> <strong>de</strong> stockage et <strong>le</strong>s formats <strong>de</strong>s données<br />

La mémoire <strong>du</strong> microprocesseur est organisée <strong>de</strong> façon bytes. Ce qui veut dire, que <strong>le</strong>s variab<strong>le</strong>s à 16<br />

ou 32 bits doivent être stockées à l’ai<strong>de</strong> <strong>de</strong> plusieurs bytes. Il est recommandé <strong>de</strong> stocker <strong>le</strong>s va<strong>le</strong>urs 16<br />

bits à <strong>de</strong>s adresses paires et <strong>de</strong>s va<strong>le</strong>urs 32 bits à <strong>de</strong>s adresses multip<strong>le</strong>s <strong>de</strong> 4 (cela est même une<br />

obligation <strong>avec</strong> certain processeur). Ce qui permet d’effectuer <strong>le</strong>s opérations <strong>de</strong> <strong>le</strong>cture et d’écriture en<br />

une seu<strong>le</strong> étape <strong>avec</strong> <strong>de</strong>s bus <strong>de</strong> données <strong>de</strong> 16 ou <strong>de</strong> 32 bits.<br />

14 / 41


2.5.4 Litt<strong>le</strong> Endian / Big Endian<br />

Hardwarenahe Programmierung in C<br />

Il existe <strong>de</strong>ux formats <strong>de</strong> stockages <strong>de</strong>s va<strong>le</strong>urs, qui sont composées <strong>de</strong> plusieurs bytes. Avec <strong>le</strong> format<br />

petit boutiste (en anglais litt<strong>le</strong> endian), c’est toujours <strong>le</strong> byte <strong>de</strong> poids plus faib<strong>le</strong> qui est stocké en<br />

premier. Avec <strong>le</strong> format gros boutiste (en anglais big endian) c’est <strong>le</strong> contraire. Les figures suivantes<br />

illustres ces <strong>de</strong>ux formats <strong>de</strong> stockage <strong>avec</strong> <strong>le</strong>s processeurs 8, 16 et 32 bits :<br />

Microprocesseur 32 bits<br />

Litt<strong>le</strong> Endian<br />

15 / 41<br />

Big Endian<br />

Va<strong>le</strong>ur 32 bits (long) Va<strong>le</strong>ur 32 bits (long)<br />

Bit 0-7 Bit 8-15 Bit 16-23 Bit 24-32 Bit 24-32 Bit 16-23 Bit 8-15 Bit 0-7<br />

Microprocesseur 16 bits<br />

Litt<strong>le</strong> Endian<br />

Big Endian<br />

Va<strong>le</strong>ur 32 bits (long) Va<strong>le</strong>ur 32 bits (long)<br />

Bit 16-23 Bit 24-32 Bit 0-7 Bit 8-15 Bit 24-32 Bit 16-23 Bit 8-15 Bit 0-7<br />

Microprocesseur 8 bits<br />

Litt<strong>le</strong> Endian<br />

Big Endian<br />

Va<strong>le</strong>ur 32 bits (long) Va<strong>le</strong>ur 32 bits (long)<br />

Bit 24-32 Bit 16-23 Bit 8-15 Bit 0-7 Bit 24-32 Bit 16-23 Bit 8-15 Bit 0-7<br />

Figure 10 : Modè<strong>le</strong> <strong>de</strong> stockage et format <strong>de</strong> données


2.6 La périphérie<br />

Hardwarenahe Programmierung in C<br />

Les composants suivant sont considérés comme périphériques :<br />

a) Les composants qui permettent d’accé<strong>de</strong>r aux données <strong>de</strong> l’environnement <strong>du</strong> système. Ces<br />

données sont lues <strong>avec</strong> <strong>de</strong>s senseurs ou d’autre type d’interfaces.<br />

b) Les composants qui permettent <strong>de</strong> transmettre <strong>le</strong>s données à l’environnement <strong>du</strong> système. Ces<br />

données sont transmises <strong>avec</strong> <strong>de</strong>s actuateurs ou d’autres types d’interface.<br />

La périphérie représente l’interface entre <strong>le</strong> processeur et son environnement. Les composants<br />

périphériques sont en général connectés au bus <strong>du</strong> processeur.<br />

2.6.1 Les registres<br />

Les registres sont utilisés pour fixer <strong>le</strong> mo<strong>de</strong> <strong>de</strong> fonctionnement ou comme mémoire tampon pour <strong>le</strong>s<br />

va<strong>le</strong>urs d’entrée et <strong>de</strong> sortie <strong>de</strong>s composants périphériques. Ils forment donc l'interface entre <strong>le</strong><br />

processeur et sa périphérie.<br />

Un registre est un regroupement <strong>de</strong> cellu<strong>le</strong>s <strong>de</strong> stockage selon une certaine fonctionnalité. Ces <strong>de</strong>rniers<br />

sont <strong>le</strong> plus souvent réalisés <strong>avec</strong> <strong>de</strong>s flip-flops, ou parfois <strong>avec</strong> <strong>de</strong>s cellu<strong>le</strong>s DRAM.<br />

Figure 11 : Registre à 8 bits, réalisé <strong>avec</strong> <strong>de</strong>s flip-flops<br />

16 / 41


2.6.2 Les amplificateurs <strong>de</strong> sortie<br />

Hardwarenahe Programmierung in C<br />

Les signaux <strong>de</strong> sortie d’un chip, qui sont fournis à l’ai<strong>de</strong> <strong>de</strong>s pins, doivent être amplifiés. Il existe<br />

différents types d’amplificateur <strong>de</strong> sortie, dont <strong>le</strong> choix dépend <strong>de</strong> l’application.<br />

Port<br />

Out<br />

Totem-Po<strong>le</strong> Open Drain Tri state<br />

17 / 41<br />

Port<br />

Out<br />

Figure 12 : Amplificateur <strong>de</strong> sortie<br />

Les étages totem po<strong>le</strong><br />

Les étages totem po<strong>le</strong> fournissent toujours un signal à <strong>le</strong>ur sortie. Par conséquent, ils ne peuvent pas<br />

être connectés en parallè<strong>le</strong> !<br />

a) La logique low est représentée <strong>le</strong> plus souvent par « 0 »<br />

b) La logique high est représentée <strong>le</strong> plus souvent par « 1 »<br />

Open Drain<br />

Les sorties Open Drain (<strong>avec</strong> la technologie FET) ou Open Col<strong>le</strong>ctor (<strong>avec</strong> la technologie bipolaire)<br />

possè<strong>de</strong>nt un seul transistor, qui permet <strong>de</strong> tirer une résistance (Pull-up) contre la masse. Les<br />

résistances pull-up peuvent être sois internes ou externes. Les sorties Open Drain et Open Col<strong>le</strong>ctor<br />

peuvent être connectées en parallè<strong>le</strong>, comme par exemp<strong>le</strong> <strong>avec</strong> <strong>le</strong>s sources d’interruption :<br />

Tri state<br />

IRQx<br />

Pull<br />

up<br />

Source<br />

d’interrup.<br />

1<br />

Source<br />

d’interrup.<br />

2<br />

D<br />

Source<br />

d’nterrup.<br />

3<br />

Figure 13 : Source d’interruption <strong>avec</strong> <strong>de</strong>s sorties Open Drain<br />

Les sorties tri state peuvent avoir un état à haute impédance. L’état <strong>de</strong> sortie active ou « tri state » est<br />

activée à l’ai<strong>de</strong> d’un signal <strong>de</strong> contrô<strong>le</strong> supplémentaire (G).<br />

En généra<strong>le</strong> <strong>le</strong>s sorties, qui fournissent <strong>de</strong>s signaux sur un bus, sont réalisées <strong>avec</strong> <strong>de</strong>s tri states,<br />

comme par exemp<strong>le</strong> <strong>le</strong>s entrées et sorties <strong>de</strong>s données (I/O) d’une RAM.<br />

G<br />

Port<br />

Out


2.6.3 Les entrées et sorties digita<strong>le</strong>s<br />

Hardwarenahe Programmierung in C<br />

Les entrées et sorties digita<strong>le</strong>s sont utilisées respectivement pour la <strong>le</strong>cture et l’écriture <strong>de</strong>s signaux<br />

digita<strong>le</strong>s. Il existe <strong>de</strong>ux possibilités pour fournir <strong>de</strong>s entrées sorties digita<strong>le</strong>s :<br />

1) Utilisation <strong>de</strong> pins <strong>du</strong> microcontrô<strong>le</strong>ur, appelés GPIO (General Purpose Input Output). Le nombre<br />

<strong>de</strong> ces pins varie en fonction <strong>de</strong> la famil<strong>le</strong> <strong>de</strong>s microcontrô<strong>le</strong>urs. L’accès à ces <strong>de</strong>rniers s’effectue à<br />

l’ai<strong>de</strong> <strong>de</strong> registres.<br />

2) Utilisation <strong>de</strong> composants périphériques supplémentaires (FPGA, PIO, …), qui mettent à<br />

disposions <strong>de</strong>s I/O. La communication <strong>avec</strong> ces composants s’effectue <strong>avec</strong> <strong>le</strong> système <strong>de</strong> bus.<br />

Les entrées et sorties digita<strong>le</strong>s sont utilisées pour connecter <strong>le</strong>s éléments d’affichage (lampes, LED<br />

etc.), <strong>le</strong>s relais, <strong>le</strong>s moteurs, <strong>le</strong>s soupapes etc.<br />

Les sorties digita<strong>le</strong>s possè<strong>de</strong>nt souvent un étage d’amplification, afin qu’el<strong>le</strong>s puissent fournir <strong>le</strong><br />

courant nécessaire à la transmission (ex. contrô<strong>le</strong> <strong>de</strong>s moteurs, <strong>de</strong>s soupapes etc.). Les entrées digita<strong>le</strong>s<br />

possè<strong>de</strong>nt souvent <strong>de</strong>s filtrés (circuit RC et trigger <strong>de</strong> Schmitt). El<strong>le</strong>s sont éga<strong>le</strong>ment protégées contre<br />

<strong>le</strong>s sur tensions (comme par exemp<strong>le</strong> à l’ai<strong>de</strong> <strong>de</strong> dio<strong>de</strong>s Transzorb et <strong>de</strong>s varistances).<br />

Microcontrô<strong>le</strong>ur<br />

2.6.4 L’interface sériel<strong>le</strong><br />

GPIO1<br />

GPIO2<br />

…<br />

Contrô<strong>le</strong>ur <strong>de</strong><br />

moteur<br />

18 / 41<br />

Protection<br />

d’entrée<br />

Motor<br />

Interrupteur<br />

Figure 14 : Exemp<strong>le</strong> d’utilisation <strong>de</strong> GPIO<br />

Les interfaces sériel<strong>le</strong>s sont utilisées pour transmettre <strong>de</strong>s données <strong>de</strong> façon sériel<strong>le</strong> (ex. RS232, I 2 C,<br />

SPI, FireWire, USB etc.). Un registre à décalage est nécessaire pour convertir <strong>le</strong>s données, <strong>de</strong>puis <strong>le</strong><br />

format parallè<strong>le</strong> en séquence <strong>de</strong> bits, afin <strong>de</strong> pouvoir réaliser la transmission.<br />

Les propriétés <strong>le</strong>s plus importantes <strong>de</strong> la transmission sériel<strong>le</strong> sont <strong>le</strong>s suivants :<br />

• Le nombre <strong>de</strong> bit par secon<strong>de</strong> (baud rate)<br />

• La tension<br />

• Le protoco<strong>le</strong>


TxD RxD<br />

Hardwarenahe Programmierung in C<br />

19 / 41<br />

Signaux <strong>de</strong><br />

contrô<strong>le</strong><br />

Registre <strong>de</strong> transmission Registre <strong>de</strong> reception Registre <strong>de</strong> contrô<strong>le</strong><br />

2.6.5 Le port sériels RS232<br />

CPU<br />

Figure 15 : Principe <strong>de</strong> fonctionnement d’une interface sériel<strong>le</strong><br />

L’interface RS232 est très importante dans <strong>le</strong> domaine <strong>de</strong>s systèmes embarqués. Cette interface permet<br />

par exemp<strong>le</strong> <strong>de</strong> gérer un affichage LCD ou une ligne <strong>de</strong> comman<strong>de</strong> (Command Line Interface). La<br />

plupart <strong>de</strong>s microcontrô<strong>le</strong>urs possè<strong>de</strong>nt déjà une interface RS232. Toutefois, <strong>le</strong>s tensions <strong>de</strong> sortie <strong>de</strong><br />

ces <strong>de</strong>rnières correspon<strong>de</strong>nt au niveau TTL. Par conséquent, un convertisseur <strong>de</strong> tension externe doit<br />

être ajouté au système.<br />

Les bits <strong>de</strong> données sont transmis <strong>de</strong> façon sériel<strong>le</strong>. Le début <strong>de</strong> la transmission est marqué par un bit<br />

<strong>de</strong> démarrage, qui a la va<strong>le</strong>ur logique 0. Les bits <strong>de</strong> données sont transmis à la suite <strong>de</strong> ce bit <strong>de</strong><br />

démarrage, en commençant par <strong>le</strong> bit <strong>de</strong> poids <strong>le</strong> plus faib<strong>le</strong> (Least Signifiant Bit ≡ LSB). La fin <strong>de</strong> la<br />

transmission est marquée par un ou <strong>de</strong>ux bits d’arrêt, qui ont la va<strong>le</strong>ur logique 1. Un bit <strong>de</strong> parité peut<br />

être inséré en option entre <strong>le</strong> <strong>de</strong>rnier bit <strong>de</strong> donnée et <strong>le</strong> bit d’arrêt.<br />

Le canal <strong>de</strong> transmission possè<strong>de</strong> par défaut la va<strong>le</strong>ur logique 1. Ce qui permet <strong>de</strong> repérer <strong>le</strong> bit <strong>de</strong><br />

démarrage.<br />

La norme RS232 requiert pour <strong>le</strong> niveau logique 0, une tension <strong>de</strong> transmission <strong>de</strong> +12 V et pour <strong>le</strong><br />

niveau logique 1, une tension <strong>de</strong> transmission <strong>de</strong> - 12 V.<br />

La diagramme <strong>de</strong> la tension en fonction <strong>du</strong> temps est <strong>le</strong> suivant pour un exemp<strong>le</strong> quelconque :<br />

Tension<br />

+12V<br />

-12V<br />

1<br />

0 1 0 1 1 0 1 0 0 1<br />

Start D0 D1 D2 D3 D4 D5 D6 D7 Stop<br />

Figure 16 : Transmission <strong>de</strong> donnée selon RS232<br />

Temp


Hardwarenahe Programmierung in C<br />

Le schéma bloc <strong>de</strong> l’interface RS232 est typiquement <strong>le</strong> suivant :<br />

Internal Bus<br />

Control<br />

Unit<br />

Transmit FIFO<br />

Transmit Shifter<br />

Baudrate<br />

Generator<br />

Receive Shifter<br />

Receive FIFO<br />

20 / 41<br />

Transmitter<br />

Receiver<br />

Transmit Holding Register<br />

Receive Holding Register<br />

Figure 17 : Schéma bloc d’une interface RS232 commercia<strong>le</strong><br />

La connexion entre un émetteur et un récepteur nécessite <strong>de</strong>ux lignes <strong>de</strong> connexion, une ligne <strong>de</strong><br />

données et une ligne <strong>de</strong> masse. Une ligne supplémentaire est nécessaire pour une communication dans<br />

<strong>le</strong>s <strong>de</strong>ux sens. Ces connexions sont désignées <strong>avec</strong> <strong>le</strong>s abréviations suivantes : GND pour la masse (pin<br />

numéro 5), TXD pour la sortie <strong>de</strong>s données (pin numéro 3) et RXD pour l’entrée <strong>de</strong>s données (pin<br />

numéro 2). Les numéros <strong>de</strong> pin correspon<strong>de</strong>nt à ceux d’un connecteur RS232 à 9 broches (voir figure<br />

17). Il faut toujours transposer TXD <strong>de</strong> l’émetteur <strong>avec</strong> RXD <strong>du</strong> récepteur.<br />

L’interface sériel<strong>le</strong> possè<strong>de</strong> éga<strong>le</strong>ment d’autres lignes <strong>de</strong> comman<strong>de</strong>, qui ne sont pas décrites dans ce<br />

document. Ces lignes <strong>de</strong> comman<strong>de</strong> sont utilisées pour <strong>le</strong> « handshaking », et permettent <strong>de</strong> stopper<br />

l’émetteur lorsque <strong>le</strong>s données arrivent trop rapi<strong>de</strong>ment. Le handshaking peut être désactivé à l’ai<strong>de</strong> <strong>du</strong><br />

co<strong>de</strong> ou par transposition <strong>de</strong>s lignes <strong>de</strong> contrô<strong>le</strong>.<br />

L’émetteur et <strong>le</strong> récepteur doivent utiliser <strong>le</strong> même format <strong>de</strong> transmission afin qu’ils puissent se<br />

comprendre. Ce qui veut dire que <strong>le</strong> nombre <strong>de</strong> bits par secon<strong>de</strong> (Baud rate), <strong>le</strong> nombre <strong>de</strong> bits <strong>de</strong><br />

données à transmettre et <strong>le</strong> mo<strong>de</strong> <strong>de</strong> parité doivent être configuré <strong>de</strong> la même manière.<br />

TxD<br />

RxD


2.6.6 SPI<br />

Hardwarenahe Programmierung in C<br />

Figure 18: Connecteur à 9 pô<strong>le</strong>s<br />

L’interface SPI (Serial Peripheral Interface) est un système <strong>de</strong> bus sériel à haut débit, <strong>de</strong>stiné à la<br />

communication entre <strong>le</strong> microcontrô<strong>le</strong>ur et la périphérie. Ce <strong>de</strong>rnier est souvent utilisé pour la<br />

communication <strong>avec</strong> <strong>de</strong>s extensions I/O, <strong>de</strong>s affichages LCD ainsi que <strong>de</strong>s convertisseurs A/D et D/A.<br />

Il peut éga<strong>le</strong>ment être utilisé pour la communication entre microcontrô<strong>le</strong>urs.<br />

La Figure 19 montre <strong>le</strong> principe <strong>de</strong> fonctionnement <strong>du</strong> SPI.<br />

Entré <strong>de</strong>s données<br />

en parallè<strong>le</strong><br />

7 0<br />

Sortie <strong>de</strong>s données<br />

en parallè<strong>le</strong><br />

Participant 1<br />

Générateur <strong>de</strong> la<br />

fréquence d’horloge<br />

Figure 19 : Principe <strong>du</strong> SPI<br />

21 / 41<br />

Entré <strong>de</strong>s données<br />

en parallè<strong>le</strong><br />

7 0<br />

Sortie <strong>de</strong>s données<br />

en parallè<strong>le</strong><br />

Participant n<br />

L’interface SPI est toujours utilisée en mo<strong>de</strong> maître esclave. Le maître est alors responsab<strong>le</strong> <strong>de</strong> la<br />

génération <strong>de</strong> la fréquence d’horloge. Le SPI peut travail<strong>le</strong>r <strong>de</strong> façon <strong>du</strong>p<strong>le</strong>xe à l’ai<strong>de</strong> <strong>de</strong> <strong>de</strong>ux lignes<br />

<strong>de</strong> transmission : MOSI (Master Out Slave In) et MISO (Master In Slave Out). Les esclaves peuvent<br />

être connectés soit <strong>de</strong> façon parallè<strong>le</strong> (c’est à dire que toutes <strong>le</strong>s sorties <strong>de</strong>s esclaves sont rassemblée et<br />

connectées à l’entré MISO <strong>du</strong> maître) ou <strong>de</strong> façon sériel<strong>le</strong> (la sorite d’un esclave est connectée à<br />

l’entrée <strong>du</strong> prochain esclave et la sortie <strong>du</strong> <strong>de</strong>rnier esclave est connecté à l’entrée MISO <strong>du</strong> maître).


Hardwarenahe Programmierung in C<br />

Le microcontrô<strong>le</strong>ur écrit <strong>le</strong>s données à transmettre dans un tampon <strong>de</strong> transmission. Ces <strong>de</strong>rnières sont<br />

sérialisées à l’ai<strong>de</strong> d’un registre à décalage (comme une transmission RS232). Les données reçues sont<br />

éga<strong>le</strong>ment converties à l’ai<strong>de</strong> d’un registre à décalage. Le microcontrô<strong>le</strong>ur peut alors lire ces données<br />

<strong>de</strong> façon parallè<strong>le</strong> dans <strong>le</strong> tampon <strong>de</strong> réception. Du fait que <strong>le</strong>s interfaces SPI ont une ban<strong>de</strong> passante<br />

relativement é<strong>le</strong>vé, <strong>le</strong>s tampons <strong>de</strong> transmission et <strong>de</strong> réception contiennent souvent plusieurs bytes.<br />

Sé<strong>le</strong>ction<br />

esclave<br />

SPI maître<br />

Esclave SPI 2<br />

Horloge<br />

Donnée<br />

Registre à<br />

décalage<br />

FIFO <strong>de</strong><br />

réception<br />

2.7 Les convertisseurs A/D<br />

22 / 41<br />

Registre à<br />

décalage<br />

Donnée<br />

Registre à<br />

décalage<br />

Esclave SPI 1<br />

FIFO <strong>de</strong><br />

tansmission<br />

Figure 20 : SPI <strong>avec</strong> un maître <strong>de</strong> <strong>de</strong>ux esclaves<br />

MOSI<br />

MISO<br />

SCK<br />

Les convertisseurs A/D mesure une tension analogue à <strong>le</strong>ur entrée, compare cette va<strong>le</strong>ur <strong>avec</strong> une<br />

tension <strong>de</strong> référence afin <strong>de</strong> fournir une va<strong>le</strong>ur digita<strong>le</strong>. Le microcontrô<strong>le</strong>ur peut lire cette va<strong>le</strong>ur soit à<br />

l’ai<strong>de</strong> <strong>du</strong> système <strong>de</strong> bus ou <strong>avec</strong> une interface sériel (comme par exemp<strong>le</strong> <strong>le</strong> SPI).<br />

Les convertisseurs A/D possè<strong>de</strong>nt souvent plusieurs entrées analogues, qui peuvent être sé<strong>le</strong>ctionnées<br />

à l’ai<strong>de</strong> d’un multip<strong>le</strong>xeur.<br />

Les caractéristiques <strong>le</strong>s plus importants pour un convertisseur A/D sont <strong>le</strong>s suivants:<br />

• Largeur <strong>de</strong> bit (<strong>le</strong>s va<strong>le</strong>urs typiques sont 8, 10, 12 ou 16 bits)<br />

• Temps <strong>de</strong> conversion


Analog Inputs<br />

MUX<br />

Hardwarenahe Programmierung in C<br />

S&H<br />

23 / 41<br />

VREF<br />

A/D<br />

Converter<br />

Control-Register Data-Register<br />

CPU<br />

Figure 21 : Schéma bloc d’un convertisseur A/D


Hardwarenahe Programmierung in C<br />

3 La famil<strong>le</strong> <strong>de</strong>s microcontrô<strong>le</strong>urs C8051F2xx<br />

La famil<strong>le</strong> 8051 est la famil<strong>le</strong> la plus connue et la plus répan<strong>du</strong>e <strong>de</strong>s contrô<strong>le</strong>urs 8 bits. Plusieurs<br />

fabricants fournissent <strong>de</strong>s dérivées <strong>de</strong> ce microcontrô<strong>le</strong>ur, qui se distinguent par <strong>le</strong>urs mo<strong>du</strong><strong>le</strong>s<br />

périphériques. Le 8031 d’INTEL est considéré ici comme étant <strong>le</strong> précurseur.<br />

Tous <strong>le</strong>s microcontrô<strong>le</strong>urs <strong>de</strong> la famil<strong>le</strong> C8051F2xx, qui sont pro<strong>du</strong>it par « Silicon Laboratories »,<br />

possè<strong>de</strong>nt <strong>le</strong> cœur 8051. Les opérations arithmétiques et logiques y sont effectuées sur 8 bits. Cette<br />

famil<strong>le</strong> <strong>de</strong> microcontrô<strong>le</strong>ur possè<strong>de</strong> éga<strong>le</strong>ment 8 kilo bytes <strong>de</strong> mémoire flash, 256 ou éventuel<strong>le</strong>ment<br />

1280 bytes <strong>de</strong> RAM et <strong>de</strong>s interfaces sériel<strong>le</strong>s (UART et SPI). Quant aux différents packages, ils sont<br />

composés <strong>de</strong> 22 à 32 pins d’entrée sortie, dont certains peuvent être assignés aux mo<strong>du</strong><strong>le</strong>s<br />

périphériques (UART, SPT etc.).<br />

Certaine version <strong>de</strong> la famil<strong>le</strong> C8051F possè<strong>de</strong>nt éga<strong>le</strong>ment <strong>de</strong>s convertisseurs analogique digita<strong>le</strong><br />

(CAD). Tous <strong>le</strong>urs pins d’entrée sortie peuvent être configurés comme entrée analogique pour ces<br />

convertisseurs.<br />

Figure 22: Les différents processeurs <strong>de</strong> la famil<strong>le</strong> C8051F2xx<br />

24 / 41


3.1 Le cœur <strong>du</strong> C8051F2xx<br />

Hardwarenahe Programmierung in C<br />

Le cœur <strong>de</strong>s microcontrô<strong>le</strong>urs <strong>de</strong> la famil<strong>le</strong> C8051F2xx est composé <strong>de</strong>s composants suivants :<br />

1) CPU (8051 Core)<br />

2) 8 kilo bytes <strong>de</strong> mémoire flash<br />

3) 256 bytes <strong>de</strong> SRAM plus éventuel<strong>le</strong>ment 1024 bytes <strong>de</strong> XRAM<br />

4) Des interfaces sériel<strong>le</strong>s (UART et SPI)<br />

5) Trois compteurs 16 bits (Timer 0, Timer 1 et Timer2)<br />

6) Un comparateur <strong>de</strong> tension et un convertisseur AD en option<br />

7) 128 bytes <strong>de</strong> registres <strong>de</strong> configuration (Special Function Register : SFR)<br />

8) Quatre ports d’entrée sortie <strong>de</strong> 8 pins chacun<br />

Un bus interne relie <strong>le</strong> CPU <strong>avec</strong> <strong>le</strong>s différents composants <strong>de</strong> stockage et un bus SFR relie <strong>le</strong> CPU<br />

<strong>avec</strong> <strong>le</strong>s registres <strong>de</strong> configuration.<br />

Figure 23 : Schéma bloc <strong>du</strong> contrô<strong>le</strong>ur C8051F2xx<br />

25 / 41


Hardwarenahe Programmierung in C<br />

3.2 La mémoire <strong>du</strong> C08051F2xx<br />

La mémoire vive <strong>du</strong> C8051F2xx est composée <strong>de</strong> 256 bytes. La zone d’adressage supérieure <strong>de</strong> cette<br />

mémoire est partagée entre <strong>le</strong>s registres <strong>de</strong> configuration (Special Function Register) et la SRAM. Le<br />

mo<strong>de</strong> d’adressage permet d’y différencier l’accès. L’adressage direct permet ainsi à accé<strong>de</strong>r aux<br />

registres <strong>de</strong> configuration et l’adressage indirect à la RAM. Les 32 bytes <strong>de</strong> la zone d’adressage<br />

inférieure sont composés <strong>de</strong> 4 jeux <strong>de</strong> registres fantômes (banked register) d’utilité généra<strong>le</strong>, et <strong>le</strong>s 16<br />

bytes suivants peuvent être adressé à la fois <strong>de</strong> façon byte et bit. Une mémoire vive externe <strong>de</strong> 1024<br />

bytes est éga<strong>le</strong>ment mise à disposition en option <strong>avec</strong> <strong>le</strong>s famil<strong>le</strong>s F206, F226 et F236.<br />

La mémoire programme est composée <strong>de</strong> <strong>de</strong>ux mémoires flash <strong>de</strong> 8 kilos et 128 bytes. La zone<br />

mémoire entre 0x1E00 et 0x1FFF est réservée pour <strong>le</strong> fabricant. La figure suivante illustre <strong>le</strong> plan <strong>de</strong><br />

mémoire <strong>de</strong>s composants <strong>de</strong> stockage :<br />

Figure 24 : plan <strong>de</strong> mémoire <strong>de</strong>s microcontrô<strong>le</strong>urs <strong>de</strong> la famil<strong>le</strong> C8051F2xx<br />

26 / 41


3.3 L’interface JTAG<br />

Hardwarenahe Programmierung in C<br />

Les contrô<strong>le</strong>urs <strong>de</strong> la famil<strong>le</strong> C8051F2xx possè<strong>de</strong>nt une interface JTAG et <strong>de</strong> la logique <strong>de</strong> déboguage,<br />

qui permettent <strong>de</strong> développer et tester <strong>le</strong>s applications en temps réel.<br />

Les applications peuvent ainsi être programmées à l’ai<strong>de</strong> d’environnements <strong>de</strong> <strong>développement</strong><br />

mo<strong>de</strong>rne sur <strong>le</strong>s PC. Ensuite el<strong>le</strong>s peuvent être téléchargées sur <strong>le</strong>s cartes <strong>de</strong> <strong>développement</strong> afin d’y<br />

être testées en temps réel. Ces testes peuvent être éga<strong>le</strong>ment effectuées pas à pas à l’ai<strong>de</strong> <strong>de</strong> points<br />

d’arrêt. Ces <strong>de</strong>rniers peuvent être insérés à n’importe quel endroit dans <strong>le</strong> programme et permettent,<br />

comme <strong>le</strong>ur nom l’indique, d’arrêter momentanément l’exécution <strong>du</strong> programme.<br />

La Figure 25 montre la connexion entre <strong>le</strong> PC et la carte <strong>de</strong> développent à l’ai<strong>de</strong> d’un adaptateur sériel,<br />

dont <strong>le</strong> rô<strong>le</strong> est <strong>de</strong> convertir uniquement <strong>le</strong> format <strong>du</strong> signal <strong>de</strong> déboguage, <strong>de</strong>puis RS323 à JTAG.<br />

Figure 25 : Environnement <strong>de</strong> <strong>développement</strong> <strong>de</strong> “Silicon Laboratories”<br />

27 / 41


Hardwarenahe Programmierung in C<br />

3.4 Les entrées et <strong>le</strong> sorties <strong>du</strong> C08051F2xx<br />

Tous <strong>le</strong>s contrô<strong>le</strong>urs <strong>de</strong> la famil<strong>le</strong> 8051 possè<strong>de</strong>nt 4 ports standards, contenant chacun 8 pins. L’étage<br />

d’amplification <strong>de</strong> sortie <strong>de</strong> ces pins peut être configuré soit comme « push pull » ou « open drain ».<br />

Les composants digitaux (<strong>le</strong> timer, l’horloge <strong>du</strong> système, <strong>le</strong> comparateur <strong>de</strong> tension, <strong>le</strong> convertisseur<br />

AD, <strong>le</strong>s interfaces sériels SPI et UART,) peuvent être connectés à <strong>le</strong>urs pins à l’ai<strong>de</strong> <strong>de</strong> multip<strong>le</strong>xeurs.<br />

Ces multip<strong>le</strong>xeur peuvent être configuré à l’ai<strong>de</strong> <strong>de</strong> registres <strong>de</strong> configuration (Special Function<br />

Register : SFR).<br />

Un multip<strong>le</strong>xeur (en abrégé: MUX) est un circuit <strong>de</strong> commutation, qui permet <strong>de</strong> sé<strong>le</strong>ctionner un<br />

signal parmi un certain nombre <strong>de</strong> signaux (comme par exemp<strong>le</strong>, pour <strong>le</strong>s accès aux cases mémoire ou<br />

la sé<strong>le</strong>ction analogique ou numérique <strong>de</strong>s canaux d’entrée).<br />

Les mo<strong>de</strong>s d’entrée <strong>de</strong>s 32 pins peuvent être configurés soit en analogique ou en numérique (voir<br />

Figure 26).<br />

Figure 26 : Schéma bloque <strong>de</strong>s entrées et <strong>de</strong>s sorties<br />

28 / 41


Hardwarenahe Programmierung in C<br />

3.5 Les ports sériels <strong>du</strong> C08051F2xx<br />

Les microcontrô<strong>le</strong>urs <strong>de</strong>s famil<strong>le</strong>s C8051F206, C8051F220/1/6 et C8051F230/1/6 possè<strong>de</strong>nt un<br />

UART, capab<strong>le</strong> <strong>de</strong> transmettre en mo<strong>de</strong> <strong>du</strong>p<strong>le</strong>xe, et un bus sériel <strong>du</strong> type SPI. Tous <strong>le</strong>s <strong>de</strong>ux bus sont<br />

implémentés en <strong>hardware</strong> et sont en mesure <strong>de</strong> générer <strong>de</strong>s interruptions. Ce qui permet <strong>de</strong> ré<strong>du</strong>ire au<br />

minimum <strong>le</strong>s interventions <strong>de</strong> <strong>le</strong> CPU. De plus, <strong>le</strong>s <strong>de</strong>ux buses ne partagent pas <strong>le</strong>s mêmes ressources<br />

<strong>hardware</strong>, comme par exemp<strong>le</strong> <strong>le</strong>s timers, <strong>le</strong>s interruptions ou <strong>le</strong>s ports d’entrée sortie. Ils peuvent par<br />

conséquent être utilisés simultanément (la fréquence d’horloge pour la transmission UART peut être<br />

générée soit <strong>avec</strong> <strong>le</strong> Timer1, <strong>le</strong> Timer2 ou <strong>le</strong> SYSCLK).<br />

3.6 Le convertisseur analogique - digita<strong>le</strong> <strong>du</strong> C08051F2xx<br />

Le C8051F220/1/6 possè<strong>de</strong> un convertisseur AD <strong>de</strong> 8 bis. La fréquence <strong>de</strong> conversion maxima<strong>le</strong> est <strong>de</strong><br />

100 kilo échantillons par secon<strong>de</strong>. La tension <strong>de</strong> référence peut soit être la tension d’alimentation ou<br />

une référence externe (VREF). Le système peut désactiver <strong>le</strong> convertisseur afin d’entrer dans un mo<strong>de</strong><br />

d’économie d’énergie. Un amplificateur à gain programmab<strong>le</strong> permet d’amplifier <strong>le</strong> signal <strong>du</strong><br />

multip<strong>le</strong>xeur. Les facteurs d’amplification peuvent être définis <strong>de</strong> 0.5 à 16 par pas <strong>de</strong> puissance <strong>de</strong> 2.<br />

La conversion peut être démarrée <strong>de</strong> <strong>de</strong>ux façons ; soit par comman<strong>de</strong> software ou <strong>avec</strong> <strong>le</strong> Timer2. Ce<br />

qui permet <strong>de</strong> démarrer <strong>le</strong>s conversions soit <strong>avec</strong> <strong>de</strong>s évènements <strong>du</strong> type software ou <strong>de</strong> façon<br />

continue. La fin <strong>de</strong> la conversion peut être marqué soit à l’ai<strong>de</strong> d’une interruption ou <strong>avec</strong> un bit d’état.<br />

Le résultat <strong>de</strong> la conversion peut alors être lu à partir d’un registre <strong>de</strong> configuration.<br />

Figure 27 : Le convertisseur AD <strong>de</strong>s microcontrô<strong>le</strong>urs C8051F220/1/6<br />

29 / 41


Hardwarenahe Programmierung in C<br />

4 La programmation <strong>proche</strong> <strong>du</strong> <strong>hardware</strong><br />

Lorsque que l’on veut définir un programme pour micro contrô<strong>le</strong>ur, il <strong>de</strong>vient alors primordial <strong>de</strong><br />

pouvoir accé<strong>de</strong>r directement au <strong>hardware</strong>. En effet, <strong>le</strong>s diverses fonctionnalités <strong>de</strong>s composants<br />

<strong>hardware</strong> ne peuvent être définie qu’<strong>avec</strong> <strong>de</strong>s registres <strong>de</strong> configurations. Ces registres sont <strong>de</strong>s cases<br />

mémoires, qui possè<strong>de</strong>nt <strong>de</strong>s adresses prédéfinies. C'est-à-dire qu’ils occupent certaines zones <strong>du</strong> plan<br />

<strong>de</strong> mémoire comme <strong>le</strong>s mémoires RAM et ROM. La fonctionnalité et la signification <strong>de</strong> ces registres<br />

sont fournies par la documentation <strong>du</strong> microcontrô<strong>le</strong>ur.<br />

La Figure 28 décrit par exemp<strong>le</strong> <strong>le</strong> registre <strong>de</strong> configuration « PRT0MX », qui contient 8 bits. Ces<br />

<strong>de</strong>rniers permettent <strong>de</strong> définir la fonctionnalité <strong>de</strong>s 8 pins d’entrée sortie <strong>du</strong> port 0.<br />

4.1 L’adressage direct<br />

Figure 28 : Description <strong>du</strong> registre <strong>de</strong> configuration PRT0MX<br />

Dans <strong>le</strong> mo<strong>de</strong> d'adressage direct, l’accès aux cases mémoire s’effectue en indiquant <strong>le</strong>ur nom<br />

symbolique. Les variab<strong>le</strong>s <strong>du</strong> type registre permettent <strong>de</strong> réaliser ce type d’adressage. Ces <strong>de</strong>rnières<br />

sont définies <strong>avec</strong> <strong>de</strong>s mots clés spécifiques à l’environnement <strong>de</strong> <strong>développement</strong>, qui ne font pas<br />

partie <strong>du</strong> standard ANSI-C.<br />

L’exemp<strong>le</strong> suivant montre la définition et l’utilisation d’une variab<strong>le</strong> <strong>du</strong> type registre dans<br />

l’environnement <strong>de</strong> <strong>développement</strong> « Silicon Laboratories ».<br />

30 / 41


Hardwarenahe Programmierung in C<br />

/***********************************************/<br />

/* Definition of the register variab<strong>le</strong> PRT0MX */<br />

/* with the key word sfr. */<br />

/* The initialisation value 0xE1 corresponds */<br />

/* here to its address within the memory map! */<br />

/***********************************************/<br />

sfr PRT0MX = 0xE1;<br />

/***********************************************/<br />

/* Direct access to the register variab<strong>le</strong> */<br />

/* Set the functionality of Port0 to IO */<br />

/***********************************************/<br />

PRT0MX = 0x00;<br />

4.2 L’adressage indirect<br />

Dans <strong>le</strong> mo<strong>de</strong> d'adressage indirect, l’accès aux cases mémoire s’effectue en indiquant <strong>le</strong>ur adresse.<br />

Cette <strong>de</strong>rnière est copiée dans un registre spécial <strong>du</strong> processeur, dont la tail<strong>le</strong> est i<strong>de</strong>ntique à cel<strong>le</strong> <strong>du</strong><br />

bus d'adresses. Les pointeurs permettent <strong>de</strong> réaliser ce type d’adressage selon <strong>le</strong> standard ANSI-C.<br />

L'avantage, par rapport à l'adressage direct, est que l'adresse peut être manipulée, comme par exemp<strong>le</strong><br />

pour accé<strong>de</strong>r à une suite <strong>de</strong> données consécutives en mémoire. Ceci est particulièrement uti<strong>le</strong> lorsqu'on<br />

manipu<strong>le</strong> <strong>de</strong>s données stockées dans un tab<strong>le</strong>au.<br />

L’environnement <strong>de</strong> <strong>développement</strong> <strong>du</strong> C8051F2xx contient <strong>le</strong>s types <strong>de</strong> données suivants : char 8<br />

bits, short int 16 bits, et long 32 bits. Les registres 8 bits peuvent ainsi être adressés <strong>avec</strong> un<br />

pointeur <strong>du</strong> type unsigned char, <strong>le</strong>s registres 16 bits <strong>avec</strong> un pointeur <strong>du</strong> type unsigned<br />

short int et <strong>le</strong>s registres 32 bits <strong>avec</strong> un pointeur unsigned long.<br />

Les exemp<strong>le</strong>s suivants permettent d’écrire la va<strong>le</strong>ur 0x12 à l’adresse 0x00F1 (qui pourrait<br />

représenter <strong>le</strong> port parallè<strong>le</strong> d’un composant externe).<br />

Compact<br />

*((unsigned char *) 0x00F1) = 0x12;<br />

/* Convert the value 0x00F1 into an address and acce<strong>de</strong> to it */<br />

Via pointeur<br />

/* Definition of the pointer variab<strong>le</strong> */<br />

unsigned char *Paral<strong>le</strong>lport;<br />

/* Inisialisation of the pointeur with the address 0x00F1 */<br />

Paral<strong>le</strong>lport = (unsigned char *) 0x00F1;<br />

/* Write the value into the memory case,<br />

which is addressed by the pointer */<br />

*Paral<strong>le</strong>lport = 0x12;<br />

Avec une macro<br />

/* Definition of the macro instruction,<br />

which could be done in a hea<strong>de</strong>r fi<strong>le</strong> */<br />

#<strong>de</strong>fine Paral<strong>le</strong>lport *((unsigned char *) 0x00F1)<br />

/* Call the macro */<br />

Paral<strong>le</strong>lport = 0x12;<br />

31 / 41


Hardwarenahe Programmierung in C<br />

4.3 Mise à un et mise à zéro <strong>de</strong>s bits dans <strong>le</strong>s registres<br />

Les mises à un et <strong>le</strong>s mises à zéro ciblées <strong>de</strong>s bits dans un registre peut être réalisées <strong>avec</strong> <strong>le</strong>s<br />

opérateurs logiques standards (et ‘&’, ou ‘|’, ou exclusif binaire ‘^’ et inverser ‘~’). Ces opérateurs<br />

permettent d'effectuer <strong>de</strong>s opérations au niveau <strong>de</strong>s bits.<br />

Dans l’exemp<strong>le</strong> suivant, <strong>le</strong> bit 4 <strong>du</strong> registre <strong>de</strong> configuration PRT0MX est d’abord mis à un et ensuite<br />

remis à zéro.<br />

/***********************************************/<br />

/* Configure pin 0.4 for the timer 0 */<br />

/* Set the bit 4 of PRT0MX */<br />

/***********************************************/<br />

PRT0MX = PRT0MX | 0x40;<br />

/***********************************************/<br />

/* Configure pin 0.4 as standard IO */<br />

/* C<strong>le</strong>ar the bit 4 of PRT0MX */<br />

/***********************************************/<br />

PRT0MX = PRT0MX & ~0x40;<br />

4.4 Désactivation <strong>de</strong>s optimisations <strong>du</strong> compilateur<br />

Tous <strong>le</strong>s compilateurs essayent <strong>de</strong> générer un co<strong>de</strong>, qui est <strong>le</strong> plus optimal possib<strong>le</strong>. Cette optimisation<br />

comprend entre autre l’élimination <strong>de</strong> co<strong>de</strong> superflu ou redondant. ANSII C met à disposition <strong>le</strong> mot<br />

clé volati<strong>le</strong> afin <strong>de</strong> désactiver ces optimisations. volati<strong>le</strong> est par conséquent très uti<strong>le</strong> pour<br />

l’accès direct <strong>hardware</strong> ou pour <strong>le</strong>s interruptions.<br />

4.4.1 Exemp<strong>le</strong><br />

Le co<strong>de</strong> suivant :<br />

whi<strong>le</strong> (Paral<strong>le</strong>lport == 0) {<br />

i++; /* wait until the paral<strong>le</strong>l port is ready */<br />

}<br />

peut être optimisé par <strong>le</strong> compilateur <strong>de</strong> la manière suivante :<br />

if (Paral<strong>le</strong>lport == 0) { /* test if paral<strong>le</strong>l port is read*/<br />

whi<strong>le</strong> (1) {<br />

i++; /* if yes, then never ending loop */<br />

}<br />

}<br />

Le compilateur optimise <strong>le</strong> co<strong>de</strong> <strong>de</strong> ci-<strong>de</strong>ssus afin <strong>de</strong> ré<strong>du</strong>ire <strong>de</strong> nombre d'accès à la variab<strong>le</strong><br />

Paral<strong>le</strong>lport. Ce qui permet d’améliorer considérab<strong>le</strong>ment la vitesse d’exécution <strong>du</strong> co<strong>de</strong>. Cela<br />

est tout à fait correct, car <strong>du</strong> point <strong>de</strong> vue <strong>du</strong> compilateur, la variab<strong>le</strong> Paral<strong>le</strong>lport reste constante.<br />

Les <strong>de</strong>ux co<strong>de</strong>s sont d’ail<strong>le</strong>urs équiva<strong>le</strong>nts, tant que Paral<strong>le</strong>lport ne change pas.<br />

32 / 41


Un autre exemp<strong>le</strong> est la séquence :<br />

Paral<strong>le</strong>lport = 0;<br />

Hardwarenahe Programmierung in C<br />

whi<strong>le</strong> (Paral<strong>le</strong>lport == 0) {<br />

i++; /* wait until the paral<strong>le</strong>l port is ready */<br />

}<br />

Cette <strong>de</strong>rnière sera optimisée en :<br />

Paral<strong>le</strong>lport = 0;<br />

whi<strong>le</strong> (1) {<br />

i++; /* wait until the paral<strong>le</strong>l port is ready */<br />

}<br />

Ici <strong>le</strong> compilateur sait que la variab<strong>le</strong> Paral<strong>le</strong>lport possè<strong>de</strong> la va<strong>le</strong>ur 0. Par conséquent, <strong>le</strong> test<br />

<strong>avec</strong> if <strong>de</strong>vient superflu.<br />

Un <strong>de</strong>rnier exemp<strong>le</strong> est la séquence suivante pour la transmission <strong>de</strong>s bits d’information :<br />

Paral<strong>le</strong>lport = 0; /* C<strong>le</strong>ar all bits */<br />

Paral<strong>le</strong>lport = 1; /* Set the clock bit */<br />

Paral<strong>le</strong>lport = 0; /* C<strong>le</strong>ar the clock bit */<br />

Paral<strong>le</strong>lport = 2; /* Set the data bit */<br />

Paral<strong>le</strong>lport = 3; /* Set the clock bit */<br />

Paral<strong>le</strong>lport = 2; /* C<strong>le</strong>ar the clock bit */<br />

Paral<strong>le</strong>lport = 0; /* C<strong>le</strong>ar all bits */<br />

Le compilateur optimisera cette séquence da la manière suivante :<br />

Paral<strong>le</strong>lport = 0; /* C<strong>le</strong>ar all bits */<br />

Ici la <strong>de</strong>rnière instruction fixe définitivement la va<strong>le</strong>ur <strong>de</strong> Paral<strong>le</strong>lport. Toute <strong>le</strong>s va<strong>le</strong>urs<br />

précé<strong>de</strong>ntes sont sur écrite par cette <strong>de</strong>rnière.<br />

Afin <strong>de</strong> forcer <strong>le</strong> compilateur à exécuter toutes <strong>le</strong>s opérations <strong>de</strong> <strong>le</strong>cture et d’écriture sans optimisation,<br />

il faut définir <strong>le</strong>s variab<strong>le</strong>s <strong>de</strong> façon volati<strong>le</strong>.<br />

La définition <strong>de</strong> la variab<strong>le</strong> Paral<strong>le</strong>lport doit être complétée <strong>avec</strong> <strong>le</strong> mot clé volati<strong>le</strong> dans <strong>le</strong>s<br />

exemp<strong>le</strong>s <strong>de</strong> ci-<strong>de</strong>ssus.<br />

Compact<br />

*((volati<strong>le</strong> unsigned char *) 0x00F1 ) = 0x12;<br />

Via pointeur<br />

/* Definition of the pointer variab<strong>le</strong> */<br />

volati<strong>le</strong> unsigned char *Paral<strong>le</strong>lport;<br />

/* Inisialisation of the pointeur with the address 0x00F1 */<br />

Paral<strong>le</strong>lport = (volatia<strong>le</strong> unsigned char *) 0x00F1;<br />

/* Write the value into the memory case,<br />

which is addressed by the pointer */<br />

*Paral<strong>le</strong>lport = 0x12;<br />

33 / 41


Avec une macro<br />

Hardwarenahe Programmierung in C<br />

/* Definition of the macro instruction,<br />

which could be done in a hea<strong>de</strong>r fi<strong>le</strong> */<br />

#<strong>de</strong>fine Paral<strong>le</strong>lport *((volati<strong>le</strong> unsigned char *) 0x00F1)<br />

/* Call the macro */<br />

Paral<strong>le</strong>lport = 0x12;<br />

Toutes <strong>le</strong>s variab<strong>le</strong>s, qui peuvent changer sans que <strong>le</strong> compilateur <strong>le</strong> remarque ou dont <strong>le</strong> changement<br />

peut influencer <strong>le</strong> <strong>hardware</strong>, doivent toujours être définies <strong>de</strong> façon volati<strong>le</strong>. C'est-à-dire, toutes <strong>le</strong>s<br />

variab<strong>le</strong>s qui ont un rapport <strong>avec</strong> <strong>le</strong> <strong>hardware</strong>, ou qui peuvent être changée dans une routine<br />

d’interruption.<br />

Le co<strong>de</strong> peut souvent fonctionner sans <strong>le</strong> mot clé volati<strong>le</strong>. Toutefois un complément ou une<br />

modification <strong>du</strong> co<strong>de</strong> peuvent engendrer <strong>de</strong>s problèmes, qui seront diffici<strong>le</strong>ment localisab<strong>le</strong>s.<br />

Les optimisations <strong>du</strong> compilateur peuvent éga<strong>le</strong>ment être d’autres natures, que cel<strong>le</strong>s décrites ci<strong>de</strong>ssus.<br />

Par exemp<strong>le</strong>, <strong>le</strong> contenu d’une variab<strong>le</strong> peut être stocké dans un registre <strong>du</strong> processeur tout au<br />

début <strong>de</strong> la fonction. L’accès à ce type <strong>de</strong> registre est en généra<strong>le</strong> beaucoup plus rapi<strong>de</strong> que l’accès à la<br />

mémoire <strong>de</strong>s données. Tous <strong>le</strong>s traitements <strong>de</strong> la variab<strong>le</strong> s’effectueront alors à l’ai<strong>de</strong> <strong>de</strong> ce registre. A<br />

la fin <strong>de</strong> la fonction, <strong>le</strong> contenu <strong>du</strong> registre sera écrit dans la variab<strong>le</strong>. Le co<strong>de</strong> <strong>de</strong>vient ainsi beaucoup<br />

plus rapi<strong>de</strong>. Mais si cette optimisation se fait toujours au détriment <strong>de</strong> l’accès direct <strong>hardware</strong>. Par<br />

conséquent, <strong>le</strong> co<strong>de</strong> ne pourrait plus fonctionner correctement.<br />

4.5 Déviation <strong>de</strong>s fonctions d’entrée et <strong>de</strong> sortie<br />

Les microprocesseurs ne possè<strong>de</strong>nt ni <strong>de</strong> système <strong>de</strong> fichiers ni <strong>de</strong> fonctions d’entrée et <strong>de</strong> sortie. Les<br />

bibliothèques standards permettent néanmoins d’adapter ces fonctions au <strong>hardware</strong>. Dans <strong>le</strong> cas <strong>le</strong> plus<br />

simp<strong>le</strong>, il suffit <strong>de</strong> redéfinir <strong>le</strong>s fonctions putc(), getc() et éventuel<strong>le</strong>ment ungetc(). Les autres<br />

fonctions <strong>de</strong> la librairie standard d’entrée et <strong>de</strong> sortie (stdio.h) utilisent ces fonctions.<br />

Si l’on veut utiliser un système <strong>de</strong> fichier <strong>avec</strong> plusieurs canaux d’entrée et <strong>de</strong> sortie, on doit<br />

éga<strong>le</strong>ment programmer <strong>le</strong>s fonctions fopen(), fclose() et éventuel<strong>le</strong>ment d’autres fonctions<br />

spécia<strong>le</strong>s comme ftell() ou fseek().<br />

L’argument pointeur sur fichier (FILE *) peut être ignoré dans <strong>le</strong>s fonctions getc() et putc()<br />

lorsque l’on ne travail<strong>le</strong> pas <strong>avec</strong> un système <strong>de</strong> fichier. La déviation <strong>de</strong>s entrées et <strong>de</strong>s sorties sur<br />

notre système <strong>de</strong> <strong>développement</strong> peut être définie <strong>de</strong> la manière suivante :<br />

int putc (int c, FILE *stream)<br />

{<br />

SendByteToSerialPort(c);<br />

return c; /* Should return EOF when an error has occured */<br />

}<br />

int getc (FILE *stream)<br />

{<br />

/* return next character (or EOF when an error has occurred)*/<br />

return GetByteFromSerialPort();<br />

}<br />

34 / 41


Hardwarenahe Programmierung in C<br />

4.6 Adaptation supplémentaire <strong>de</strong> la bibliothèque<br />

standard<br />

La disponibilité <strong>de</strong> toutes <strong>le</strong>s fonctionnalités <strong>de</strong> la librairie standard pour un système <strong>de</strong><br />

<strong>développement</strong> nécessite <strong>de</strong>s adaptations supplémentaires.<br />

Il faut adapter <strong>le</strong>s fonctions pour la gestion dynamique <strong>de</strong> la mémoire (stdlib.h) et pour la gestion<br />

<strong>du</strong> temps (time.h). Naturel<strong>le</strong>ment, seu<strong>le</strong>ment en cas <strong>de</strong> nécessité.<br />

Les fonctions malloc() et free() doivent être modifiés pour la gestion dynamique <strong>de</strong> la mémoire.<br />

Toutefois, <strong>le</strong>s options <strong>du</strong> relieur suffisent dans la plupart <strong>de</strong>s systèmes <strong>de</strong> <strong>développement</strong>. Dans ce cas,<br />

il suffit <strong>de</strong> définir <strong>le</strong> domaine <strong>de</strong> la mémoire <strong>de</strong>stiné à sa gestion dynamique.<br />

Il est recommandé <strong>de</strong> consulter la documentation technique <strong>de</strong> l’environnement <strong>de</strong> <strong>développement</strong><br />

pour adapter <strong>le</strong>s fonctions <strong>de</strong>stinées à la gestion <strong>du</strong> temps (time.h).<br />

35 / 41


5 Les interruptions<br />

Hardwarenahe Programmierung in C<br />

Les interruptions sont <strong>de</strong>s moyens importants pour réaliser <strong>de</strong>s tâches en temps réels. Une interruption<br />

est générée par un évènement (souvent externe) et interrompt <strong>le</strong> programme principal à un instant<br />

donnée.<br />

Lorsqu’apparaît une interruption, un sous programme est appelé afin <strong>de</strong> traiter cette <strong>de</strong>rnière. Dans ce<br />

contexte on par<strong>le</strong> <strong>de</strong> routine <strong>de</strong> service d’interruption (Interrupt Service Routine : ISR). La <strong>de</strong>man<strong>de</strong><br />

d’interruption est appelée requête d’interruption. Lorsque toutes <strong>le</strong>s instructions <strong>de</strong> la routine <strong>de</strong><br />

service d’interruption ont été exécutées, <strong>le</strong> programme principal continue à l’endroit ou il a été<br />

interrompu, comme si rien n’a eu lieu.<br />

Exemp<strong>le</strong> d’interruption <strong>de</strong> la vie <strong>de</strong> tous <strong>le</strong>s jours<br />

Je suis en train <strong>de</strong> lire un livre dans <strong>le</strong> salon. Tout à cas, <strong>le</strong> téléphone sonne. J’interromps mon activité<br />

et je vais <strong>de</strong> décrocher <strong>le</strong> téléphone. A la fin <strong>de</strong> la communication, je raccroche <strong>le</strong> téléphone et je<br />

continue mon activité origina<strong>le</strong>. Il se peut qu’un événement plus important a lieu pendant la<br />

communication téléphonique (par exemp<strong>le</strong> quelqu’un pourrait sonner à la porte). En fonction <strong>de</strong><br />

l’importance <strong>de</strong> cet événement, je vais éga<strong>le</strong>ment être obligé d’interrompre la communication<br />

téléphonique.<br />

Evénement<br />

Interrupt Request<br />

Programme principa<strong>le</strong> ISR<br />

Instruction<br />

actuel<strong>le</strong><br />

Instruction<br />

suivante<br />

36 / 41<br />

Première<br />

instruction<br />

Dernière<br />

instruction<br />

rte<br />

Figure 29 : Fonctionnement <strong>du</strong> programme à la suite d’une requête d’interruption<br />

Le « contexte » est l’état actuel <strong>du</strong> programme principal (registre <strong>du</strong> processeur, <strong>le</strong> stack etc.). La<br />

routine d’interruption doit assurer qu’après son exécution <strong>le</strong> programme principal continue comme si<br />

rien n’est arrivé. Comme si vous avez noté la page que vous êtres en train <strong>de</strong> lire, avant d’al<strong>le</strong>r<br />

répondre au téléphone.<br />

5.1 Définition d’une routine d’interruption<br />

Le compilateur doit générer un co<strong>de</strong> spécial pour <strong>le</strong>s routines d’interruption car ces <strong>de</strong>rniers peuvent<br />

interrompre <strong>le</strong> programme principal à n’importe quel instant. Avec <strong>le</strong>s appel<strong>le</strong>s <strong>de</strong> sous programmes<br />

standard, <strong>le</strong> compilateur connaît parfaitement l’instant et <strong>le</strong>s va<strong>le</strong>urs <strong>de</strong>s registres à sauver. Avec <strong>le</strong>s<br />

routines d’interruption cela n’est pas connu d’avance. Par conséquent, avant d’exécuter <strong>le</strong>s instructions<br />

<strong>de</strong> la routine d’interruption, il est pru<strong>de</strong>nt <strong>de</strong> sauver toutes <strong>le</strong>s données importantes au début <strong>de</strong> la<br />

routine <strong>de</strong> service afin que ces <strong>de</strong>rniers puissent être restitués à la fin <strong>de</strong> la routine. Cela n’a pas été<br />

standardisé en C. Par conséquent, chaque environnement <strong>de</strong> <strong>développement</strong> possè<strong>de</strong> ses propres


Hardwarenahe Programmierung in C<br />

compléments d’instruction. Certains utilisent <strong>de</strong>s mots clés comme par exemp<strong>le</strong> interrupt,<br />

__int, interrupt_nn ou #pragma interrupt. La syntaxe exacte doit être recherchée dans<br />

la documentation <strong>du</strong> compilateur.<br />

Dans l’environnement <strong>de</strong> <strong>développement</strong> <strong>du</strong> C8051Fxx, <strong>le</strong>s routines d’interruption doivent être<br />

définies à l’ai<strong>de</strong> <strong>du</strong> mot clé interrupt, complété <strong>avec</strong> <strong>le</strong> numéro <strong>du</strong> vecteur d’interruption :<br />

/* the ISR will be cal<strong>le</strong>d every 100 ms from timer interrupt */<br />

void TimerInterruptHand<strong>le</strong>r (void) interrupt 5<br />

{<br />

Timeout--;<br />

if (Timeout 0) {<br />

Magic = 1.0 / (float) Timeout;<br />

}<br />

}<br />

Dans l’exemp<strong>le</strong> <strong>de</strong> ci-<strong>de</strong>ssus une division par zéro peut apparaître, pourquoi ?<br />

Car l’interruption peut apparaître juste après <strong>le</strong> test <strong>avec</strong> if et ré<strong>du</strong>ire la va<strong>le</strong>ur <strong>de</strong> Timeout <strong>de</strong> 0 à 1,<br />

avant que la division ne soit exécutée par l’ordinateur.<br />

Afin d’éviter cette erreur il faut modifier <strong>le</strong> co<strong>de</strong> <strong>de</strong> la manière suivante :<br />

37 / 41


Hardwarenahe Programmierung in C<br />

void TimerInterruptHand<strong>le</strong>r (void) interrupt 5<br />

{<br />

}<br />

Timeout--;<br />

void Troub<strong>le</strong> (void)<br />

{<br />

Disab<strong>le</strong>Interrupts ();<br />

if (Timeout > 0) {<br />

Magic = 1.0 / (float) Timeout;<br />

}<br />

Enab<strong>le</strong>Interrupts ();<br />

}<br />

Ce qui est beaucoup meil<strong>le</strong>ur. Mais que se passe-t-il lorsque <strong>le</strong>s interruptions sont préalab<strong>le</strong>ment<br />

bloquées et que ces <strong>de</strong>rniers sont libérés. Il existe pour cela <strong>de</strong>s fonctions, qui permettent <strong>de</strong><br />

déterminer si <strong>le</strong>s interruptions sont préalab<strong>le</strong>ment bloquées ou pas. De co<strong>de</strong> <strong>de</strong>vrait être définie <strong>de</strong><br />

façon optima<strong>le</strong> <strong>de</strong> la manière suivante :<br />

void TimerInterruptHand<strong>le</strong>r (void) interrupt 5<br />

{<br />

Timeout--;<br />

}<br />

void Troub<strong>le</strong> (void)<br />

{<br />

int OldInterruptState;<br />

OldInterruptState = GetInterruptState();<br />

Disab<strong>le</strong>Interrupts();<br />

}<br />

Attention<br />

if (Timeout > 0) {<br />

Magic = 1.0 / (float) Timeout;<br />

}<br />

/* Enab<strong>le</strong> Interrupts only if they were enab<strong>le</strong>d before */<br />

if (OldInterruptState == 1) {<br />

Enab<strong>le</strong>Interrupts ();<br />

}<br />

Même <strong>le</strong>s morceaux <strong>de</strong> co<strong>de</strong> qui peuvent paraître comme étant apparemment sur, comme par exemp<strong>le</strong><br />

a++ ou a = a + 1, doivent être protéges <strong>de</strong>s interruptions. Car ces instructions haut niveau sont<br />

souvent tra<strong>du</strong>ites en une suite d’instructions assemb<strong>le</strong>ur (<strong>le</strong>cture, incrémentation et écriture), qui ne<br />

doivent éga<strong>le</strong>ment pas être interrompues. Avec certain processeur, il existe <strong>de</strong>s instructions dites<br />

« atomiques », qui ne peuvent pas être interrompues. Mais pour pouvoir utiliser ces instructions, il faut<br />

activer certaines options <strong>du</strong> compilateur.<br />

38 / 41


Hardwarenahe Programmierung in C<br />

5.3 Traitement <strong>de</strong>s interruptions <strong>avec</strong> <strong>le</strong> contrô<strong>le</strong>ur<br />

C8051F<br />

Le traitement <strong>de</strong>s interruptions dans notre système se dérou<strong>le</strong> exactement <strong>de</strong> la manière décrite ci<strong>de</strong>ssus.<br />

Chaque source d’interruption peut être libérée ou bloquée <strong>avec</strong> <strong>de</strong>s bits <strong>de</strong> configuration, qui<br />

sont contenus dans <strong>le</strong>s registres <strong>de</strong> fonctions spécia<strong>le</strong>s (IE, EIE1 et EIE2). Toutefois, <strong>le</strong>s<br />

interruptions doivent être libérées <strong>de</strong> façon globa<strong>le</strong> en activant <strong>le</strong> bit EA dans <strong>le</strong> registre IF.<br />

Les contrô<strong>le</strong>urs C8051F possè<strong>de</strong>nt <strong>de</strong>ux niveaux <strong>de</strong> priorités d’interruption, une haute et une basse.<br />

Une interruption <strong>de</strong> basse priorité peut être interrompue par une interruption <strong>de</strong> haute priorité. Par<br />

contre, une interruption <strong>de</strong> haute priorité ne peut pas être interrompue. Le niveau <strong>de</strong> priorité peut être<br />

définie <strong>avec</strong> <strong>le</strong>s bits <strong>de</strong> priorité, qui se situent dans <strong>le</strong>s registres <strong>de</strong> fonction spécia<strong>le</strong>s (IP, EIP1 et<br />

EIP2). Si <strong>de</strong>ux requêtes d’interruption apparaissent au même instant, la requête <strong>avec</strong> la plus haute<br />

priorité sera traitée en premier. Si <strong>le</strong>s <strong>de</strong>ux requêtes possè<strong>de</strong>nt <strong>le</strong> même niveau <strong>de</strong> priorité, <strong>le</strong><br />

traitement aura lieu en fonction d’un ordre <strong>de</strong> priorité fixé d’avance, selon <strong>le</strong> tab<strong>le</strong>au 9.4 <strong>de</strong> la<br />

documentation concernant <strong>le</strong> C8051F2xx.<br />

L’exemp<strong>le</strong> <strong>de</strong> l’alinéa précédant peut être adapté à notre système <strong>de</strong> la manière suivante :<br />

void TimerInterruptHand<strong>le</strong>r (void) interrupt 5<br />

{<br />

Timeout--;<br />

}<br />

void Troub<strong>le</strong> (void)<br />

{<br />

unsigned char OldStateIE;<br />

/* Save old state of Interrupt Enab<strong>le</strong> (IE) register */<br />

OldStateIE = IE;<br />

}<br />

/* Disab<strong>le</strong> the interrupts by c<strong>le</strong>aring the<br />

Enab<strong>le</strong> All (EA) interrupts bits<br />

in the Interrupt Enab<strong>le</strong> (IE) Register */<br />

EI = EI & 0x7F;<br />

if (Timeout > 0) {<br />

Magic = 1.0 / (float) Timeout;<br />

}<br />

/* Restore old state of Interrupt Enab<strong>le</strong> (IE) register */<br />

IE = OldStateIE;<br />

5.3.1 Les vecteurs d’interruption<br />

La définition <strong>de</strong>s routines d’interruption n’est pas suffisante. Le processeur doit éga<strong>le</strong>ment avoir,<br />

quel<strong>le</strong> routine doit être appelée lorsqu’apparaît une requête d’interruption. Le principe est <strong>le</strong> même<br />

pour toutes <strong>le</strong>s famil<strong>le</strong>s <strong>de</strong> processeur. Soit <strong>le</strong> système possè<strong>de</strong> une tabel<strong>le</strong> <strong>de</strong>s vecteurs d’interruption,<br />

qui contient toutes <strong>le</strong>s adresses <strong>de</strong>s routines <strong>de</strong> service d’interruption. Ou alors, <strong>le</strong> système fait <strong>de</strong>s<br />

sauts <strong>de</strong> programme à <strong>de</strong>s adresses prédéfinies. Dans <strong>le</strong> premier cas, <strong>le</strong> programmeur doit écrire<br />

39 / 41


Hardwarenahe Programmierung in C<br />

l’adresse <strong>de</strong> la routine <strong>de</strong> service dans la tabel<strong>le</strong> <strong>de</strong>s vecteurs d’interruption. Dans <strong>le</strong> second cas, il doit<br />

déposer <strong>le</strong> co<strong>de</strong> <strong>de</strong> la routine <strong>de</strong> service d’interruption à l’adresse prédéfinie dans la mémoire.<br />

Le C8051F travail<strong>le</strong> <strong>avec</strong> un tab<strong>le</strong>au <strong>de</strong> vecteurs d’interruptions. Ce tab<strong>le</strong>au contient 21 vecteurs<br />

d’interruption, dont 9 sont dédiés aux composants périphériques, comme par exemp<strong>le</strong> : <strong>le</strong> mo<strong>du</strong><strong>le</strong><br />

temporel (Timer 2), la communication sériel, <strong>le</strong>s convertisseurs AD et <strong>le</strong>s comparateurs (voir tab<strong>le</strong>au<br />

9.4 <strong>de</strong> la documentation <strong>du</strong> C8051F2xx).<br />

Vector number<br />

Timer 2<br />

5<br />

Serial Port (UART)<br />

Vector number<br />

Mo<strong>du</strong><strong>le</strong><br />

CPU<br />

4<br />

40 / 41<br />

Program memory<br />

Co<strong>de</strong> for timer 2<br />

interrupt hand<strong>le</strong>r<br />

Co<strong>de</strong> for serial port<br />

interrupt hand<strong>le</strong>r<br />

Vector tab<strong>le</strong><br />

Figure 30 : Principe d’appel <strong>de</strong> la routine <strong>de</strong> service d’interruption<br />

Lorsque qu’un composant périphérique génère une requête d’interruption, il transmet simultanément<br />

son vecteur d’interruption. A l’ai<strong>de</strong> <strong>de</strong> ce vecteur d’interruption, <strong>le</strong> CPU peut chercher l’adresse <strong>de</strong> la<br />

routine <strong>de</strong> service dans la tabel<strong>le</strong> <strong>de</strong>s vecteurs d’interruption.<br />

Dans notre environnement <strong>de</strong> <strong>développement</strong>, <strong>le</strong> mot clé interrupt permet d’écrire l’adresse <strong>de</strong> la<br />

routine <strong>de</strong> service d’interruption dans la tabel<strong>le</strong> <strong>de</strong>s vecteurs d’interruption. Ce <strong>de</strong>rnier doit être<br />

complété <strong>avec</strong> <strong>le</strong> numéro <strong>du</strong> vecteur d’interruption. Dans <strong>le</strong>s exemp<strong>le</strong>s <strong>de</strong> ci-<strong>de</strong>ssus, l’adresse <strong>de</strong> la<br />

routine <strong>de</strong> service d’interruption est stockée dans <strong>le</strong> vecteur numéro 5 <strong>de</strong> la tabel<strong>le</strong> <strong>de</strong>s vecteurs<br />

d’interruption. En effet, ce vecteur d’interruption est réservé pour <strong>le</strong> mo<strong>du</strong><strong>le</strong> temporel 2 :<br />

void TimerInterruptHand<strong>le</strong>r (void) interrupt 5<br />

{<br />

Timeout--;<br />

}<br />

6<br />

5<br />

4<br />

3


6 Le co<strong>de</strong> <strong>de</strong> démarrage<br />

Hardwarenahe Programmierung in C<br />

Certaines tâches d’initialisation doivent être réalisées avant <strong>le</strong> démarrage <strong>de</strong> la fonction principa<strong>le</strong><br />

main. Ces tâches sont en généra<strong>le</strong> très spécifiques au processeur et doivent être programmé en partie<br />

en assemb<strong>le</strong>ur. Ces tâches comprennent l’initialisation <strong>de</strong>s variab<strong>le</strong>s globa<strong>le</strong>s et statiques,<br />

l’initialisation <strong>de</strong>s fonctions <strong>de</strong>s bibliothèques standards, la configuration minima<strong>le</strong> <strong>du</strong> <strong>hardware</strong> et<br />

initialisation <strong>de</strong>s registres spéciaux <strong>du</strong> processeur et fina<strong>le</strong>ment initialisation <strong>du</strong> pointeur <strong>de</strong> pi<strong>le</strong><br />

(stack) et <strong>de</strong> trame (frame) pour la gestion <strong>de</strong>s appel<strong>le</strong> <strong>de</strong> fonction et <strong>de</strong>s variab<strong>le</strong>s loca<strong>le</strong>s.<br />

Le dérou<strong>le</strong>ment d’un système à microcontrô<strong>le</strong>ur autonome est <strong>le</strong> suivant (on admet que <strong>le</strong> programme<br />

se trouve dans la ROM).<br />

Procé<strong>du</strong>re :<br />

Reset<br />

Co<strong>de</strong> <strong>de</strong><br />

démarrag<br />

main()<br />

Fin<br />

41 / 41<br />

Initialisation <strong>de</strong> la<br />

bibliothèque run time<br />

Figure 31 : Diagramme <strong>de</strong> flux <strong>de</strong> l’initialisation d’un système à microprocesseur<br />

Il n’y pas <strong>de</strong> retour <strong>de</strong>puis la fonction principa<strong>le</strong> main() dans <strong>le</strong>s programmes <strong>de</strong>stinés aux<br />

microcontrô<strong>le</strong>urs. Ce <strong>de</strong>rnier est composé en généra<strong>le</strong> d’une bouc<strong>le</strong> infinie, qui réalise <strong>le</strong>s diverses<br />

tâches <strong>de</strong> contrô<strong>le</strong>.<br />

Si par malheur la fonction principa<strong>le</strong> s’achève, <strong>le</strong> système pourrait entrer dans un état indéfini. En<br />

généra<strong>le</strong> ce <strong>de</strong>rnier entre dans une bouc<strong>le</strong> infinie. Toutefois, il serait peut être plus intelligent <strong>de</strong> <strong>le</strong><br />

redémarrer dans ces cas.<br />

Dans <strong>le</strong>s PC, un programme se termine à la fin <strong>de</strong> la fonction principa<strong>le</strong>. Toutes <strong>le</strong>s fenêtres <strong>de</strong><br />

l’application sont alors fermées et <strong>le</strong> système d’exploitation attend sur <strong>de</strong>s nouvel<strong>le</strong>s comman<strong>de</strong>s <strong>de</strong><br />

l’utilisateur.<br />

Les microcontrô<strong>le</strong>urs ne contiennent en généra<strong>le</strong> pas <strong>de</strong> système d’exploitation. Le développeur doit<br />

dans ce cas définir par lui-même ce qui doit être fait (en tous cas quelque chose, qui ne limite pas la<br />

sécurité et la stabilité <strong>du</strong> processus. Un système <strong>de</strong> navigation <strong>de</strong>vrait par exemp<strong>le</strong> se réinitialiser ou<br />

stopper <strong>le</strong> véhicu<strong>le</strong>. Dans tous <strong>le</strong>s cas il ne <strong>de</strong>vrait pas s’arrêter et laisser <strong>le</strong> véhicu<strong>le</strong> continuer dans<br />

une direction donnée)

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!