Poly Periph

Embed Size (px)

Citation preview

  • Lart de programmerson petit copeau

    de silicium

    Quatrime anne DGEI INSA / release 2010c

    Automne 2010

  • Table des matires

    1 On en tient une couche 51.1 Introduction et dfinitions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.2 Architecture logicielle recommande . . . . . . . . . . . . . . . . . . . . . . . . . . . 51.3 Guide des bonnes manires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61.4 La couche matrielle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

    2 Faudrait pas prendre les pilotes pour des navigateurs ! 82.1 Premier exemple : configuration dune broche dentre-sortie . . . . . . . . . . . . . . 8

    2.1.1 Pilote dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82.1.2 Pilote statique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

    2.2 Second exemple : configuration dune interruption . . . . . . . . . . . . . . . . . . . . 122.2.1 Pilote dynamique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122.2.2 Pilote statique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

    3 Bah ! Les masques 153.1 Oprateur logiques et bit bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163.2 Mettre un bit 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.3 Mettre un bit 0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173.4 Inverser un bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183.5 Initialiser une tranche de bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

    4 Lpointeur de fonctions ne manque(nt) pas de piquant ! 204.1 Appel indirect des fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

    4.1.1 Pointeur de fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 204.1.2 Affectation dun pointeur de fonction . . . . . . . . . . . . . . . . . . . . . . . 204.1.3 Appel de fonction par un pointeur . . . . . . . . . . . . . . . . . . . . . . . . 204.1.4 Passage de fonctions en paramtre . . . . . . . . . . . . . . . . . . . . . . . . 21

    4.2 Lart et la manire... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224.2.1 ... de sen servir avec la solution dynamique . . . . . . . . . . . . . . . . . . . 224.2.2 ... de sen passer avec la solution statique . . . . . . . . . . . . . . . . . . . . 234.2.3 Quelques commentaires pour se faire une religion . . . . . . . . . . . . . . . . 23

    5 Une mise au point simpose ! 255.1 Les points darrts et les espions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

    5.1.1 Les diffrents points darrts . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

    2

  • 5.1.2 Pose dun point darrt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265.2 Emulation avance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

    5.2.1 Contrle de lexcution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275.2.2 Simulation de lactivit des broches du STM32 . . . . . . . . . . . . . . . . . 30

  • Chap 1: On en tient une couche

    1.1 Introduction et dfinitions

    Un pilote informatique (ou plus connu sous langlicisme driver ) est un programme infor-matique qui permet un autre programme dinteragir avec un priphrique. En gnral, chaquepriphrique a son propre pilote.

    Pour assurer la qualit dune application, il est ncessaire de bien concevoir les pilotes et leur re-lation avec lapplication. Petit rappel : en informatique, la qualit dsigne un ensemble dindicateurspour offrir une apprciation globale dun logiciel. Elle se base sur : la compltude des fonctionnali-ts, la prcision des rsultats, la fiabilit, la tolrance aux pannes, la facilit et la flexibilit de sonutilisation, la simplicit, lextensibilit, etc.

    Parmi ces critres, le nologisme portabilit dsigne, pour un programme informatique, sa ca-pacit fonctionner dans diffrents environnements dexcution, en particulier diffrents environne-ments matriels. A cela sajoute ladaptabilit qui est souvent utilis pour dsigner la qualit dunlogiciel qui peut tre modifi aisment en harmonie avec les changements auxquels son utilisationpeut tre soumise.

    La portabilit et ladaptabilit dune application ncessite davoir une architecture logiciellesolide. Celle-ci dfinit lorganisation interne dun logiciel, son dcoupage en couches et en modules,ainsi que les responsabilits de chaque module et la nature et la structure des relations entre modules.

    Les relations entres les modules sont fournies via une interface de programmation (ApplicationProgramming Interface ou API ). Elle permet linteraction des programmes les uns avec les autres.Du point de vue technique une API est un ensemble de fonctions, procdures ou classes mises disposition par une bibliothque logicielle, un systme dexploitation ou un service. La connaissancedes API est indispensable linteroprabilit entre les composants logiciels.

    Dans le cas typique dune bibliothque, il sagit gnralement de fonctions considres commeutiles pour dautres composants. Une interface en tant que telle est quelque chose dabstrait ; lescomposants ralisant celle-ci tant des mises en uvre (ou implmentation). Idalement il peut yavoir plusieurs mises en uvre pour une mme interface. Par exemple, sous UNIX, la libc dfinitdes fonctions de base utilises par pratiquement tous les programmes et est fournie par des misesen uvre propritaires ou libres, sous diffrents systmes dexploitation.

    1.2 Architecture logicielle recommande

    Pour en revenir nos moutons lectroniques, nous prconisons pour les TP de priphriques unearchitecture logicielle en trois couches (voir figure 1.1).

    Les diffrentes couches sont : La couche application : Cette couche ne comporte que du code ddi une application.

    Elle comporte lensemble des fonctions de traitement et dorchestration de lapplication. La couche de services applicatifs : Cette couche un ensemble de fonctions qui masquent les

    priphriques matriels au niveau de lapplication pour en offrir une reprsentation abstraite.

    5

  • module ADC

    couche application

    couche services applicatifs

    couche pilotesmodule PWM

    module IO

    module Timers...

    module vitesse

    module position

    module comm.

    modulesuper-vision...

    application

    Figure 1.1 Architecture logicielle

    Par exemple, le service dacquisition dune vitesse masque lappel au priphrique ADC pouroffrir une vision purement abstraite de la variable de vitesse.

    La couche de pilotes : Cette couche ne comporte que du code li la configuration etlutilisation des priphriques sans prsuppos une utilisation particulire par une application.

    Une telle architecture offre de nombreux avantages : Seules les couches services applicatifs et pilotes doivent changer si le matriel volue,

    la couche application nayant a priori besoin que de quelques modifications pour prendre enconsidration les nouvelles capacits du support dexcution (surtout en ce qui concerne letemps).

    Les modules qui composent la couche pilotes peuvent tre utilises pour diffrentes applicationset ainsi offrir des composants pris sur tagres.

    La couche services applicatifs fournit des services gnriques pour un mme ensemble defamilles dapplications sans avoir besoin dtre rcrit chaque dveloppement ou volutiondune application sur le mme support.

    Le test des modules est fait de manire unitaire, ce qui facilite le dbogage sans avoir besoinde chercher la petite bte.

    Les lments qui composent une couche ne peuvent communiquer quavec un lment dunecouche infrieure et cela se fait uniquement travers les API des diffrentes modules.

    1.3 Guide des bonnes manires

    Chaque module est associ deux fichiers, lun comportant le code (.c) et lautre dfinissant sonAPI (.h). Seul les fonctions dclares dans le ficher den-tte sont accessibles aux autres lmentslogiciels.

    Comme le fichier den-tte est le seul lment utilisable (lisible / modifiable) par un utilisateurexterne au module, il est capital de bien le commenter. Le commentaire est considr comme un

    6

  • mode demploi du module. Ceci est dautant plus vrai, que les constructeurs de micro-contrleursproposent des modules (ou bibliothques) au format .lib ou .o. Ces derniers sont compils donc defait, non modifiables.

    Afin dassurer la portabilit des modules de la couche pilotes, il est interdit quune des fonctionsdun module utilisent une variable globale au projet. Si on veut utiliser une variable globale auprojet, dans la couches service ou application, cela peut se faire par le biais dun fichier denttepartag, par exemple, global.h. Ceci tant, cest fortement dconseill.

    Quelques rgles sont spcifiques aux couches : Couche application

    Le main() est contenu dans la couche application et ne peut faire appel qu des fonctionsde la couche services.

    Aucune rfrence des priphriques nest fait au niveau de la couche application. Couche services applicatifs

    Le code des modules de la couches services contient des fonctions directements lies lap-plication : les noms de fonctions et de variables font explicitement rfrence lapplication.

    Les fonctions au niveau services appellent uniquement des fonctions de niveau pilotes. Ellesne sappellent pas entre elles. Dit autrement, elles ne peuvent inclure que des fichiers deniveau pilote.

    Les fichiers sont organiss par domaine li lapplication Couche pilotes

    La couche pilotes ne contient que les fonctions qui concernent directement les priphriques. Les noms des fonctions doivent voquer les priphriques. Les fonctions ne font pas rfrence lapplication et doivent tre dfinie de manire ind-

    pendante toute application.

    1.4 La couche matrielle

    Le logiciel, et dans notre cas la couche pilote, est excut sur le coeur du processeur et doitcommuniquer avec les priphriques. Les priphriques sont des circuits, essentiellement de llec-tronique numrique, prsents sur la puce qui fournissent des fonctions dinterface avec le matrielsur lequel la puce est embarque. Ces circuits ne sont pas programmables comme le coeur : ils nepeuvent pas excuter des lignes de programmes. Par contre, on peut les configurer, c--d. modifierun paramtre de son fonctionnement, o transfrer des donnes avec le coeur du processeur.

    TODO SCHEMA REGISTRE GPIOA_ODRSi lon crit une valeur ladresse XXX, avec la ligne *(0x8000123)=13 en langage C qui

    sera traduite par exemple par ldr R0,=0x8000123 ; ldr R1,=13; str R1,[R0] en assembleur, lecoeur va positionner la valeur 0x8000123 sur le bus dadresse, la valeur 13 sur le bus de donne, laligne R/W 0 pour write et attendre un front dhorloge actif.

    TODO finir tout a

    7

  • Chap 2: Faudrait pas prendre lespilotes pour des navigateurs !

    Lors de limplmentation dun pilote plusieurs possibilits sont offertes en particulier pour toutce qui est li la configuration.

    2.1 Premier exemple : configuration dune broche dentre-sortie

    Prenons lexemple de la configuration dun port dentre-sortie. Au cour de la conception lafonction Pin_IO_Init(State, Port, Pin_Number) est dcrite comme permettant au pin numroPin_Number du port Port dtre configurer dans ltat State.

    Au niveau implmentation cela peut se traduire de deux manires : soit dynamiquement, cest--dire que cest lexcution que la configuration sera faite, soit statiquement, cest--dire que laconfiguration sera faite la compilation. Ces deux stratgies ncessitent alors une implmentationdiffrente.

    2.1.1 Pilote dynamique

    Dans le cas dynamique, lAPI du pilote fournit lapplication une fonction de configuration, parexemple lAPI ./pilotes/GPIO_dyn.h du listing 2.1 et son implmentation dans ./pilotes/GPIO_dyn.c

    // Port c on f i g u r a t i on func t i onvoid Pin_IO_Init (char State , GPIO_TypeDef Port , int Pin_Number) ;// S ta t e shou ld be i f o r INPUT, o f o r OUTPUT// Port po in t e r to GPIO s t r u c t u r e de f ined in stm_regs . h : GPIOA, . . .// Pin_Number : as i t says . . .// Example :// Pin_IO_Init ( o ,GPIOD,3 ) ; s e t por t D pin number 3 as an output

    Listing 2.1 ./pilotes/GPIO_dyn.h : lAPI du pilote dynamique

    (listing 2.2) permet de rgler les registre du Port voulus en fonction de State et Pin_Number.La configuration dune broche se fera par un appel de lapplication (couche application ou service)

    en passant les paramtres souhaits la fonction Pin_IO_Init. Dans lexemple du listing 2.3, onrgle la broche 2 du port GPIOA en entre.

    Les fonctions de configurations sont donc crites dans le fichier .c, par exemple ./pilotes/GPIO_dyn.cet on donne accs aux couches suprieures (service et application) via une API dument commen-te, par exemple ./pilotes/GPIO_dyn.h. Larborescence des fichiers conseille, voir fig. 2.1, permetainsi de rutiliser le pilote dans plusieurs projets sans faire de copie multiple de ces fichiers.

    8

  • void Pin_IO_Init (char State , GPIO_TypeDef Port , int Pin_Number){

    i f ( State== i ){// input por t

    // r e s e t mode [ 0 : 1 ] to 00 = f l o a t i n g inpu tPort>CRL &= ~(3

  • Figure 2.1 Arborescence o le rpertoire pilotes est aumme niveau que celui des projets. Plusieurs projets peuventdonc inclure le mme pilote en donnant le chemin relatif vers le.h (../../pilotes/GPIO_stat.h). Chaque applicatif de projet(Test_GPIO.c) configure son pilote en passant les paramtreslors d elappel de la fonction dinitialisation. Dans le cas de pi-lote statique, le fichier de configuration GPIO_stat_conf.h estplac dans le projet car la configuration dpend de lapplicationet ne peut tre la mme.

    2.1.2 Pilote statique

    Dans le cas statique, la configuration se fait directement dans un fichier de configuration, parexemple ./projet/exemple/GPIO_stat_conf.h, appartenant au projet. Dans ce fichier de configu-ration, lutilisateur va commenter ou dcommenter des directives #define ... :

    //CONF : i f you want to use GPIOA por t then// uncomment the f o l l ow i n g l i n e#define GPIOA_IS_USED

    // CONF : by d e f a u l t a l l po r t s are inpu t s// to s e t a por t to output add l i n e s in the format// #undef P_// #de f i n e P_ IS_OUTPUT// Example : PB_3 f o r t pin number 3 o f GPIOB#undef PA_2#define PA_2 IS_OUTPUT

    Listing 2.4 ./projet/exemple/GPIO_stat_conf.h : configuration via des directive de compilation

    Le fichier de configuration est inclus par le fichier source, par exemple ./pilotes/GPIO_stat.c,ce qui va influencer sa compilation et ainsi intgrer les configurations :

    Lapplication, quand elle, ne fait quappeler une fonction dinitialisation sans paramtres :Dans cet exemple la simplicit nest pas en faveur de la version statique, cependant le code

    10

  • #define IS_INPUT 0x0#define IS_OUTPUT 0x3

    #define PA_0 IS_INPUT#define PA_1 IS_INPUT#define PA_2 IS_INPUT. . .

    #include "GPIO_stat_conf . h"// path to the conf f i l e shou ld be s e t in compi ler op t i ons// Now PA_x are con f i gured by user

    void GPIO_Init (void ){

    #i f d e f GPIOA_IS_USED// cons t ruc t the i n i t from the PA_x con f i guredGPIOA>CRL = (PA_0

  • produit statiquement est beaucoup moins coteux en terme de mmoire, car il ne compilera lesfonctions de configuration que si des ports sont utiliss.

    2.2 Second exemple : configuration dune interruption

    Les interruptions peuvent permettre dexcuter une fonction lie lapplication suite un v-nement matriel. Il y a donc dun ct la fonction qui appartient la couche applicative et de lautrelinterruption capturer au niveau de la couche pilotes. Lors de la configuration du systme il fauttre capable de faire le lien entre ces deux lments...

    2.2.1 Pilote dynamique

    Dans sa version dynamique, cela revient prototyper une fonction dans le pilote du priphriquequi permet de faire le lien entre la fonction et une interruption du priphrique. Supposons que nousvoulons excuter la fonction Gazabeuh(void) lors de linterruption provoque par le priphriqueXXX.

    Le pilote de XXX comportera une fonction Init_IT_XXX(void (* IT_fonction) (void)) quipermettra de lier linterruption de XXX la fonction IT_fonction.

    void (pt_IT_Hook) (void ) ; // Pointeur de f onc t i on pour l IT

    void Init_IT_XXX(void ( IT_fonction ) (void ) ){

    pt_IT_Hook = IT_fonction ;. . . // Act i ver l i n t e r r u p t i o n

    }. . .

    Listing 2.7 ./pilotes/Pilote_XXX.c : configuration dune interruption

    Le handler de linterruption est alors dfini dans la suite de manire gnrique par la codesuivant :

    Au niveau applicatif la configuration du priphrique se fera grce au code suivant :Bien sr la fonction de configuration de linterruption pourrait tre plus volue, par exemple

    en fixant le niveau de linterruption etc.

    2.2.2 Pilote statique

    Dans le cas dun pilote statique la solution est plus simple implmenter. Il suffit de faire unfichier de configuration :

    Le source du pilote utilise la directive #ifdef pour insrer ou non lappel de la fonction lors delinterruption

    Remarquez que dans cet exemple, la version statique va gnrer uniquement un Handler videalors que la version dynamique gnre un Handler avec 4 lignes de code, plus une fonction dini-tialisation (1 ligne) et son appel du main (1 ligne). Vous comprenez maintenant la compacit de laversion statique mais malheureusement aussi sa complexit...

    12

  • . . .void XXX_IRQHandler void // Handler de l IT de XXX{

    i f ( ( int ) pt_IT_Hook != 0){

    (pt_IT_Hook) ( ) ; // Appel l a f onc t i on}

    elsewhile (1 ) ; // bouc l e i n f i n i . . Le hand ler n e s t pas con f i gu

    // mais i l e s t dangereux de f a i r e n importe quoi}

    Listing 2.8 ./pilotes/Pilote_XXX.c : handler dune interruption en dynamique

    #include " . . / . . / . . / p i l o t e s /Pilotes_XXX . h". . .void main (void ) // Handler de l IT de XXX{

    Init_Clock ( ) ;Init_GPIO ( ) ;Init_IT_XXX(&Gazabeuh ) ;

    }

    void Gazabeuh (void ){

    // Code excu t e r pendant l i n t e r r u p t i o n}. . .

    Listing 2.9 ./projet/ex_it/main.c : Exemple de configuration dune interruption en dynamique

    // CONFIGURATION PART// p l e a s e uncomment i f you wich to launch a func t i on on IT// #de f i n e THERE_IS_A_HOOK_ON_IT#ifde f THERE_IS_A_HOOK_ON_IT

    // CONFIGURE here the func t i on pro to t ypevoid Gazabeuh (void ) ;//CONFIGURE here the c a l l to the hook func t i on#de f i n e IT_HOOK_CALL Gazabeuh ( )

    #endif

    Listing 2.10 ./projet/exemple/Pilote_XXX_conf.h : configuration via des directives decompilation

    13

  • #include "Pilote_XXX_conf . h"// path to the conf f i l e shou ld be s e t in compi ler op t i ons

    void XXX_IRQHandler void // Handler de l IT de XXX{

    #i f d e f THERE_IS_A_HOOK_ON_ITIT_HOOK_CALL;

    #elsewhile (1 ) ; // bouc l e i n f i n i . . Le hand ler n e s t pas

    con f i gu// mais i l e s t dangereux de f a i r e n importe quoi

    #end. . .

    }

    Listing 2.11 ./pilotes/Pilote_XXX.c : handler dIT utilisant les directives de compilation

    vous de choisir...

    14

  • Chap 3: Bah ! Les masques

    Pour programmer un priphrique il est ncessaire daller modifier un ou plusieurs bits dans unregistre sans modifier les autres. Par exemple le registre ADC_CR1 sert configurer le convertisseuranalogiquenumrique ADC1 :

    Figure 3.1 Extrait du reference manual du STM32 p. 236, la suite dcrit la fonction de chaquebit, comme SCAN et AWDIE et la signification des valeurs de chaque tranches de bit tels que DISCNUM

    Pour cela on utilise les masques logiques et certaines astuces pour construire un masque claire-ment sans risquer de se tromper. Dans lexemple suivant le bit SCAN de ADC_CR1 est mis 1 et lebit EOCIE est mis 0 sans toucher aux autres bits. Les registres ADC1_CR2, ADC1_SQR1, ADC1_SQR3sont aussi manipuls avec des masques :

    ADC1>CR1 |= (ADC_SCAN) ; // cont inuous scan o f channe l s 1 ,14 ,15

    ADC1>CR1 &= ~(ADC_EOCIE) ; // pas d i n t e r r u p t i o n de f i n de conv .

    ADC1>CR2 |= (ADC_EXTSEL_ON_SWSTART | ADC_ CONT | ADC_DMA) ;// EXTSEL = SWSTART// use data a l i g n r i g h t , cont inuous convers ion// send DMA reque s t

    // conver t sequence i s channel 1 then 14 then 15ADC1>SQR3 |= (1

  • Si vous avez aucune ide de comment ce code fonc-tionne cest que vous ne maitrisez pas encore lartprimitif du masque : lisezdonc la suite.Cicontre, un masque primitif (on prfre diredart premier) dorigine Gabonaise.

    3.1 Oprateur logiques et bit bit

    On utilise les oprateurs logiques ET, OU, XOR (OU exclusif) et NOT entre un registre et unmasque pour manipuler les bits. Les oprateurs logiques et leurs syntaxe en langage C sont rsumsdans le tableau suivant :

    Fonction logique Oprateur logique Oprateur bit bitET && &OU || |XOR aucun NON !

    Loprateur logique considre les oprandes (quelle soient 8/16/32 bit) comme une valeur boo-lenne fausse si tous les bits sont nuls et vrai sinon. Elle fournit un rsultat boolen nul si cestfaux et diffrent de zro (en gnral la valeur 1) sinon. Ne confondez donc pas loprateur logiqueavec loprateur bit bit qui effectue 8/16/32 oprations logiques entre chaque bits respectifs desoprandes, par exemple :

    a = 2 ; // s o i t b00000010 en b i na i r e e s t v r a i car d i f f r e n t de 0b = 1 ; // s o i t b00000001 en b i na i r e e s t v r a i au s s iy = a && b ; // donne 1( v ra i ) car a ET b e s t v r a iz = a & b ; // donne b00000000 car chaque ET des b i t s de a e t b sont

    faux

    16

  • 3.2 Mettre un bit 1

    Pour cela on utilise loprateur OU avec une valeur binaire, appele masque, ayant des bits 1uniquement devant les bits que lon veut initialiser :

    b7 b6 b5 b4 b3 b2 b1 b0

    OU 0 0 0 1 0 0 1 1

    = b7 b6 b5 1 b3 b2 1 1

    car x OU 1 = 1 et x OU 0 = x

    Ainsi les bits b4, b1 et b0 sont passs 1 sans modifier la valeur des autres bits.Pour effectuer cela en langage C on doit calculer la valeur du masque binaire : convertir

    b00010011 en hexadcimal (0x13) ou en dcimal (19) car le langage C nadmet pas de littrauxen binaire.

    char av o i l e ;. . .// fo rmu la t i ons q u i v a l e n t e sav o i l e = avo i l e | 0x13 ; // opra teur | i n l i n eav o i l e |= 0x13 ; // opra teur | p r f i x =av o i l e |= 19 ; // va l eu r du masque en dcimal

    Il nest pas trs vident de comprendre que 0x13 ou 19 correspond un masque visant les bitsde rang 0,1 et 4, de plus il est trs facile de se tromper lorsque lon fait la conversion soimme. Ungeek utilisera loprateur de dcalage gauche

  • Ainsi les bits b4, b1 et b0 sont passs 0 sans modifier la valeur des autres bits.Pour construire le masque, on peut toujours effectuer la conversion soit-mme avec un risque

    derreur : b11101100 = 0xEC = 236. On peut aussi construire le masque avec des 1 devant les bits annuler et ensuite inverser chaque bit avec loprateur .

    (1

  • recopier les 1 du premier masque dans avoile avec un OU :

    num n7 n6 n5 n4 n3 n2 n1 n00x7 0 0 0 0 0 1 1 1

    (num&0x7) 0 0 0 0 0 n2 n1 n0(num&0x7)

  • Chap 4: Lpointeur de fonctionsne manque(nt) pas de piquant !

    4.1 Appel indirect des fonctions

    Extraits de : T. Monteil et al., Du langage C au C++, Presses Universitaires du Mirail, 2009.

    De la mme manire que le nom dun tableau reprsente ladresse dimplantation de ce tableau(cest--dire ladresse de son premier lment), le nom dune fonction (sans parenthses) reprsenteladresse de cette fonction, plus exactement ladresse de son point dentre. Cette adresse peut tre :

    attribu un pointeur (pointeur de fonction), ce qui permet lappel indirect de cette fonction, transmise comme paramtre dautres fonctions, place dans un tableau de pointeurs de fonction.

    4.1.1 Pointeur de fonction

    Un pointeur de fonction est une variable pouvant recevoir ladresse dune fonction. Dans ladclaration du pointeur, cette fonction est type, si bien quil ne peut ensuite accepter de recevoir queladresse dune fonction de mme type. Voici la forme gnrale de la dclaration dun tel pointeur :

    type ( * ptrFct ) (type, type, ...);

    Les parenthses de gauche sont obligatoires, sinon il sagirait dune fonction retournant unpointeur.

    4.1.2 Affectation dun pointeur de fonction

    Voici comment on affecte ladresse dune fonction un pointeur :

    double ( * Math ) ( int, int, double ) ; /* Pointeur de fonction */double Racine ( int, int, double ) ; /* Fonction */

    Math = Racine ; /* Affectation */

    4.1.3 Appel de fonction par un pointeur

    Ds quun pointeur reu ladresse dune fonction, on peut appeler celle-ci indirectement selonla forme gnrale suivante :

    /* dfinition dun pointeur */type ( * ptrFcn ) (type, type, ...);

    20

  • /* dclaration dune fonction de mme type renvoy */type Fonc (type, type, ...);

    /* affectation du pointeur */ptdFcn = Fonc;

    /* appel indirect de Fonc() */(*ptrFcn) (arguments);

    Dans le cas prsent, les deux instructions ci-dessus sont bien quivalentes un appel direct deFonc() puisque *ptrFcn a pour valeur Fonc.

    4.1.4 Passage de fonctions en paramtre

    Il est possible de transmettre une fonction en paramtre dune fonction appelante. Celle-ci em-ploie le nom de la fonction appele sans parenthses ni arguments la suite. Cest donc ladressedu point de lancement de cette fonction qui est empile. Pareillement, on peut transmettre indirec-tement une fonction en paramtre grce un pointeur sur cette fonction. Dans lexemple qui suit,Fonction() est appele deux fois avec deux (adresses de) fonctions diffrentes passes en argument,et une fois avec un pointeur de fonction :

    int Premiere (void) ;int Seconde (void) ;int ( * pFonction ) () = Seconde ;

    void Fonction (int (* ptrFoncArg) (), int Un , int deux ){/* Corps de Fonction () */}/* exemple dappels *//************************************************************************************//* Appel directement avec ladresse de la fonction Premier et les entiers 12 et -45 */Fonction ( Premiere, 12, -45);

    /************************************************************************************//* Appel avec ladresse de la fonction Premier et les entiers 0 et 0 */Fonction ( Seconde, 0, 0);

    /************************************************************************************//* Appel indirect avec ladresse de la fonction Seconde contenue *//* dans le pointeur de fonction *//* Les deux entiers sont affect avec la sortie des fonctions Premiere et Seconde */Fonction ( pFonction, Premiere (), Seconde () );

    21

  • 4.2 Lart et la manire...

    Pour bien comprendre lutilit de cette technique de programmation, il convient den rappelerlobjectif principal : nous voulons offrir le moyen un dveloppeur dapplication de confi-gurer un priphrique sans quil est besoin den connatre son fonctionnement. Le codeque produit le dveloppeur est uniquement dans la couche application (voir chapitre 1) et il ne peutfaire appel qu des fonctions de la couche pilote pour manipuler le matriel.

    Il se pose alors le problme suivant : comment offrir un service un dveloppeur dapplicationsqui lui permette dexcuter lors dune interruption une fonction quil aura dveloppe ?Il est noter que cette approche est quivalente la notion de services quoffre un systme dex-ploitation.

    Par exemple, il souhaite excuter la fonction :

    void Ma_Fonction_IT ( void ) /* Couche application */{

    /* Le code excuter pendant linterruption */}

    Il faut noter que, quoiquil en soit, cette fonction ne pourra ni prendre darguments en entre nien retourner puisque son appel ne sera pas dclencher logiciellement.

    Il faut donc que dans le Handler de linterruption (la fonction qui sera appele en premier lieulors de linterruption) il fasse appel cette fonction, soit :

    void XXX_IRQHandler ( void ) /* Couche pilote */{

    Ma_Fonction_IT ();}

    Or cela ne respecte pas nos rgles de codage, puisque le Handler doit faire partie de la couchepilote alors que Ma_foncion_IT fait partie de la couche application...

    Il ny a pas de solution miracle, il faut faire un peu de programmation avance ! Ca fait dubien aux neurones... Remarquons au passage que la solution est fournie dans le chapitre 2.

    Si dautres solutions effectives sont proposes, nous sommes preneur.

    4.2.1 ... de sen servir avec la solution dynamique

    Une premire solution consiste utiliser un pointeur de fonctions et scrit :

    /* Fichier de la couche "application" */void Ma_Fonction_IT ( void ){

    /* Le code excuter pendant linterruption */}

    /* faire dans le main */Init_Periph(Ma_Fonction_IT);

    22

  • /* Fichier de la couche pilote */void (* pFnc) (void) ; /* dclaration dun pointeur de fonction */

    void XXX_IRQHandler ( void ){

    if (pFnc != 0)(*pFnc) (); /* appel indirect de la fonction */

    }

    Init_periph (void (* ptrFonction) (void)){

    pFnc = ptrFonction; /* affectation du pointeur */}

    4.2.2 ... de sen passer avec la solution statique

    Une seconde solution consiste dfinir dans un fichier de configuration la fonction excuterpendant linterruption :

    /* Fichier de la couche application crite par lutilisateur du pilote*/void Ma_Fonction_IT ( void ){

    /* Le code excuter pendant linterruption */}

    /* Fichier de configuration modifiable par lutilisateur du pilote*/#ifdef HOOK_ON_XXX

    #define XXX_HOOK_CALL Ma_Fonction_IT ()#endif

    /* Fichier de la couche pilote uniquement visible par le dveloppeur du pilote */#ifdef HOOK_ON_XXXvoid XXX_IRQHandler ( void ){

    XXX_HOOK_CALL ;}#end

    4.2.3 Quelques commentaires pour se faire une religion

    Ces deux solutions sont lgantes et permettent de bien sparer les couches application et pilote.Elles ne sont pas strictement identiques au niveau fonctionnel et comportent quelques nuances :

    La version dynamique permet de configurer linterruption la vole et de la reconfigurer encours dexcution.

    La version statique ncessite une compilation du fichier pilote et donc de fournir son code, cequi nest pas le cas de la version dynamique. De plus, il faut maintenir le fichier de configura-tion.

    23

  • La version statique va gnrer uniquement un Handler sil y a une fonction excuter alors quela version dynamique gnre un Handler avec 4 lignes de code, plus une fonction dinitialisation(1 ligne) et son appel du main (1 ligne), ce qui permet davoir un code plus compact.

    24

  • Chap 5: Une mise au pointsimpose !

    5.1 Les points darrts et les espions

    5.1.1 Les diffrents points darrts

    Pour mettre au point vos programmes en assembleur en 3e anne, vous avez utilis des pointsdarrt dexcution. Il suffit de placer un tel point darrt sur une instruction pour que lexcution sesuspende lorsque ladresse de cette instruction est atteinte par le compteur ordinal du STM32. Ona alors tout loisir pour observer les donnes et les registres, et, ventuellement, les modifier avantde reprendre lexcution.

    Vision offre dautres possibilits que nous allons rapidement passer en revue.1. Tout point darrt dispose dun systme de comptage (count) qui fait que le point darrt

    ne devient actif que sil a t atteint le nombre de fois indiqu. Par dfaut, count=1, et lepoint darrt fonctionne chaque fois que ladresse est atteinte. Si, par exemple, count vaut3, les 2 premiers passages lendroit du point darrt ne dclencheront rien, mais lexcutionsinterrompra au 3e, puis 4e, 5e, 6e, 7e, passage.

    2. Lorsquun point darrt actif est atteint, le dbogueur peut aussi lancer une commande choisieau pralable par lutilisateur. Une fois la commande finie, lexcution du programme reprend,sans marquer darrt (le point "darrt" est alors plutt un point de dtournement vers lemoniteur).

    3. Outre le point darrt dexcution, il existe deux autres types de points darrts : le point darrt daccs la mmoire : le point darrt est actif si une variable, quil faut bien

    sr spcifier lors de la dfinition du point darrt, vient dtre utilise par une instruction.On peut demander ragir tout type daccs, ou filtrer en ne considrant que les accs enlecture ou ceux en criture. On peut aussi demander de ne ragir que si la variable prendune certaine valeur.

    le point darrt conditionnel : on associe cette fois au point darrt une expression condi-tionnelle qui sera automatiquement teste en permanence (aprs lexcution de chaque ins-truction). Si la condition devient vraie, le point darrt est atteint.

    N.B. Contrairement au point darrt dexcution, ces deux derniers points darrt ne sont paslis une instruction spcifique.

    En rsum, on peut dire quassocies chaque point darrt, on trouve trois informations appelesexpression, compte (count) et commande. Selon que lexpression, obligatoire, est

    une instruction (code) : on a un point darrt dexcution ; une variable, ou une expression boolenne sur la valeur dune variable, avec laccs READ, ou

    WRITE, ou READWRITE : on a un point darrt daccs ; une expression boolenne ou une variable sans mention daccs : on a un point darrt condi-

    tionnel. La commande est facultative, comme nous lavons vu.

    25

  • 5.1.2 Pose dun point darrt

    Il exite deux possiblits pour poser un point darret : soit avec la commande spcifique BS dansla fentre de dialogue Output Windows, soit travers une fentre de gestion associe.

    La commande BS

    Placer un point darrt dexcution ordinaire est facile : il suffit de cliquer deux fois sur unespace de la ligne dinstruction, ou dutiliser le bouton de dpose. Pour placer un point darrt pluslabor, on peut faire appel la commande du dbogueur BREAKSET (ou BS, cf. la documentationen ligne Vision Users Guide : Debug Commands). Elle doit tre tape dans la ligne de commandedu dbogueur, ou place dans un fichier dinitialisation .ini. Voici la syntaxe de cette commande :

    BS [READ | WRITE | READWRITE] expression [, compte] [, "commande"]

    ainsi que quelques exemples :

    Commande au dbogueur Arrt

    BS main E sur la 1re instruction de la fonction main()BS \Timer_1234 \50 E sur linstruction la ligne 175 du module HorlogeBS Port_IO_Blink 4 E partir du 4e appel la fonction

    Port_IO_Blink()(1re instruction)BS TicTac==1 C si le boolen TicTac devient vraiBS READWRITE Heure A sur tout accs la variable HeureBS WRITE Test==100,1, " printf(\"Le test vaut 100 \\n\")"

    A seulement si Test 100, lancement dune com-mande (printf() fonc. prdfinie)

    BS WRITE Carac < 65 A si Carac reoit une valeur infrieure 65BS Carac < 65 "MaFonction(4)" C si Carac est < 65, lance la fonction MaFonc-

    tion() avec largument 4

    Remarques :

    1. Dans le dernier exemple, la commande effectue sous condition consiste en lappel dune fonc-tion de mise au point dfinie par lutilisateur, en lui fournissant largument 4.

    2. Notez aussi que les deux derniers exemples sont dfinis avec exactement la mme expressionboolenne, Carac < 65, et pourtant, le premier correspond un point darrt daccs, alorsque le second est un point darrt conditionnel.

    3. Notez galement que la vitesse de simulation est considrablement diminue par lutilisationde points darrt conditionnels. Pour la surveillance de variables dterministes, il vaut doncmieux employer des points darrt sur accs. En revanche, la surveillance des pattes du STM32exigera lemploi de points darrt conditionnels.

    4. Toutes ces commandes ne sont taper quune seule fois : lorsque lon fait des allers/retoursentre ldition et le debug, ces informations sont conserves.

    26

  • Figure 5.1 Fentre de gestion des points darrts

    Pose dun point darrt grce la fentre de gestion des points darrt

    Pour un dbutant, lutilisation de la commande BS nest pas trs facile. Il est alors plus simple defaire appel la fentre de gestion des points darrts, appele par Debug Breakpoints,... (Voirfigure 5.1) Pour poser un nouveau point darrt dans cette fentre, vous devez au moins y fournirlexpression dfinissant ladresse daccs, et, ventuellement, modifier le compte, spcifier laccsen mmoire ainsi que le nombre dobjets (ou doctets) concerns partir de ladresse daccs, etspcifier une commande. La figure suivante reprsente cette fentre de gestion, au moment o lonsapprte dfinir le dernier point darrt du tableau prcdent (conditionnel car aucune des casesAccess na t coche). Les autres points darrt prsents correspondent aussi ceux de ce tableaudexemples.

    5.2 Emulation avance

    Le logiciel de dveloppement que vous utilisez offre des possibilits de contrle de lexcution duprogramme qui permettent davoir une grande matrise de ce qui passe. Nous distinguerons dans ceparagraphe deux aspects particuliers qui sont le contrle de lexcution et le contrle des activitssur les broches du circuit

    5.2.1 Contrle de lexcution

    Pour avoir une comprhension complte et une action possible de lexcution dun programmeen mode simul le logiciel donne accs des variables du systme. Attention il ne faut pas lesconfondre avec des registres du microcontrleur (mme si certaines dentre elles apparaissent commetel dans le fentre register en mode debug). Ces variables vous permettent, depuis une fonction ou

    27

  • une commande, dobtenir des informations sur ltat de votre programme lorsquun point darrtest atteint. Elles permettent aussi de contrler la reprise de lexcution. Vous les trouverez listesen totalit dans le documentation Vision Users Guide -> Debbuging Voici les trois variablessystmes les plus utiles :

    nom type accs Description sommaire

    _break_ unsigned int R/W Arrte lexcution si sa valeur est diffrente de 0(voir son utilisation au paragraphe suivant).

    states unsigned long R Valeur courante du compteur dtats (coupsdhorloge) de la CPU. Ce compteur est remis 0 au dbut de toute excution.

    $ unsigned long R/W Valeur courante du pointeur de programme. Onpeut changer sa valeur pour effectuer un sautdans le code.

    Remarques : La variable states se dcline en variable sec en convertissant le nombre decoups dhorloge en seconde par la simple multiplication la priode de lhorloge CPU. Ces variablespermettent donc davoir un mesure trs prcise du temps dexcution qui sera coul en mode rel.

    La variable _break_ permet quant elle davoir une influence sur le droulement de lexcutionde lmulation. Quand une fonction ou une commande est appele lorsquun point darrt a tatteint, vous pourrez remarquer que normalement, lexcution reprend sans marquer darrt. Il estpossible dobtenir quand mme un arrt, en programmant la fonction pour quelle change la valeurde la variable _break_.

    Nous allons voir quelques exemples de fonctions dfinies par lutilisateur, en supposant quon aplac un point darrt devant ragir tout accs en criture au registre GPIOB_ODR : BS WRITEGPIOB_ODR. Le comportement dun tel point darrt dpend de la commande associe

    ? Sil ny a aucune commande prvue, lexcution stoppe chaque criture dans loctet de poidsfaible du port 3.

    ? Si lon associe au point darrt la fonction suivante :

    FUNC void SansArret (void){if ((PORTB & 0x0200) == 0) /* PORTB est un VTREG : on teste la borne GPIOB.9 */

    printf ("La borne = GPIOB.9 est 0 !\n") ;else

    printf ("Bip\n") ;}

    Pour cette, on a employ le VTREG PORTB (cf.paragraphe 5.2.2 pour la comprhension desVTREG). Ainsi on observe ce qui se passe au niveau de lactivit lectrique des broches (PORTB)et non pas au niveau de lactivit logique du registre sens la piloter (GPIOB_ODR). Ceci permetde confirmer, par exemple, que la configuration de direction est bien positionne. Lexcution duprogramme ne sinterrompt pas, mais chaque fois que le point darrt est atteint, on a un message

    28

  • qui saffiche dans la fentre de messages du dbogueur : les niveaux bas de la borne 9 du portGPIOB sont identifis par un message particulier.

    ? Changeons de fonction :

    FUNC void AvecArret (void){if ((PORTB & 0x0200) == 0) /* PORTB est un VTREG : on teste la borne GPIOB.9 */

    {printf ("La borne = GPIOB.9 est 0 !\n") ;_break_ = 1 ; /* variable systme, globale, permanente */}

    elseprintf ("Bip\n") ;

    }

    Tant que le bit 9 nest pas 0, lexcution continue avec affichage du message "Bip" chaquecriture dans le port GPIOB (pf). Puis lexcution sinterrompt systmatiquement pour toute autremodification du port GPIOB.

    ? Avec lexemple suivant, lexcution sarrte chaque criture avec le bit 3 0 :

    FUNC void SemiArret (void){if ((PORTB & 0x0200) == 0) /* PORTB est un VTREG : on teste la borne GPIOB.9 */

    {printf ("La borne = GPIOB.9 est 0 !\n") ;_break_ = 1 ; /* arrt */}

    else{printf ("Bip\n") ;_break_ = 0 ; /* pas darrt */}

    }

    ? Nous avons vu que tout point darrt pouvait ne devenir actif quaprs avoir t atteint uncertain nombre de fois, grce la proprit de comptage (count). Avec _break_, on peutraliser lopration duale : fabriquer un point darrt qui ne fonctionne quun certain nombrede fois, en dbut de lexcution. Par exemple :

    29

  • FUNC void Arret_ X _ fois (void){if ((PORTB & 0x0200) == 0) /* PORTB est un VTREG : on teste la borne GPIOB.9 */

    {printf ("La borne = GPIOB.9 est 0 !\n") ;if (_break_ != 0) /* ou if ( !_break_) */

    _break_ = _break_ - 1 ;}

    }

    Avant de lancer lexcution, il faut initialiser la variable _break_ en tapant, par exemple, lacommande _break_ = 5. Lexcution sarrtera alors 4 fois, puis ne sarrtera plus.

    5.2.2 Simulation de lactivit des broches du STM32

    Lorsque lon cherche mettre au point un programme pour un microcontrleur en mode simul,une des difficults majeures est de pouvoir agir (et observer) sur ce quil se passe au niveau desbroches du circuit. Cela induit que lon soit capable de simuler galement lenvironnement extrieuret donc de se mettre dans des conditions de travail qui sapproche le plus possible des conditionsrelles dexprimentation. Cette simulation des interactions aux bornes du STM32 peut seffectuerde deux manires : la premire mthode, rudimentaire, consiste utiliser les fentres ouvertes parle menu droulant Peripherals.

    Remarque : souvenez-vous que sous simulation, vous ne bnficiez de la mise jour rguliredes fentres du dbogueur que si vous avez coch loption View Periodic Window Update.

    La seconde mthode, plus puissante, fait appel une vritable programmation simulant le mondeextrieur laide de fonctions (que nous appellerons fonctions de lutilisateur), crites en un langageC rduit, contenues dans un fichier dinitialisation dont le nom prsente le suffixe .ini. Ces fonctions- fonctions de mise au point et fonctions signal - sont destines au dbogueur, et ne font pas partiedu programme pour le STM32, mme sil est dusage dinclure ce fichier .ini dans le projet. Onindique au dbogueur de prendre en compte ces fonctions en citant le nom de ce fichier dans le menuProject Options for Target Xxx Debug Initialization File ou bien en utilisantla commande au dbogueur INCLUDE (cf. dernier paragraphe).

    Les fonctions de lutilisateur

    Ces fonctions, destines au dbogueur, sont indpendantes du programme mettre au point.Elles permettent, comme nous venons de le dire, la simulation du monde extrieur. Pour les crire,lutilisateur emploie la syntaxe du langage C-ANSI, quelques restrictions prs (cf 5.2.2). Si elles en-voient des signaux - gnralement priodiques - vers les pattes dentre des priphriques du STM32on les appelle fonctions signal ; elles nentrent en fonction que si elles ont t lances en tapant leurnom dans la ligne de commande du dbogueur. Les fonctions de mise au point, elles, permettentdobserver ltat lectrique des pattes de sortie des priphriques du STM32 et permettent aussidobserver et de modifier tous les registres du STM32, ainsi que toutes les variables de son pro-gramme. Dans ce cas, elles sont souvent associes un point darrt, cest--dire quune certaine

    30

  • fonction de mise au point nest lance que si une condition darrt a t atteinte par le programme(cf. les points darrt) . Dautre part, pour Vision, il existe en fait deux classes de fonctions : lesfonctions dfinies par lutilisateur, celles dont nous venons de parler, et les fonctions prdfinies,cest--dire faisant partie de la bibliothque fournie avec le dbogueur (built-in functions). Avant dedtailler ces fonctions, voyons comment seffectue linterface entre les deux simulateurs.

    Les bornes du STM32 (VTREG)

    Pour avoir accs aux bornes du microcontrleur, il faut que les fonctions crites par lutilisateurpuissent les dsigner. Pour cela, ltat lectrique des pattes des ports du STM32 est gard dans desregistres spciaux appels VTREG (Virtual Target Register). Ces registres sont externes au STM32et font partie du simulateur. Ils peuvent contenir des valeurs analogiques (entres du convertisseuranalogique-numrique ADC) ou numriques. En voici quelques-uns :

    VTREG Description Type Type C

    PORTA E/S numriques 16 bits unsigned char, ucharPORTB E/S numriques 16 bits unsigned char, ucharPORTC E/Snumriques 16 bits unsigned int, uintPORTD E/S numriques 16 bits ( !3 pf utiles) unsigned int, uint

    ADC1_INy Lentre analogiques x du convertisseur 1 rel floatADC2_INy Lentre analogiques x du convertisseur 2 rel float

    SxIN Le buffer dentre de la liaison srie x 16 bits unsigned int, uintSxOUT Le buffer de sortie de la liaison srie x 16 bits unsigned int, uintSxTIME La vitesse (baudrate) de la liaison srie x 16 bits unsigned int, uint

    Attention ! Ne confondez pas GPIOB_ODR, le registre de donnes en sortie du port GPIOB,interne au STM32, et PORTB, le VTREG indiquant les niveaux physiques des pattes du STM32,vues depuis le monde extrieur. Les deux entits (GPIOB_ODR et PORTB) existent bien maispeuvent prendre des valeurs diffrentes. Cela correspond en mode rel au cas o une broche dentreTTL est niveau haut alors que le bit du registre correspondant reste au niveau bas ( cause dunemauvaise configuration du GPIOB_CRH par exemple).

    Fonctions prdfinies

    En voici quelques unes parmi les plus courantes (liste complte et documentation de Vision-Debugging - Debug Functions - Predifined Function). Ces fonctions lorsquelles sont insres dansune script de simulation (fichier .ini) permettent de se fabriquer un scnario dvnements et devisualiser ce quil se passe en raction. Lide de base de toute cette approche est de tester unexcutable sans modifier une seule ligne de celui-ci : le code est instrumentalis depuis lextrieur.

    31

  • Retour Nom Argument Description

    void printf ("format",...) comme printf() du langage C-ANSIint getint ("chane dinvite") demande lutilisateur de fournir un entierint rand (int seed) fournit un entier alatoire sign -

    32768..+32767void twatch (ulong states) bloque lexcution de la fonction durant le

    nombre de coups dhorloge pass en argu-ment.

    void exec ("commande(chane)" excute depuis une fonction une com-mande au dbogueur

    uchar _RBYTE (adresse) lit un octet (char) en mmoireuchar _RWORD (adresse) lit un mot (int) en mmoirevoid _WBYTE (adresse, uchar valeur) crit un octet en mmoirevoid _WWORD (adresse, uchar valeur) crit un mot en mmoire

    Remarque : mis part printf(), vous ne disposez pas des fonctions dentres/sorties (stdio)du langage C. Cela peut paratre limitatif mais noubliez pas que le but des ces fonctions est defaire de la mise au point dapplication et non des interfaces homme/machine volues.

    Les fonctions de mise au point

    La syntaxe gnrale de ces fonctions est la suivante :

    FUNC (){

    }

    Exemple :

    /* Etat()* Indique le niveau dentre appliqu AN0, et qqs registres.*/FUNC void Etat (void)

    { /* pas de variables locales dans cet exemple */printf ("===================================\n") ;printf (" Entree analogique-0 : %f Volts \n", ADC1_IN1) ; /* VTREG ADC1_IN1 */printf ("===================================\n\n") ;printf ("****** Registres du STM32 *******\n") ;

    32

  • printf ("* R1 R2 R3 R4 R5 R6 \n") ;printf ("* %08X %08X %08X %08X %08X %08X \n",

    , R1, R2, R3, R4, R5, R6) ; /* registres */printf ("********************************\n") ;printf ("* Registre (SP) : %04X\n", R13) ;printf ("* Program Counter : %06LX\n",R15 ) ; /* PC courant */

    /* (lettre L) entier long (32 bits)*/printf ("********************************\n") ;}

    Pour appeler cette fonction, il faut taper sur la ligne de commande du dbogueur :Etat()

    Etat() et lexcution, dans la fentre de messages du dbogueur, pourrait ressembler :

    ===================================Entree analogique-0 : 2.452000 Volts===================================****************** Registres du STM32 ******************** R1 R2 R3 R4 R5 R6* 00000001 00000200 40010C00 00000000 00000000 00000000********************************* Registre (SP) : 20004FB8* Program Counter : 80004A0********************************

    La fonctions signal

    La syntaxe gnrale de ces fonctions est la suivantes :

    SIGNAL void (){

    }

    Une fonction signal permet de rpter des actions externes, comme par exemple lenvoi de signauxpriodiques ou dimpulsions vers le STM32 simul. Une fonction signal doit toujours faire appel twatch() ou swatch(). Voici un exemple de fonction qui envoie des rampes priodiques dchelonsde tension (100 mV) vers lentre analogique n 0.

    33

  • /* Analog0(float Maxi)* Simule un signal variable analogique appliqu lentre AN0.* Argument dentre fournir : la valeur maxi du signal.* Forme du signal : priodique, fonction toit asymtrique, par incr-* ments (ou dcrments) de 0,1V.*/ Signal void Analog0 (float Maxi)

    { float SignAnalog ;printf ("Signal en marche. Maximum = %f.\n", Maxi) ;while (1) /* linfini... Donc signal priodique */{SignAnalog = 0.0 ; while (SignAnalog Maxi) /* Croissance du signal */{ADC1_IN0 = SignAnalog ; /* Signal appliqu au VTREG ADC1_IN0 */swatch (0.01) ; /* Attendre 0.01 secondes */SignAnalog = SignAnalog + 0.1 ; /* Signal crot */

    }SignAnalog = Maxi ;while (SignAnalog Maxi) /* Croissance linaire du signal */{ADC1_IN0 = SignAnalog ; /* Signal appliqu au VTREG ADC1_IN0 */swatch (0.02) ; /* Attendre 0.02 secondes */SignAnalog = SignAnalog - 0.2 ; /* Signal crot */

    }}

    }

    Dans cet exemple, vous notez lutilisation? dune variable locale SignAnalog,? du VTREG ADC1_IN0? des fonctions prdfinies printf() et swatch().

    Lintervalle entre deux paliers de tension conscutifs est de 4 secondes lors de la monte du signal, etde 2 secondes lors de la descente. La valeur maximale atteinte par le signal est donne en argumentlors de lappel, par exemple Analog0(1.2) Une fois ainsi lance, cette fonction ne sarrte que si ondtruit la fonction par la commande au dbogueur : SIGNAL KILL Analog0

    Restrictions et diffrences par rapport au C-ANSI

    Lors de lcriture dune fonction, lutilisateur emploie un langage C limit selon les points essen-tiels suivants (vous trouverez plus de dtails p. 119 dans Vision2 Getting Started) :

    ? Majuscules et minuscules sont confondues : les VTREG ADC1_IN2 ou PORTC peuvent aussitre dsign Adc1_In1 et portC.

    34

  • ? Pas de prprocesseur : #define, #include, #ifdef ne marchent pas !? Dclaration de variables globales interdites. On peut cependant utiliser des grandeurs globales

    si on les a au pralable fabriques sous dbogueur par la commande DEFINE .? Aucune variable ne peut tre initialise lors de sa dclaration.? Structures interdites !? Le type de la valeur retourne par une fonction ne peut tre un pointeur.? Pas de rcursivit.? Pas dappel indirect de fonctions.

    Quelques commandes utiles

    En guise de bouquet final, voici listes ci dessous quelques commandes qui pourront agrmenterlutilisation de ces fonctions utilisateurs :

    Nom Exemple Action

    EVALUATE EVAL 0x1234 donne la valeur de 0x1234 dans diverses bases dereprsentation

    KILL KILL FUNC * dtruit toutes les fonctions (signal ou non) char-ges par lutilisateur dans le dbogueur

    KILL FUNC Toto dtruit la fonction de mise au point Toto()SIGNAL SIGNAL KILL Titi dtruit la fonction signal Titi()

    SIGNAL STATES donne ltat des diverses fonctions signalDEFINE DEFINE CHAR UnOctet dfinit une grandeur globale intitule UnOctet

    DEFINE FLOAT UnReel dfinit un rel globalAffectation UnOctet=0x80 affecte un octet

    UnReel=3.14159 affecte un relINCLUDE INCLUDE Tutu.ini charge le dbogueur avec les fonctions ou les

    commandes incluses dans le fichier Tutu.iniDIR 1 DIR SIGNAL liste toutes les fonctions signal

    DIR UFUNC liste toutes les fonctions de mise au point crespar lutilisateur

    DIR BFUNC liste les fonctions prdfiniesDIR FUNC liste toutes les fonctions de Vision

    35

    On en tient une coucheIntroduction et dfinitionsArchitecture logicielle recommandeGuide des bonnes maniresLa couche matrielle

    Faudrait pas prendre les pilotes pour des navigateurs ! Premier exemple : configuration d'une broche d'entre-sortiePilote dynamiquePilote statique

    Second exemple : configuration d'une interruptionPilote dynamiquePilote statique

    Bah ! Les masquesOprateur logiques et bit bitMettre un bit 1Mettre un bit 0Inverser un bitInitialiser une tranche de bits

    L'pointeur de fonctions ne manque(nt) pas de piquant !Appel indirect des fonctionsPointeur de fonctionAffectation d'un pointeur de fonctionAppel de fonction par un pointeurPassage de fonctions en paramtre

    L'art et la manire... ... de s'en servir avec la solution dynamique... de s'en passer avec la solution statiqueQuelques commentaires pour se faire une religion

    Une mise au point s'impose ! Les points d'arrts et les espionsLes diffrents points d'arrtsPose d'un point d'arrt

    Emulation avanceContrle de l'excutionSimulation de l'activit des broches du STM32