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

C Discussion :

Variable pointant sur un registre hardware !


Sujet :

C

  1. #1
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut Variable pointant sur un registre hardware !
    Salut à tous.

    Je connais le 'C', mais je ne suis pas familiarisé avec l'accès aux registres du hardware.
    Je bidouille en assembleur ARM sur la raspberry et je sais faire du Bare-Metal.
    Mon problème est que j'aimerai accéder aux registres des GPIO afin de créer un programme en 'C' sans passer par des bibliothèques.
    Je sais que c'est possible sauf que je n'ai jamais fait ça en 'C'.

    J'aimerai savoir comment déclarer une variable qui va pointer sur un registre de la Raspberry Pi Zero.
    Ce registre se trouve à l'adresse 0x20200000 et se nomme adresse de base des GPIO.

    Pour qualifier un registre, je suppose qu'il faut :

    1) la déclarer "extern" car la variable n'est pas propre au programme 'C'.

    2) la déclarer "volatile" car cette variable peut être modifiée par un moyen extérieur au programme.

    3) la déclarer en tant que pointer afin de lui attribuer une adresse physique.
    Cette adresse physique est 0x20200000.

    4) le type de cette variable doit être du même genre que le registre.
    Dans mon cas, il s'agit d'un mot de 32 bits, non signé.

    5) voici mon exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdio.h>
    #include <stdlib.h>
     
    typedef unsigned int            uint32_t;
    #define _GPIO_BASE              (0x20200000)
     
    extern volatile uint32_t        *_gpio;
     
    int main(void)
    {
            _gpio = (uint32_t*)_GPIO_BASE;
     
            exit(EXIT_SUCCESS);
    }
    A la compilation, cela me retourne l'erreur suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /usr/bin/ld: main.o: in function `main':
    main.c:(.text+0x18): undefined reference to `bcm2835_gpio'
    collect2: error: ld returned 1 exit status
    make: *** [makefile:54: lancer] Error 1
    Comment faire ?
    Pouvez-vous me dire ce qui ne va pas dans mon exemple ?

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  2. #2
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Salut,

    Si ton programme a accès à cette zone mémoire, tu peux interagir avec ton registre de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #include <stdint.h> //uint32_t
    #define  GPIO_BASE (*(volatile uint32_t*) 0x20200000)
     
    int main (void) {
        //lecture 
        uint32_t x= GPIO_BASE;
        //écriture 
        GPIO_BASE= x;
    }

  3. #3
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut kaitlyn.

    Je viens de tester et j'obtiens une erreur de segmentation.
    Ta déclarative ne peut pas fonctionner car les accès aux registres sont externe au programme.

    Mon idée est de déclarer une variable dans le type uint32_t (int unsigned).
    Par le pointeur de cette variable, lui attribuer l'adresse.
    Mais cette variable doit être aussi extern et volatile.

    Il me semble qu'il manque une étape, mais je ne sais pas laquelle.

    Merci de ta participation.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  4. #4
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Une segfault? Mais tu disais faire du bare-metal. Sur un OS, il faut faire un driver, pas une application utilisateur. Sans ça, l'OS ne te laissera jamais accéder directement à ces registres.

  5. #5
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut kaitlyn.

    Je me suis certainement mal exprimé.

    Je sais faire du bare metal en 'C' ainsi qu'en assembleur.
    Je veux dire par là, que je sais programmer la raspberry pour gérer les registres des GPIO, du SPI, du PWM et de l'I2C.

    Maintenant, je désire faire un programme en 'C', sans utiliser l'assembleur et sans faire du bare metal.
    Je ne désire pas utiliser les bibliothèques comme bcm2835 ou encore WiringPi.
    Ni d'ailleurs les bibliothèques natives du 'C', sauf si c'est nécessaire.

    Donc, je suis dans Raspberry Pi OS, en 32 bits, et je désire faire un driver pour accéder à ces registres.
    Qu'est-ce que je dois utiliser comme compilateur 'C' ?
    Et comment dois-je déclarer ma variable _gpio pour lui attribuer l'adresse physique 0x20200000 ?
    Et bien sûr, faire une écriture ?

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  6. #6
    Membre éprouvé
    Femme Profil pro
    ..
    Inscrit en
    Décembre 2019
    Messages
    562
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 94
    Localisation : Autre

    Informations professionnelles :
    Activité : ..

    Informations forums :
    Inscription : Décembre 2019
    Messages : 562
    Points : 1 253
    Points
    1 253
    Par défaut
    Le code est bon, mais pas le contexte d'exécution. Cherche "Linux kernel module", c'est un autre genre de programme, sans main() dedans, et là les registres te seront accessibles.

  7. #7
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Mais dans ce cas là, c'est du bare metal.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  8. #8
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    Salut kaitlyn.

    Je viens de tester et j'obtiens une erreur de segmentation.
    Ta déclarative ne peut pas fonctionner car les accès aux registres sont externe au programme.

    Mon idée est de déclarer une variable dans le type uint32_t (int unsigned).
    Par le pointeur de cette variable, lui attribuer l'adresse.
    Mais cette variable doit être aussi extern et volatile.

    Il me semble qu'il manque une étape, mais je ne sais pas laquelle.

    Merci de ta participation.
    @+
    Quand une application s'exécute sur un OS, elle est en mode logique. cela signifie qu'elle n'a accès qu'à des zones qui lui sont réservées. Une pointeur dans cette application ne peut pas, quelle que soit sa valeur, accéder où il veut. Et heureusement sinon ça serait un beau merdier si les applications pouvaient accéder à l'espace mémoire des autres!

    En effet, il te manque une étape. Elle consiste à demander poliment au système d'accéder à une zone particulière, le système de donnera cet accès et te fournira une adresse logique correspondant à l'adresse physique voulue. Cette adresse logique peut être utilisée dans un pointeur par ton application. Cette fonction s'appelle mmap().

    Je ne connais le raspberry ni Linux mais je tente un exemple à partir d'une lecture rapide du net.
    Code : 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
    #define piPeriphBase  0x20000000
    #define GPIO_BASE  (piPeriphBase + 0x00200000)
    #define GPIO_LEN  0xF4
    static volatile uint32_t*  gpioReg;  // le voilà ton pointeur volatile!
     
    void gpioInitialise(void) {
       int  fd = open( "/dev/mem", O_RDWR | O_SYNC );
       if ( fd < 0 ) {
          fprintf( stderr, "Ce programme doit avoir le privilège root. Essaie avec sudo\n" );
          exit( -1 );
       }
       // et on obtient un pointeur logique dans la zone GPIO physique
       gpioReg  = mmap( 0, GPIO_LEN, PROT_READ|PROT_WRITE|PROT_EXEC,
           MAP_SHARED|MAP_LOCKED, fd, GPIO_BASE );
       close( fd );
    }
     
    int  main(void) {
       gpioInitialise();
     
       // tu peux maintenant utiliser ton pointeur gpioReg pour accéder à ses 61 registres
       gpioReg[0x0] = .....
       gpioReg[0x3c] = ....
    }

  9. #9
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut dalfab.

    Merci pour ta participation.

    Je connais cette technique, qui s'appelle devmem, qui est très sensible aux bugs.
    A le mérite de faire planter facilement le système !
    L'exemple que tu donnes n'est pas du tout recommandé car tu passes par le gestionnaire de fichiers.

    Il y a aussi SysFS qui passe aussi par le système de fichier, mais a surtout l'inconvénient d'être lente.

    Ce sont des anciennes méthodes qui sont devenues obsolètes !

    Il y a la nouvelle bibliothèque "libgpiod" qui est disponible depuis 2018.
    Mais elle ne sait pas gérer le pull-up / pull-down interne à la raspberry.

    --> Christophe Blaess Partie 1
    --> Christophe Blaess Partie 2

    Mais ma question ne se limite pas aux GPIO mais aussi aux autres registres : SPI, I2C, PWD, UART ...

    Ma question est d'ordre général, en ce qui concerne les accès aux registres de la raspberry, et non en particulier aux GPIO.
    Il se peut que je n'utilise pas le bon compilateur 'C' pour avoir les autorisations de le faire.
    Je ne crois pas, non plus, qu'il s'agisse de créer un module dans le noyau de la raspberry.
    J'ai jeté un coup d'œil rapide, mais cela ne correspond pas à ce que je veux faire.

    Mon but est de créer une bibliothèque de fonctions en 'C'.
    Les fonctions ne sont pas compliqués à faire, puisqu'il s'agit juste de mettre du paramétrage dans des registres.
    Je le fais déjà en "bare metal", pour des programmes embarqués sur la raspberry pi zero.

    J'ai jeté un coup d'œil sur la fameuse bibliothèque BCM2835 de Mike McCauley, que l'on utilise en remplacement de la WiringPi de Gordon.
    --> https://www.airspayce.com/mikem/bcm2835/
    Sauf que je n'ai pas compris la technique utilisé pour accéder aux registres.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  10. #10
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    1) la déclarer "extern" car la variable n'est pas propre au programme 'C'.

    (...)

    A la compilation, cela me retourne l'erreur suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    /usr/bin/ld: main.o: in function `main':
    main.c:(.text+0x18): undefined reference to `bcm2835_gpio'
    collect2: error: ld returned 1 exit status
    make: *** [makefile:54: lancer] Error 1
    Tu n'as pas compris la signification de extern.

    https://c.developpez.com/faq/?page=L...fichier-source
    https://c.developpez.com/faq/?page=G...mbol-not-found

    Accessoirement, je n'ai pas l'impression que l'erreur corresponde à ce code.

    La technique donnée par kaitlyn est correcte : tu connais l'adresse du registre, tu castes cette adresse en pointeur, tu peux modifier le registre en déréférençant le pointeur.

    Citation Envoyé par Artemus24 Voir le message
    Je sais faire du bare metal en 'C' ainsi qu'en assembleur.
    Je veux dire par là, que je sais programmer la raspberry pour gérer les registres des GPIO, du SPI, du PWM et de l'I2C.
    Qu'entends-tu exactement par "bare metal" ? Ici, tu parles de faire du code "bas niveau" éventuellement. "Bare metal" veut dire sans OS, mais je ne suis pas certain que ce soit le sens que tu donnes à ce mot.

    Citation Envoyé par Artemus24 Voir le message
    Donc, je suis dans Raspberry Pi OS, en 32 bits, et je désire faire un driver pour accéder à ces registres.
    Je rejoins à nouveau kaitlyn et donc dalfab pour la suite : si tu as un OS, il est probable qu'il t'empêche d'accéder à certaines adresses mémoires. En particulier celles de registres hardwares. Je te conseille de lire la réponse à cette question : https://raspberrypi.stackexchange.co...ddressing-work Si la technique avec mmap() ne te plait pas, libre à toi d'en trouver une autre. Mais il faudra en trouver une.

  11. #11
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut à tous.

    Citation Envoyé par Bktero
    Tu n'as pas compris la signification de extern.
    Si, si, je connais la signification de "extern".

    Citation Envoyé par Bktero
    La technique donnée par kaitlyn est correcte : tu connais l'adresse du registre, tu castes cette adresse en pointeur, tu peux modifier le registre en déréférençant le pointeur.
    J'ai testé la technique de Kaitlyn, mais elle ne fonctionne pas.

    Citation Envoyé par Bktero
    Qu'entends-tu exactement par "bare metal" ?
    A savoir installer un programme que j'ai assemblé dans un environnement où j'ai un OS (buster), dans une carte genre microcontroleur (RPi Pico), où dans mon cas un ordinateur (raspberry pi zero) où il n'y a pas d'OS.
    J'ai la même définition que toi.

    Bare metal signifie "métal nu", c'est-à-dire sans passer par un os comme dans le cas des cartes embarquées.

    Citation Envoyé par Bktero
    Ici, tu parles de faire du code "bas niveau" éventuellement.
    C'est ça, au plus près de la machine, et sans contrainte.
    Pour l'instant, quand je fais du bare metal, je le fais en assembleur ARM Cortex-a7.
    J'ai aussi la possibilité de faire du bare metal par un mélange assembleur (déclaration des fonctions PUT32() et GET32)) et du 'C'.

    Coté bare metal, mon but de ma question est de faire que du 'C' pur, sans passer par l'assembleur.
    Mais ce n'est pas coté bare metal que j'ai ce problème.

    Coté OS, il s'agit bien d'accéder à des registres, qui en temps normal, je n'ai pas accès, puisque j'obtiens une erreur de segmentation.

    Peut-être que je m'exprime mal, peut-être que je n'utilise pas la bonne technique, peut-être que je n'utilise pas le bon compilateur (gcc) pour avoir les autorisations d'accès.
    Je recherche comment accéder à des registres qui ne font pas partis de mon espace de travail et c'est bien ça le problème que je rencontre.

    Si je passe par les bibliothèques que j'ai à ma disposition, je n'ai pas accès à tous les registres, voire même dans le cas des GPÏO, je n'ai pas accès au paramétrage du pull-up / pull-down interne à la raspberry.
    Pour pousser le vice encore plus loin, il existe des registres qui ne sont pas référencés dans la documentation officielle.
    C'est une technique que je ne connais pas car il ne s'agit pas, comme dans ton exemple, de faire la liaison entre deux programmes où la variable global n'a pas été déclaré dans le fichier ".h".
    Le blocage est au niveau du compilateur, ce qui me fait dire que je n'utilise pas le bon compilateur (gcc).

    Je tiens à préciser que je fais mon développement dans la raspberry pi 4B / 8GB sous buster.
    Et j'aimerai savoir comment développer en 'C' pour accéder aux registres spéciaux de la raspberry.

    Merci.
    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  12. #12
    Modérateur

    Avatar de Bktero
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Juin 2009
    Messages
    4 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués

    Informations forums :
    Inscription : Juin 2009
    Messages : 4 481
    Points : 13 679
    Points
    13 679
    Billets dans le blog
    1
    Par défaut
    Si, si, je connais la signification de "extern".
    J'insiste : tu n'as pas compris la signification de extern. Il sert pour utiliser une variable définie dans une autre unité de compilation. Autre unité de compilation qui sert à la création de ton programme. En aucun cas tu ne peux récupérer une variable d'un autre programme. C'est clairement expliqué dans les liens que j'ai donné. D'ailleurs, dans ce cas précis, de quelle variable s'agirait-il ?


    Le blocage est au niveau du compilateur, ce qui me fait dire que je n'utilise pas le bon compilateur (gcc).
    Je vais même aller jusqu'à dire que tu ne comprends pas tout à fait ce qu'est un compilateur, et la différence entre les droits d'un programme et la création de ce programme. Quelles raisons ou éléments te font penser que GCC n'est pas le bon compilateur ?

  13. #13
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut Bktero.

    Es tu là pour me critiquer ou pour m'aider ?

    Citation Envoyé par Bktero
    Il sert pour utiliser une variable définie dans une autre unité de compilation.
    Je ne dis pas le contraire. Ce que je nomme programme, c'est un source.

    Un source se compile, non ? Je ne parle pas ici d'un exécutable.
    Le résultat est un relogeable, non ?
    Quand tu regroupes tes relogeable en un exécutable, tu le fais par l'intermédiaire de l'éditeur de lien, non ?

    L'extern permet d'accéder à une variable qui se trouve dans un autre espace de compilation.
    Mais cet espace de compilation se trouve dans le même exécutable, donc dans le même espace d'adressage.
    Le lien se fait par l'intermédiaire de l'édition des liens car c'est au moment de la création de l'exécutable qu'il connait l'emplacement et le nom de cette variable.
    Je ne peux pas, en principe, accéder à autre chose que dans mon espace d'adressage qui est celui de l'exécutable.

    Je le répète, je sais utiliser l'extern. Ce n'est pas la première fois que je le fais, même si c'est assez rare que je l'utilise.

    Citation Envoyé par Bktero
    D'ailleurs, dans ce cas précis, de quelle variable s'agirait-il ?
    Une variable que je crée dans mon programme, en lui précisant son adresse et son type.
    C'est-à-dire un accès que se trouve en dehors de mon espace d'adressage.
    D'où mon interrogation sur la possibilité de le faire avec gcc.

    Je prends comme exemple quand je fais du bare metal où je suis obligé de passer par un autre compilateur qui est : arm-none-eabi-gcc.

    Citation Envoyé par Bktero
    Quelles raisons ou éléments te font penser que GCC n'est pas le bon compilateur ?
    L'erreur de segmentation !

    La solution de Kaitlyn ne fonctionne pas.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  14. #14
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 431
    Points : 43 057
    Points
    43 057
    Par défaut
    Le segfault vient du fait que ton code, en userland, essayes d'accéder à une adresse mémoire uniquement accessible en kernelland. Tu n'utilises pas une adresse physique mais une adresse virtuelle.

    Heureusement qu’avec un OS moderne tu ne puisses pas modifier directement des valeurs en mémoire ou un registre IO comme ça.

    Soit tu programmes un pilote (un module sous Linux) qui fera l'accès et le lien entre le userland et le kernelland, la procédure à faire normalement, soit tu n'utilises pas d'OS et là tu fais ce que tu veux car tu n'as aucune protection, mise à part celle que tu mets toi-même éventuellement.

    Et ne pas oublier que quand tu utilises une adresse, celle-ci est virtuelle (pagination). Une adresse physique directe doit être projetée dans l'espace d'adressage du processus, et tu ne fais pas ce que tu veux.
    Exemple avec un fichier ELF x86 sous Linux, ton point d'entrée sera toujours quelque chose comme 0x08048xxxx.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  15. #15
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut chrtophe.

    Citation Envoyé par chrtophe
    Tu n'utilises pas une adresse physique mais une adresse virtuelle.
    Qu'est-ce que tu entends par une adresse virtuelle ?

    L'adresses pour accéder aux registres des GPIO commence en 0x20200000 pour la raspberry pi zero.
    Pour moi, cette adresse est physique et je n'en connais pas d'autre.

    Tu peux consulter dans la "BCM2835 datasheet", au chapitre 6 General Purpose I/O (GPIO), à la page 89 si tu désires connaitre le détail.

    Citation Envoyé par chrtophe
    Soit tu programmes un pilote (un module sous Linux) qui fera l'accès et le lien entre le userland et le kernelland, la procédure à faire normalement,
    C'est le module sous linux que je ne comprends pas.
    Je désire créer une bibliothèque de fonctions et non modifier le noyau linux.
    En quoi cela va répondre à mon attente ?

    Jette un œil dans le Github de la BCM2835 qui est la bibliothèque dont on se sert pour accéder aux registres de la raspberry.
    Dit moi si c'est un module linux ou tout simplement une bibliothèque ?

    Tu remarqueras qu'il est fait usage d'extern et de volatile pour des déclaratives comme BCM2835_GPIO qui est la variable pour accéder au registre qui se trouve à l'adresse 0x20200000.

    Citation Envoyé par chrtophe
    soit tu n'utilises pas d'OS et là tu fais ce que tu veux car tu n'as aucune protection, mise à part celle que tu mets toi-même éventuellement.
    Tu veux dire dans le cas de la programmation en bare metal. Si c'est cela, je sais déjà faire.

    Il y a un point qui n'est pas clair.
    Kaitlyn m'a donné une solution qui ne fonctionne pas dans Raspbian. Elle prétend que oui quand elle dit :
    Citation Envoyé par Kaitlyn
    Si ton programme a accès à cette zone mémoire, ...
    Qu'est-ce qu'elle sous-entend par "zone mémoire" ?

    Pour reprendre les propos de Bktero, par "zone mémoire", je comprends qu'il s'agit de l'espace d'adressage de compilation (ou du processus).
    Comme cette zone mémoire dont je désire accéder est en dehors de cet espace d'adressage, j'aurai un "segment fault".

    Comment écrire un module linux ?

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  16. #16
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 642
    Points
    7 642
    Par défaut
    Citation Envoyé par Artemus24 Voir le message
    Qu'est-ce que tu entends par une adresse virtuelle ?
    L'adresse pour accéder aux registres des GPIO commence en 0x20200000 pour la raspberry pi zero.
    Pour moi, cette adresse est physique et je n'en connais pas d'autre.
    Une adresse virtuelle - que l'on appelle aussi adresse logique - c'est une adresse que le processeur peut utiliser quand ton application s'exécute.
    Citation Envoyé par Artemus24 Voir le message
    Tu peux consulter dans la "BCM2835 datasheet", au chapitre 6 General Purpose I/O (GPIO), à la page 89 si tu désires connaitre le détail.

    C'est le module sous linux que je ne comprends pas.
    Je désire créer une bibliothèque de fonctions et non modifier le noyau linux.
    En quoi cela va répondre à mon attente ?
    Quand ton application s'exécute, d'autres sont aussi là en train de tourner. Supposons qu'avec une simple définition de pointeur on puisse pointer n'importe où dans la mémoire physique (comme en bare metal) on pourrait écrire dans la mémoire des autres applications et ça serait un beau merdier!
    Tu ne veux pas modifier le noyau, tu dois donc l'utiliser tel qu'il est. Et le noyau t'interdit d'écrire n'importe où. Ton application ne peut qu'utiliser les adresses virtuelles associées à ton processus. C'est pourquoi je t'ai donné la fonction mmap() qui consiste à demander au noyau d'accéder à une zone physique, en échange le noyau te fabrique une adresse accessible dans l'espace de ton application correspondant à ce que tu veux, par exemple pour l'adresse physique 20020000 il donnera un pointeur qui vaut 0x13000, la liaison entre ces deux valeurs est faite dans un composant du processeur appelé MMU.
    Citation Envoyé par Artemus24 Voir le message
    Jette un œil dans le Github de la BCM2835 qui est la bibliothèque dont on se sert pour accéder aux registres de la raspberry.
    Dit moi si c'est un module linux ou tout simplement une bibliothèque ?

    Tu remarqueras qu'il est fait usage d'extern et de volatile pour des déclaratives comme BCM2835_GPIO qui est la variable pour accéder au registre qui se trouve à l'adresse 0x20200000.
    Que ça soit un module ou une bibliothèque, c'est du code dans ton application et il n'y a pas de miracle, ce code doit demander un accès virtuel à la zone physique à un moment.
    Citation Envoyé par Artemus24 Voir le message
    Tu veux dire dans le cas de la programmation en bare metal. Si c'est cela, je sais déjà faire.
    Ça on l'a compris.
    Citation Envoyé par Artemus24 Voir le message
    Il y a un point qui n'est pas clair.
    Kaitlyn m'a donné une solution qui ne fonctionne pas dans Raspbian. Elle prétend que oui quand elle dit :

    Qu'est-ce qu'elle sous-entend par "zone mémoire" ?
    Une zone virtuelle dans ton application qui "mappe" une zone physique.
    Citation Envoyé par Artemus24 Voir le message
    Pour reprendre les propos de Bktero, par "zone mémoire", je comprends qu'il s'agit de l'espace d'adressage de compilation (ou du processus).
    C'est l'espace du processus qui s'exécute. Ce que l'on obtient à la compilation, c'est un fichier: dans ce fichier il y a du code, des données et des demandes de réservation de mémoire. Essaie d'écrire un programme qui définit un tableau statique de 50GO, il compilera, mais à aucun moment il ne deviendra un processus, au moment du lancement le module d'attribution de la mémoire virtuelle refusera de fabriquer le processus.
    Citation Envoyé par Artemus24 Voir le message
    Comme cette zone mémoire dont je désire accéder est en dehors de cet espace d'adressage, j'aurai un "segment fault".

    Comment écrire un module linux ?
    Un segmentation fault, c'est accéder à une adresse qui n'existe pas dans l'espace virtuel de ton application.

  17. #17
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 431
    Points : 43 057
    Points
    43 057
    Par défaut
    Un segmentation fault, c'est accéder à une adresse qui n'existe pas dans l'espace virtuel de ton application.
    Je dirais plutôt un accès à une adresse interdite, une adresse inexistante étant bien entendu une adresse interdite. Ca peut être aussi une tentative d'écriture dans une zone une lecture seule. Une adresse physique non présente dans son espace d'adressage sera inexistante pour ton processus, exemple les adresses physiques du processus B sont inexistante pour le processus A.

    mmap attend un descripteur de fichiers, tu peux mapper un fichier ou un device.

    ci-joint un exemple :
    https://elinux.org/RPi_GPIO_Code_Sam...egister_access

    Le processus utilise mmap, il va donc mapper l'adresse du GPIO à l'adresse virtuelle contenue dans gpio_map.
    Peut-être nécessaire d'être en root.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

  18. #18
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut Dalfab.

    J'ai du mal à comprendre la notion d'adresse virtuelle.

    Je comprends mieux la notion d'adresse relative.
    C'est un adresse qui est relative au début du programme, quand celui-ci est encore un relogeable, c'est-à-dire à la compilation.
    Le début du programme est l'adresse relative 0x00000000. On parle plutôt de "offset", je crois.
    C'est l'édition des liens qui va lui attribuer une adresse définitive lorsque l'exécutable sera implanté à l'adresse 0x08048xxxx de l'exemple de Chrtophe.
    Cette adresse définitive s'appelle "base" ou adresse d'implantation, ou encore adresse physique.

    Citation Envoyé par Dalfab
    Supposons qu'avec une simple définition de pointeur on puisse pointer n'importe où dans la mémoire physique (comme en bare metal) on pourrait écrire dans la mémoire des autres applications et ça serait un beau merdier!
    Je comprends, mais cela ne me pose pas trop de problèmes car je suis tout seul à travailler dans ma raspberry.

    Citation Envoyé par Dalfab
    Tu ne veux pas modifier le noyau, tu dois donc l'utiliser tel qu'il est. Et le noyau t'interdit d'écrire n'importe où.
    Oui, ça, je le sais.

    Je viens de jeter un coup d'oeil à ce lien.
    Ca ne correspond pas du tout à ce que je veux faire.

    J'avais commencé mon étude avec SysFS qui comme je l'ai dit précédemment est devenu obsolète.
    J'ai étudié la libgpio qui est "linux/gpio.h".
    Sauf qu'elle ne sait pas gérer activer ou désactiver les pull-up . pull-down interne à la raspberry.

    Je pensais que je pouvais facilement accéder aux registres de la raspberry.
    Mais voilà, cela me semble bien trop compliqué à faire.
    Encore que, je n'ai pas tout étudié dans le cas des GPIO.

    Et je ne parle même pas quand je vais devoir gérer PWM.

    Pour I2c et SPI, je suis passé par la fonction "ioctl()" qui correspond bien à mon besoin.

    A bien vous comprendre, ce que je désire faire vous semble très compliquer à entreprendre.
    Est-ce qu'en passant par le compilateur arm-none-eabi-gcc, je peux créer ma bibliothèque sous Raspbian ?
    Oui, faire du bare metal pour outrepasser les interdits du compilateur gcc et le tout dans l'OS raspbian.

    Est-ce que vous avez jeté un coup d'œil à ce lien ?
    Comment cette bibliothèque a été créé ?

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  19. #19
    Expert éminent sénior Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    6 378
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 6 378
    Points : 19 054
    Points
    19 054
    Par défaut
    Salut Chrtophe.

    Merci de ton aide, mais tu ne m'as pas bien compris.

    La méthode que tu me donnes, se nomme devmem, et elle est devenue obsolète.
    Il y a un autre méthode, qui se nomme SysFS qui est aussi devenue obsolète.
    Ces méthodes ne m'intéressent pas.

    Dernièrement, en 2018, une nouvelle bibliothèque "/linux/gpio.h" vient remplacer ces deux méthodes obsolètes.
    Comme je l'ai dit, cette bibliothèque ne sait pas gérer le pull-up / pull-down interne à la raspberry.
    Ou bien, je n'ai pas compris comment faire.

    Du coup, comme je fais du bare metal, je me demandais comment accéder, sous l'OS Raspbian, aux registres de la raspberry pi.
    La réponse qui m'a été communiqué ici, est soit on ne peut pas faire, soit il faut passer par les modules linux.
    Je ne veux pas passer par un module linux car cela ne correspond pas à mon besoin.

    J'aimerai savoir comment Mr. Mike McCauley a fait pour créer sa bibliothèque BCM2835.h ?
    Je redonne le lien vers son site qui détail toutes les fonctions utilisées.
    Je donne aussi le lien vers le GitHub qui contient ls utilitaire pour créer la bibliothèque BCM2835.
    En particulier, le lien vers ce qui m'intéresse, à savoir la section "src".

    Même en mettant mon nez dans ce GitHub, je n'ai toujours pas compris comment il a fait pour créer cette bibliothèque que j'ai installé depuis fort longtemps dans ma raspberry pi.

    En tout cas, Mr. Mike Mc Cauley a fait un magnifique travail !!! Bravo.

    @+
    Si vous êtes de mon aide, vous pouvez cliquer sur .
    Mon site : http://www.jcz.fr

  20. #20
    Responsable Systèmes


    Homme Profil pro
    Gestion de parcs informatique
    Inscrit en
    Août 2011
    Messages
    17 431
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Gestion de parcs informatique
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 17 431
    Points : 43 057
    Points
    43 057
    Par défaut
    Merci de ton aide, mais tu ne m'as pas bien compris.
    Peut-être pas, mais tu as dis dans ton premier post :
    Mon problème est que j'aimerai accéder aux registres des GPIO afin de créer un programme en 'C' sans passer par des bibliothèques.
    Et là maintenant tu parles d'utiliser une bibliothèque.

    Et qu'appeles-tu programmation bare metal ? parce que pour moi, le bare metal c'est lié à la virtualisation.

    La méthode que tu me donnes, se nomme devmem, et elle est devenue obsolète
    Ah bon, et pourquoi ? plus exploitable sur les derniers RaspBerry ?
    En regardant vite fait sur le net, j'ai vu qu'il existait /dev/gpiomem, le principe semblant le même, peut-être pour un accès userland (à vérifier)

    Il y a un autre méthode, qui se nomme SysFS qui est aussi devenue obsolète.
    En regardant la doc officielle, ils recommandent l'utilisation de libgpiod, et en regardant le code source de celle-ci, on peut voir que sysFS est pas mal utilisé, donc pas si obsolète que ça. De ce que j'ai compris, c'est qu’auparavant ce sont des drivers de blocs qui étaient utilisés via sysFS et que maintenant c'est des drivers de caractères. Ce n'est pas l'usage de sysFS qui est obsolète, c'est l'usage d'anciens appels via sysFS.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur le P2V, mon article sur le cloud
    Consultez nos FAQ : Windows, Linux, Virtualisation

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 2
    Dernier message: 07/08/2017, 21h46
  2. Variable pointant sur une partie du tableau
    Par huître dans le forum C
    Réponses: 6
    Dernier message: 17/04/2015, 16h48
  3. [Free Pascal] [Débutant] Variable pointant sur partie variable d'enregistrement
    Par thierrybo dans le forum Free Pascal
    Réponses: 4
    Dernier message: 02/10/2009, 22h08
  4. Variable pointant sur un objet fermé
    Par azur668 dans le forum VBA Access
    Réponses: 2
    Dernier message: 03/08/2009, 12h27
  5. Transtyper element d'1 variable pointant sur TList?
    Par Cornell dans le forum Langage
    Réponses: 2
    Dernier message: 25/02/2003, 22h53

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