IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Embarqué Discussion :

HWA : une approche originale de la programmation du matériel en langage C


Sujet :

Embarqué

  1. #1
    Membre à l'essai
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2017
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Jura (Franche Comté)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2017
    Messages : 3
    Points : 14
    Points
    14
    Par défaut HWA : une approche originale de la programmation du matériel en langage C
    Bonjour à tous,

    Je vous présente mon projet HWA (HardWare Advanced), qui vise à établir une syntaxe élégante pour programmer des microcontrôleurs ou des périphériques en langage C.

    Il ne s'agit pas d'une bibliothèque d'abstraction mais d'un ensemble de macros qui produisent un code C qui sera correctement optimisé par le compilateur. Il n'y a donc aucun coût en termes de vitesse d'exécution ou de consommation mémoire et besoin de rien d'autre qu'une chaîne de compilation C (C11).

    Un court exemple pour un STM32 :

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    #include <hwa/stm32f103rbt6.h>
     
    #define AHBHZ		HW_DEVICE_HSIHZ		// AHB frequency
    #define COUNTER		counter2
    #define PERIOD		0.25			// Blinking period
     
    #define LED1		pa2
     
     
    /*  Service counter IRQ: toggle the LED.
     */
    HW_ISR( COUNTER )
    {
      hw( clear, irq(COUNTER) );
      hw( toggle, LED1 );
    }
     
     
    int main ( )
    {
      hwa( begin_from_reset );
     
      /*  Power the controllers we use
       */
      hwa( power, (LED1,port), on );
      hwa( power, COUNTER, on );
      hwa( commit );
     
      /*  Configure GPIOs
       */
      hwa( configure, LED1, mode, digital_output, frequency, lowest );
     
      /*  Configure the counter
       */
      hwa( configure, COUNTER,
           mode,      counter,
           clock,     from_apb1_psc,
           direction, up_loop,
           prescaler, AHBHZ*0.001 - 1,	// 1 ms clock period
           reload,    PERIOD/2 / 0.001 - 1,
           run,	  yes );
      hwa( commit );
     
      hw( turn, (COUNTER,nvic), on );
      hw( enable, irq(COUNTER) );
     
      /*  Sleep between interrupts
       */
      for(;;) {
        hw( sleep_until_irq );	// sleep_until_event is OK too.
      }
    }

    En bref, HWA fournit un ensemble d'objets prédéfinis, qui représentent le contenu du microcontrôleur, et deux instructions génériques :
    • 'hw(...)' qui effectue immédiatement une action sur un objet ;
    • 'hwa(...)' qui enregistre une action dans une transaction qui sera exécutée par 'hwa(commit)'.

    Ces instructions acceptent un nombre variable d'arguments. Typiquement, un nom d'action, un objet, une liste de paires argument/valeur qui peuvent être obligatoires ou optionnels.

    Les objets sont désignés par leur nom ou par un chemin constitué d'une suite de noms d'objets. Par exemple '(LED1,port)' désigne l'objet 'port' qui gère la broche LED1.

    J'ai porté une attention particulière à la gestion des erreurs qui peut rapidement devenir pénible avec les macros. Normalement, en cas de problème, le compilateur affiche un message éclairant, par exemple pour rappeler la syntaxe d'une action ou les valeurs acceptables pour un argument.

    Ce projet est en développement (chaotique !) depuis des années mais je pense que ses fondations commencent à bien se stabiliser.

    Le code est hébergé sur Github ici, une documentation avec des exemples : .

    L'objectif de mon intervention ici est d'évaluer l'intérêt que ce projet suscite et de récolter des idées, des remarques qui pourraient me guider pour la suite. Je réponds aux questions s'il y en a !

  2. #2
    Responsable Arduino et Systèmes Embarqués


    Avatar de f-leb
    Homme Profil pro
    Enseignant
    Inscrit en
    Janvier 2009
    Messages
    12 760
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Sarthe (Pays de la Loire)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Janvier 2009
    Messages : 12 760
    Points : 57 908
    Points
    57 908
    Billets dans le blog
    42
    Par défaut
    Bonjour,

    C'est vrai que c'est original, voire déroutant, ce qui ne retire rien à la qualité du travail. Je vois que ce projet a été commencé il y a plusieurs années, tu dois avoir du recul dessus.

    Je vois à peu près l'idée avec ce genre de macros...

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    hw( configure, PIN_LED, mode, digital_output );

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    hw( write, gpio1, 0 );

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    hw( toggle, PIN_LED );

    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      /*  Configure the UART  */
      hwa( configure, UART,
           bps,       BPS,
           databits,  8,
           parity,    none,
           stopbits,  1     );
    etc.

    Je suppose qu'il y a un effort d'apprentissage pour comprendre cette abstraction, mais il faut quand même comprendre à bas niveau son micro pour l'exploiter (activer, régler les horloges par exemple) et donc on ne s'adresse pas ici aux débutants (comme Arduino avec son "langage Arduino" qui masque énormément de choses à bas niveau, et c'est tout son intérêt aussi).
    Donc si l'utilisateur doit être expérimenté et qu'il connait déjà la programmation "classique" de son micro, quel avantage aura-t-il à apprendre en plus le fonctionnement de cette surcouche ?
    Pour du prototypage rapide ? Pour faciliter la portabilité sur d'autres micros ?

    Bref, je m'interroge beaucoup sur le besoin au départ... As-tu des retours qui expliqueraient pourquoi ou dans quelles situations les utilisateurs utilisent cette biblio ?

  3. #3
    Membre à l'essai
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2017
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Jura (Franche Comté)

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : Août 2017
    Messages : 3
    Points : 14
    Points
    14
    Par défaut
    Bonjour f_leb,

    Merci pour ton commentaire.

    Le besoin est né vers 2005 alors que j'utilisais divers Atmel AVR8. Même sans utiliser des fonctions spécifiques de contrôleurs (timers, UARTs...), passer d'un ATmega8 à un ATmega88 nécessitait de corriger le code. Pareil pour passer à un ATmega16 ou un ATtiny44. C'est quand je me suis intéressé aux STM32 que j'ai commencé à écrire HWA, en 2010.

    Les AVR8, et avr-libc, ont quelques défauts qui m'exaspèrent, notamment :
    • d'un circuit à l'autre, les mêmes registres peuvent changer de nom ou d'organisation bien que les contrôleurs intégrés soient identiques ;
    • les noms des ISR peuvent changer d'un modèle à l'autre et ne sont pas forcément « évidents » ;
    • une macro comme _BV() n'a rien de sexy et n'évite pas de devoir se plonger dans la doc.


    Les contrôleurs sont très souvent programmés pour faire les mêmes choses quels que soient les circuits utilisés. J'ai donc cherché avec HWA à élaborer une syntaxe qui fasse en sorte que le même type de contrôleur se programme avec le même code, quel que soit le circuit utilisé. Plus difficile à faire avec les AVR8 aux registres hétérogènes donc c'est par eux que j'ai commencé.

    Il y a aussi une recherche esthétique, c'est certain. Pour moi, un bon code ce n'est pas seulement un code qui produit les meilleures performances en utilisant le minimum de ressources. Il faut aussi qu'il ait belle allure et donner envie de le lire.

    Il y a toujours un effort d'apprentissage quand on utilise un outil. Donc la question est : « quel est l'avantage de HWA par rapport aux autres outils ? » Si ce projet aboutit, je dirais :
    • une syntaxe concise et homogène, la même quel que soit le circuit cible ;
    • un code facile à lire et à modifier, utilisant des mots-clés peu nombreux et faciles à deviner ;
    • donc un code facile à porter et à adapter à une reconfiguration du matériel ;
    • des performances maximales ;
    • la possibilité d'exploiter toutes les ressources du matériel ;
    • aucune dépendance extérieure ;
    • des messages d'erreur qui guident vers la solution.


    À qui s'adresse HWA ? Je dirais à tous, du débutant à l'ingénieur. HWA pourrait aussi intéresser les fondeurs. C'est peut-être prétentieux mais pour ce que j'en connais je le trouve plus puissant que CMSIS ou Arduino.

    HWA n'est pas une bibliothèque, c'est un ensemble de définitions dans des fichiers d'en-tête (quasiment tout est pris en charge par le préprocesseur). HWA symbolise sous une forme standardisée l'architecture du circuit cible ; il faut la connaître plus ou moins selon le degré d'exploitation qu'on veut en faire. Si l'on s'en tient à des fonctions de base, on doit pouvoir s'en servir sans avoir besoin de la datasheet. À l'opposé, HWA donne un accès direct aux registres (avec style !).

    Quelques concepts de base à connaître pour utiliser HWA :
    • les noms des objets : pa1, pb4, counter0, uart1... ;
    • les noms des ISR, un objet et éventuellement une raison : counter1, (counter4,overflow), (uart1,rx)... ;
    • les noms des IRQ, idem précédé de irq() : irq(counter1), irq(counter4,overflow), irq(uart1,rx)... ;
    • les noms des actions : configure, read, write... ;
    • les noms des des arguments des actions et leurs valeurs sont souvent les mêmes : direction, output... ;
    • un mécanisme de chemin permet de nommer un objet par rapport à un autre : (counter2,channel3), (pa2,port,odr)... ;


    HWA peut aussi gérer des contrôleurs externes ou en émuler par logiciel en utilisant la même syntaxe. Par exemple, un contrôleur LCD HD44780 piloté par un PCF8574 à travers une interface TWI logicielle :
    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    #include <hwa/attiny84a_pu.h>
     
    #include <hwa/swtwimaster.h>
    #include <hwa/pcf8574.h>
    #include <hwa/hd44780.h>
     
    #define TWI		HW_SWTWIMASTER( scl, pb0,	\
    					sda, pb1,	\
    					bps, TWI_BPS )
     
    #define TWI_BPS		400000
     
    #define LCD		HW_HD44780( lines, 2,			\
    				    cols,  16,			\
    				    e,     HW_IO(PCF, 1, 2),	\
    				    rs,    HW_IO(PCF, 1, 0),	\
    				    rw,    HW_IO(PCF, 1, 1),	\
    				    data,  HW_IO(PCF, 4, 4) )
     
    #define PCF		HW_PCF8574( interface, TWI, address, 0x27 )
     
    #define LCD_LED		HW_IO( PCF, 1, 3 )
     
    HW_DECLARE( TWI );
    HW_DECLARE( PCF );
    HW_DECLARE( LCD );
     
    HW_DEFINE(TWI);
    HW_DEFINE(PCF);
    HW_DEFINE(LCD);
     
     
    int main(void)
    {
      hw( configure, TWI, bps, TWI_BPS );
      hw( configure, PCF );
     
      hw( write, LCD_LED, 0 );
      hw( init, LCD );
      hw( write, LCD_LED, 1 );
     
      while(1) {
        int i = 0;
        int line = 0;
        for(i=0; i<1000 ; i++) {
     
          if ( line == 0 ) {
    	hw( gotoxy, LCD, 0, line );
    	xprintf( HW_FUNCTION(LCD,putchar), " g=%3d", i);
          }
          else {
    	hw( gotoxy, LCD, 8, line );
    	xprintf( HW_FUNCTION(LCD,putchar), " g=%03d", i);
          }
     
          line++;
          line %= 2;
          hw_waste_cycles( 0.25 * HW_SYSHZ );
        }
      }
    }

Discussions similaires

  1. Lancer une application à partir d'un programme
    Par Bouguennec dans le forum API, COM et SDKs
    Réponses: 2
    Dernier message: 05/11/2005, 19h02
  2. création d'une base de donnée par programme
    Par lassad dans le forum Bases de données
    Réponses: 9
    Dernier message: 18/10/2005, 16h36
  3. [PIC 16C84] Ajouter une eeprom externe i2c à un programme
    Par jacques8 dans le forum Autres architectures
    Réponses: 2
    Dernier message: 30/09/2005, 17h11
  4. Réponses: 2
    Dernier message: 24/06/2003, 20h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo