Les GPIO du Raspberry Pi

Publié par cpb
Nov 26 2012

GPIO & Raspberry PiLe Raspberry Pi offre quelques possibilités d’entrées-sorties directes en utilisant les broches GPIO présentes sur son connecteur P1. Elles ne sont pas très nombreuses (une dizaine) mais cela peut suffire pour des petits projets interactifs nécessitant d’interroger des capteurs tout-ou-rien ou de valider des actionneurs.

Nous pouvons utiliser ces GPIO de différentes façons, depuis l’espace utilisateur ou depuis le noyau. Voyons-en rapidement les principaux aspects…

Les broches GPIO

Sur le connecteur P1 du Raspberry Pi, nous pouvons trouver plusieurs broches consacrées aux entrées-sorties GPIO. Celles-ci peuvent être configurées individuellement en entrées ou en sorties numériques. Attention, la tension appliquée sur une borne d’entrée doit rester inférieure à 3.3 V.

Les GPIO directement accessibles sont les suivantes.

Broche GPIO
3 0 (rev.1) ou 2 (rev.2)
5 1 (rev.1) ou 3 (rev.2)
7 4
11 17
12 18
13 21 (rev.1) ou 27 (rev.2)
15 22
16 23
18 24
22 25

 

On peut remarquer que certaines broches (3, 5 et 13) ont changé d’affectations au gré des versions du Raspberry Pi, aussi évitera-t-on de les employer pour garder un maximum de portabilité aux applications.

Accès depuis l’espace utilisateur

L’accès simple, depuis le shell – ou tout autre programme de l’espace utilisateur – peut se faire très aisément grâce au système de fichiers /sys.

/ # cd /sys/class/gpio/
/sys/class/gpio # ls
export     gpiochip0  unexport

Demandons l’accès au GPIO 24 (broche 18).

/sys/class/gpio # echo 24 > export 
/sys/class/gpio # ls
export     gpio24     gpiochip0  unexport
/sys/class/gpio # cd gpio24/
/sys/devices/virtual/gpio/gpio24 # ls
active_low  direction   edge        subsystem   uevent      value
/sys/devices/virtual/gpio/gpio24 # cat direction
in

Sortie de signal

Par défaut, les broches GPIO sont dirigées en entrée. Inversons le sens du 24, puis regardons sa valeur.

/sys/devices/virtual/gpio/gpio24 # echo out > direction 
/sys/devices/virtual/gpio/gpio24 # cat value
0

Effectivement, le voltmètre confirme qu’il n’y a pas de tension sur la broche.

GPIO Raspberry Pi - 1

Modifions l’état de la sortie

/sys/devices/virtual/gpio/gpio24 # echo 1 > value

Vérifions la tension.

GPIO Raspberry Pi - 2

Re-basculons la sortie à zéro.

/sys/devices/virtual/gpio/gpio24 # echo 0 > value
/sys/devices/virtual/gpio/gpio24 #

GPIO Raspberry Pi - 3

 

Lecture d’état

Demandons à présent l’accès à la broche 16 (Gpio 23)

# cd /sys/class/gpio/
/sys/class/gpio # echo 23 > export 
/sys/class/gpio # ls
export     gpio23     gpio24     gpiochip0  unexport
/sys/class/gpio # cd gpio23/
/sys/devices/virtual/gpio/gpio23 # cat direction
in

Je relie la broche 16 à la broche 20 (GND), puis je lis la valeur d’entrée.

/sys/devices/virtual/gpio/gpio23 # cat value
0

Je relie à présent la broche 16 à la broche 17 (+3.3V)

/sys/devices/virtual/gpio/gpio23 # cat value 
1

Retour à nouveau sur la broche 20 (GND).

/sys/devices/virtual/gpio/gpio23 # cat value 
0
/sys/devices/virtual/gpio/gpio23 #

Accès depuis le kernel

Lectures et écritures

Nous pouvons écrire un petit module pour accéder en lecture et écriture aux mêmes broches. Dans le module ci-dessous un timer à 8Hz fait clignoter la sortie sur la broche 18 seulement si la broche 16 est mise à 1 (+3.3V).

rpi-gpio-1.c
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/gpio.h>
#include <linux/fs.h>

// Sortie sur broche 18 (GPIO 24)
#define RPI_GPIO_OUT 24

// Entree sur broche 16 (GPIO 23)
#define RPI_GPIO_IN  23

static struct timer_list rpi_gpio_1_timer;

static void rpi_gpio_1_function (unsigned long unused)
{
  static int value = 1;
  value = 1 - value;
  if (gpio_get_value(RPI_GPIO_IN) == 0)
    value = 0;
  gpio_set_value(RPI_GPIO_OUT, value);
  mod_timer(& rpi_gpio_1_timer, jiffies+ (HZ >> 3));
}

static int __init rpi_gpio_1_init (void)
{
  int err;

  if ((err = gpio_request(RPI_GPIO_IN,THIS_MODULE->name)) != 0)
    return err;
  if ((err = gpio_request(RPI_GPIO_OUT,THIS_MODULE->name)) != 0) {
    gpio_free(RPI_GPIO_IN);
    return err;
  }
  if ((err = gpio_direction_input(RPI_GPIO_IN)) != 0) {
    gpio_free(RPI_GPIO_OUT);
    gpio_free(RPI_GPIO_IN);
    return err;
  }
  if ((err = gpio_direction_output(RPI_GPIO_OUT,1)) != 0) {
    gpio_free(RPI_GPIO_OUT);
    gpio_free(RPI_GPIO_IN);
    return err;
  }

  init_timer(& rpi_gpio_1_timer);
  rpi_gpio_1_timer.function = rpi_gpio_1_function;
  rpi_gpio_1_timer.data = 0; // non utilise
  rpi_gpio_1_timer.expires = jiffies + (HZ >> 3);
  add_timer(& rpi_gpio_1_timer);

  return 0; 
}

static void __exit rpi_gpio_1_exit (void)
{
  del_timer(& rpi_gpio_1_timer);
  gpio_free(RPI_GPIO_OUT);
  gpio_free(RPI_GPIO_IN);
}

module_init(rpi_gpio_1_init);
module_exit(rpi_gpio_1_exit);
MODULE_LICENSE("GPL");

La compilation se fait avec le fichier Makefile suivant. Les lignes KERNEL_DIR et CROSS_COMPILE indiquent respectivement l’emplacement du répertoire de compilation du noyau pour le Raspberry Pi et le préfixe pour la toolchain sur mon système. Il faut les adapter à votre environnement.

 

Makefile
ifneq (${KERNELRELEASE},)

  obj-m += rpi-gpio-1.o

else
  ARCH          ?= arm
  KERNEL_DIR ?= ~/linux-3.2.27
  CROSS_COMPILE ?= /usr/local/cross/rpi/bin/arm-linux-
  MODULE_DIR    := $(shell pwd)
  CFLAGS        := -Wall

all: modules

modules:
  ${MAKE} -C ${KERNEL_DIR} ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} SUBDIRS=${MODULE_DIR} modules

clean:
  rm -f  *.o  .*.o  .*.o.* *.ko  .*.ko  *.mod.* .*.mod.* .*.cmd
  rm -f Module.symvers Module.markers modules.order
  rm -rf .tmp_versions
endif

Après compilation et transfert sur le Raspberry Pi, nous chargeons le module et observons à l’aide d’un analyseur logique les deux broches 16 (canal 2) et 18 (canal 1), tandis qu’un signal de +3.3V est envoyé sur la broche 16.

Raspberry Pi & GPIO - 4

Durant la période (mise en évidence par un trait rouge) où la broche 16 se voit appliquer une tension de +3.3V, nous voyons bien une oscillation de la sortie sur la broche 18.

Interruptions

À présent nous allons traiter les interruptions déclenchées par une entrée GPIO. Le module ci-dessous installe un handler d’interruption pour le GPIO 23 (broche 16). À chaque déclenchement de l’interruption, notre handler basculera l’état de la broche de sortie 18 (GPIO 24).

rpi-gpio-2.c
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/gpio.h>

// Sortie sur broche 18 (GPIO 24)
#define RPI_GPIO_OUT 24

// Entree sur broche 16 (GPIO 23)
#define RPI_GPIO_IN  23

static irqreturn_t rpi_gpio_2_handler(int irq, void * ident)
{
  static int value = 1;

  gpio_set_value(RPI_GPIO_OUT, value);
  value = 1 - value;

  return IRQ_HANDLED;
}

static int __init rpi_gpio_2_init (void)
{
  int err;

  if ((err = gpio_request(RPI_GPIO_OUT, THIS_MODULE->name)) != 0)
    return err;

  if ((err = gpio_request(RPI_GPIO_IN, THIS_MODULE->name)) != 0) {
    gpio_free(RPI_GPIO_OUT);
    return err;
  }

  if ((err = gpio_direction_output(RPI_GPIO_OUT,1)) != 0) {
    gpio_free(RPI_GPIO_OUT);
    gpio_free(RPI_GPIO_IN);
    return err;
  }

  if ((err = gpio_direction_input(RPI_GPIO_IN)) != 0) {
    gpio_free(RPI_GPIO_OUT);
    gpio_free(RPI_GPIO_IN);
    return err;
  }

  if ((err = request_irq(gpio_to_irq(RPI_GPIO_IN), rpi_gpio_2_handler, IRQF_SHARED | IRQF_TRIGGER_RISING, THIS_MODULE->name, THIS_MODULE->name)) != 0) {
    gpio_free(RPI_GPIO_OUT);
    gpio_free(RPI_GPIO_IN);
    return err;
  }

  return 0; 
}

static void __exit rpi_gpio_2_exit (void)
{
  free_irq(gpio_to_irq(RPI_GPIO_IN), THIS_MODULE->name);
  gpio_free(RPI_GPIO_OUT);
  gpio_free(RPI_GPIO_IN);
}

module_init(rpi_gpio_2_init);
module_exit(rpi_gpio_2_exit);
MODULE_LICENSE("GPL");

Le second module ayant été ajouté dans le Makefile, nous pouvons le compiler de la même façon que le précédent. Transférons-le sur le Raspberry Pi, puis chargeons-le dans le kernel.

/ # cat /proc/interrupts
           CPU0       
  3:        362   ARMCTRL  BCM2708 Timer Tick
 32:        419   ARMCTRL  dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
 52:          0   ARMCTRL  BCM2708 GPIO catchall handler
 65:         20   ARMCTRL  ARM Mailbox IRQ
 66:          1   ARMCTRL  VCHIQ doorbell
 77:        123   ARMCTRL  bcm2708_sdhci (dma)
 83:         18   ARMCTRL  uart-pl011
 84:        317   ARMCTRL  mmc0
FIQ:              usb_fiq
Err:          0
/ # insmod rpi-gpio-2.ko
/ # cat /proc/interrupts
           CPU0       
  3:        434   ARMCTRL  BCM2708 Timer Tick
 32:        463   ARMCTRL  dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
 52:          0   ARMCTRL  BCM2708 GPIO catchall handler
 65:         28   ARMCTRL  ARM Mailbox IRQ
 66:          1   ARMCTRL  VCHIQ doorbell
 77:        124   ARMCTRL  bcm2708_sdhci (dma)
 83:        119   ARMCTRL  uart-pl011
 84:        326   ARMCTRL  mmc0
193:          0      GPIO  rpi_gpio_2
FIQ:              usb_fiq
Err:          0
/ #

Nous voyons que la ligne d’interruption (numéro 193) est apparue dans /proc/interrupts. Pour l’instant aucune interruption ne s’est déclenchée. Connectons sur cette entrée un Générateur-Basse-Fréquence, qui lui envoie un signal carré [0, +3.3V] de 2.5kHz environ.

Aussitôt un signal carré apparaît sur la broche de sortie, avec une fréquence moitié du précédent. Nous pouvons le vérifier avec un oscilloscope.
Raspberry Pi & GPIO 5

Nous pouvons également vérifier dans /proc/interrupts que le nombre d’interruptions 193 traitées progresse régulièrement.

/ # cat /proc/interrupts 
           CPU0       
  3:        646   ARMCTRL  BCM2708 Timer Tick
 32:        617   ARMCTRL  dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
 52:      29791   ARMCTRL  BCM2708 GPIO catchall handler
 65:         60   ARMCTRL  ARM Mailbox IRQ
 66:          1   ARMCTRL  VCHIQ doorbell
 75:          1   ARMCTRL
 77:        124   ARMCTRL  bcm2708_sdhci (dma)
 83:        187   ARMCTRL  uart-pl011
 84:        342   ARMCTRL  mmc0
193:      29792      GPIO  rpi_gpio_2
FIQ:              usb_fiq
Err:          0
/ #

En zoomant sur le point de déclenchement, nous mesurons la durée de prise en compte de l’interruption.

Raspberry Pi & GPIO 6

 

La durée entre la montée du signal d’entrée et la réponse du handler est d’environ 7 micro-secondes, ce qui est tout à fait correct pour cette gamme de microprocesseur.

Conclusion

L’accès aux GPIO du port d’extension du Raspberry Pi est très simple, tant depuis l’espace utilisateur que depuis le noyau. Il existe d’autres broches permettant des entrées-sorties GPIO, mais elles ont une autre fonctionnalité par défaut (RS-232, SPI, etc.).

Il serait également intéressant d’accéder aux GPIO depuis un driver RTDM pour Xenomai. Ceci fera l’objet d’un prochain article.

Pour en savoir plus

Si vous souhaitez approfondir l’écriture de drivers pour Linux – notamment pour les GPIO du Raspberry Pi -, je vous propose de vous retrouver en session de formation « Écriture de drivers et programmation noyau Linux » chez Logilin.

 

 

56 Réponses

  1. Sébastien dit :

    Article fort intéressant, merci beaucoup.
    je suis en train de tester un RPI et maintenant j’aimerais bien implémenter la connexion RS232 du RPI pour commencer à bien jouer.
    Si vous avez des références sur le sujet, je suis preneur.

  2. Sébastien dit :

    Ben j’ai pas cherché bien loin, je vois que vous avez fait un article dessus, je vais y jeter un œil
    merci

  3. Francky dit :

    Bonjour,

    Est-ce que cet article fait référence à une utilisation de des GPIO de PI avec un noyau temps-réel ou un noyau simple ?

    merci

  4. Guy dit :

    Cet article est très intéressant mais je ne suis pas sûr d’avoir vraiment tout compris au niveau des interruptions. Est ce qu’il existe un lien physique sur le raspberry pi entre le GPIO et le microprocesseur pour déclencher des interruptions? Ou bien la routine écrite en C est elle purement logicielle pour surveiller le changement d’état d’une broche du GPIO.
    En tout cas merci pour les explications, plein de choses a faire avec ce Raspberry…

    Guy

    • cpb dit :

      Bonjour Guy,

      L’interruption est bien déclenchée directement par le changement d’état de la broche du GPIO. C’est l’APIC (Advanced Programmable Interrupt Controller) inclus dans le processeur qui détecte les variations de niveaux sur ces broches et envoie une demande d’interruption. Suivant sa configuration, il peut ainsi notifier le CPU d’un front électrique montant, descendant, d’un niveau haut ou bas. Toutes ces configurations ne sont peut-être pas accessibles sur l’APIC du Raspberry Pi, je n’ai pas encore vérifié.

  5. Geoffrey dit :

    Bonjour,

    Merci pour l’article. J’ai cependant deux questions…

    Quelle est la valeur de la constante HZ ? Et où est définie jiffies ?

    Par ailleurs, si l’on souhaite avoir un timer à 8Hz, ne faut-il pas écrire HZ <> 3 ?

    Peut-être me trompé-je lourdement puisque je n’ai aucune expérience dans l’écriture de pilotes, notamment sous Linux…

    Merci d’avance !

    • Geoffrey dit :

      Mon commentaire a légèrement été formaté…

      Je voulais dire HZ << 8.

      • Geoffrey dit :

        Et encore une erreur…

        Mon dernier mot sera : HZ << 3.

        Toutes mes excuses. 🙂

        • cpb dit :

          Bonjour,

          La constante HZ est définie dans un fichier d’en-tête du kernel (<asm/param.h> si je me souviens bien) et contient le nombre de ticks par secondes (même sur un système tickless).

          La variable jiffies (<linux/jiffies.h>) contient le nombre de ticks écoulés depuis le boot.

          Donc jiffies+HZ signifie « maintenant + une seconde » (ou plutôt en français : « dans une seconde » ) et jiffies+HZ/8 ou jiffies+HZ>>3 signifie « dans un huitième de seconde »

          Le timer se reprogramme ainsi régulièrement en demandant à être à nouveau invoqué dans un huitième de seconde.

  6. ahamedMoussa dit :

    Bonjour
    Je suis en train de réaliser un projet personnel avec ma mini2440 le noyau image que j’ai récupéré ne me permet pas d’accéder au répertoire sys/class/gpio/. J’aimerais connaître la procédure à faire lors de la compilation du noyau afin d’avoir accès au répertoire gpio. Un tutoriel ou un lien internet expliquant la démarche serait la bienvenue.
    Cordialement.

  7. PAIN dit :

    Bonjour

    Pour exploiter les GPIO du Raspberry Pi en domotique j’ai réalisé une carte de protection pour évité tout retour d’alimentation qui nuirai à la santé du Rasp, si cela peut vous interesser http://blueberry4pi.com/2013/02/01/carte-de-protection-pour-les-gpio-du-raspberry/

  8. steph dit :

    Hello Christophe !

    « high » n’est-il pas supposé mettre la broche en pull up et rien d’autre?
    Ca semble passer son etat d’entré en sortie.

    # echo in > direction
    # cat direction
    # in
    # echo high > direction
    # cat directon
    # out

    Normalement apres:

    # echo high > direction

    seule « value » devrait passer a ‘1’ (si broche « en l’air ») mais « direction » devrait rester en « in » ?!

    Help !

    • cpb dit :

      Inscrire « high » dans le fichier direction a pour effet de basculer la broche en sortie (si elle ne l’était pas déjà) et la place à l’état 1 (+3.3V).

      Y écrire « low » ou « out » bascule la broche en sortie et la met à 0.

      Écrire « in » dans direction passe la broche en entrée.

      En fait, il ne faut pas considérer « high » comme « haute impédance », mais comme « sortie au niveau haut ».

      NB: le code correspondant est visible dans les sources du kernel, fichier drivers/gpio/gpiolib.c, fonction gpio_direction_store().

  9. steph dit :

    Ah ok.

    Il n’y a donc aucun moyen de « tirer » la broche a 3.3V ou GND autrement que via une resistance externe ?

    Je bricole juste qq chose pour faire un « shutdown -h » avec un poussoir & Bash.

    • cpb dit :

      Je ne suis pas sûr que cela soit possible avec le Raspberry Pi.
      J’avais réalisé ce genre de chose sur une Pandaboard via le système de fichier debugfs (voir cet article), mais je n’ai pas encore regardé sur le Raspberry et je doute que cela soit possible.

  10. Lapin dit :

    C’est un bon article, mais c’est dommage que tu ne fournisses pas les sources qui t’on permis d’arrive jusque-là.
    Par exemple : on aimerait savoi d’où vient la table des correspondance broches/GPIO en début d’article. Ca permettrait à tes lecteurs d’avoir d’autres pistes à fouiller.

  11. steph dit :

    Hello

    J’ai juste inclus j’ai des erreurs:

    —————-
    gcc -I/usr/include -I/usr/src/linux/include -Wall test.c -o test
    In file included from /usr/src/linux/include/linux/list.h:4:0,
    from /usr/src/linux/include/linux/module.h:9,
    from test.c:8:
    /usr/src/linux/include/linux/types.h:13:2: warning: #warning « Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders » [-Wcpp]

    etc..
    —————-

    J’ai regardé les sources de wiringPi [http://wiringpi.com] vite fait, les fonctions C proposer semblent a premiere vue acceder au E/S par le biais de fichier (/sys/../value, etc..) est ce aussi ce qui ce passe derriere l’exemple que tu proposes?

    Un article, « GPIOs from scratch for newbies », serait bienvenu !

  12. cpb dit :

    Il ne faut pas faire de compilation des modules du noyau depuis la ligne de commande, il vaut mieux utiliser un Makefile qui va chercher les éléments de configuration et les fichiers d’en-tête du kernel.
    Il y en a un présenté dans l’article, il faut juste configurer correctement KERNEL_DIR.

    Les accès depuis l’espace utilisateur en début d’article se font en effet par l’intermédiaire de /sys.

    • steph dit :

      J’ai trouvé mon bonheur en attendant d’etre plus degourdi.

      « C library for Broadcom BCM 2835 as used in Raspberry Pi »
      http://www.airspayce.com/mikem/bcm2835/

      C’est moins « usine à gaz » que WiringPi.

      Les executables doivent evidement se faire en root (acces a /dev/mem ). Pourtant si je fais un chmod +s dessus ca ne change rien; alors qu’avec « avrdude » cette manip me permet de le lancer en simple utilisateur (/dev/bus/usb je crois).

  13. cpb dit :

    Que donne un « ls -l <executable> » (pour voir les droits et le propriétaire) ?

    • steph dit :

      Ok!! merci ! Effectivement le proprietaire etait resté un simple utilisateur ! Pfff… Le pire est que j’ai un « alias ls=’ls -lrt' » mais ca ne m’a pas empeché de ne rien voir.

      Bizarrement quand on change le nom du « group », le flag ‘s’ de l’user disparait. Bah !

  14. Grégory dit :

    Bonjour cpb,

    Je suis actuellement en train de travaillé sur une carte Emtrion Dimm-mx6 (sujet de stage de master) ou je dois piloté une irq via le kernel space.

    Je voulais savoir si ton code (rpi-gpio-2) est général pour tous type de carte ou spécifique au raspberry pi ? (hormis les broches des IO)

    • cpb dit :

      Bonjour,

      Ce code est assez générique et devrait marcher sur toutes les cartes où le support GPIO est présent dans le kernel.

      • Grégory dit :

        Etant débutant en programmation sur le kernel, je voulais savoir a quoi correspondait « THIS_MODULE->name ».

        j’ai pour but avec ma carte de générer une irq toute les 500µs, pouvez vous m’aidez a modifier votre code (signal irq interne et non d’un gbf avec top toute les 500µs ~2KHz)

        • cpb dit :

          THIS_MODULE est une macro qui représente toujours un pointeur vers la struct module du fichier courant. Le champ name contient donc son nom. Ceci permet ici d’identifier le code qui réclame l’accès aux GPIO ou l’inscription d’un handler d’interruption.

          Vous voulez générer une IRQ toutes les 500µs ou déclencher un timer toutes les 500µs ? Dans le premier cas il faut programmer un timer du CPU pour cela (code spécifique qui dépend du matériel).
          Dans le second cas il suffit de programme un HRTimer ainsi :

          #include <linux/hrtimer.h>
          #include <linux/module.h>
          #include <linux/sched.h>
          
          static enum hrtimer_restart fonction_timer(struct hrtimer *);
          static struct hrtimer htimer;
          static ktime_t kt_periode;
          
          static int __init exemple_init (void)
          {
                  kt_periode = ktime_set(0, 500000); // periode en ns.
                  hrtimer_init (& htimer, CLOCK_REALTIME, HRTIMER_MODE_REL);
                  htimer.function = fonction_timer;
                  hrtimer_start(& htimer, kt_periode, HRTIMER_MODE_REL);
                  return 0;
          }
          
          static void __exit exemple_exit (void)
          {
                  hrtimer_cancel(& htimer);
          }
          
          
          static enum hrtimer_restart fonction_timer(struct hrtimer * unused)
          {
                 
                  hrtimer_forward_now(& htimer, kt_periode);
                  // Votre code à exécuter périodiquement
          
                  return HRTIMER_RESTART;
          }
          
          
          module_init(exemple_init);
          module_exit(exemple_exit);
          MODULE_LICENSE("GPL");
          • Grégory dit :

            le but « final » c’est de générer une IRQ. Mais la je peux pour un 1er temps me contenter de générer un timer qui me fait bagoter ma sorti a chacun de ces tops d’horloge.

            Comment incorporer le timer dans le rpi-gpio-2.c ?

            Merci d’avance

  15. cpb dit :

    Pour obtenir un signal périodique précis sur une broche de sortie, il est également possible d’utiliser un PWM. Le GPIO 18 sur la broche 12 permet ce genre d’utilisation. Je ne l’ai pas encore exploré mais ça ne doit pas être très compliqué à configurer.

  16. Grégory dit :

    Bonjour cpb,

    Grace a ton aide j’ai pu avancer sur mes tests.
    J’ai utiliser une pwm comme tu la mentionné dans ton dernier post et j’ai adapté le rpi-gpio-2.c à ma carte pour que ça marche.
    Par contre dans le handler de mon programme je lui demande de faire une factorielle pour calculer sont temps de calcul. J’obtient un signal qui oscille beaucoup (pouvant aller au double du temps de calcul min). on m’a dit que cela pouvait venir de IRQF_SHARED | IRQF_TRIGGER_RISING car les IT shared sont gérées par le noyau sous la forme d’une liste chainée de handler. Le temps de réponse n’est donc pas déterministe d’ou mon oscillation.

    As tu rencontré ce problème

  17. Florian dit :

    Bonjour,

    Merci pour cet article très bien rédigé.
    Après plusieurs recherche c’est le premier article que je trouve avec une information importante concernant les entrées qui prennent du 3V3 max.

    Les relevés à l’oscilla sont très intéressants.
    Par contre pour l’utilisation côté utilisateur je trouve l’implémentation en python plus simple que celle en C.
    La librairie se trouve ici : https://pypi.python.org/pypi/RPi.GPIO et de nombreux exemples sont disponibles sur le web.
    J’ai hâte de commencer à utiliser ces GPIO pour la première fois !

    Bonne continuation,

    Cdlt,

  18. Flo_The_Geek dit :

    bonjour,
    Dans le cadre d’un projet j’ai besoin d’utiliser les broches GPIO de ma raspberry au niveau kernel j’ai pris exemple sur votre code mais j’ai un problème lors de la compilation il ne trouve pas le header .
    le système d’exploitation actuel de la raspberry celui fournis sur le site de raspberry, raspbian Whezzy.
    La version du kernel est la 3.10.25.
    Le manque de ce header est-il normal ou cela vient t’il de l’installation de l’os?
    Si cela est normal comment résoudre ce problème?

    Merci par avance de votre réponse,
    Flo_The_Geek

    • cpb dit :

      Bonjour,

      Malheureusement, la distribution Raspbian ne fournit pas les sources et les fichiers de configuration du kernel nécessaires pour compiler des modules. Il est donc indispensable de recompiler le noyau. Soit en faisant une cross-compilation depuis un PC, soit en recompilant le noyau directement sur le Raspberry (compter environ 6 heures).

      Cordialement,

  19. Ophelie dit :

    bonjour, votre document est très intéressant. j’aimerai savoir comment configurer les broches des GPIO pour les configurer comme des sorties de signaux numériques. merci d’avance

    • cpb dit :

      Bonjour,

      Pour sortir quel type de signaux ?

      • Ophelie dit :

        Bonjour, c’est une sortie numérique d’un capteur de température

        • cpb dit :

          En ce cas, je pense que le capteur doit communiquer ses mesures en utilisant un protocole I²C ou SPI.

          Il n’est pas nécessaire d’utiliser les GPIO, il suffit de relier directement les broches correspondantes du connecteur d’extension.
          Pour une communication en SPI, on peut se reporter à cet article.

          En i²C, il suffit de relier la ligne SDA du capteur à la broche 3 du Raspberry Pi, et la ligne SCL à la broche 5 (et de relier la masse également, sur la broche 25 par exemple).

          Ceci fait, il faut charger les modules kernel correspondants :

          # modprobe spi-bcm2708
          # modprobe spidev

          ou

          # modprobe i2c-bcm2708
          # modprobe i2c-dev

          Dans le premier cas, il suffira ensuite de lire le contenu de /dev/spidev0.0 par exemple, dans le second cas, je conseille d’installer les outils i2c-tools.

  20. Ophelie dit :

    merci beaucoup.

  21. cyrille dit :

    Bonjour,

    je viens de finir la toolschain en ayant suivi le tuto https://www.blaess.fr/christophe/2012/10/19/toolchain-crosstool-ng-pour-raspberry-pi/ merci encore .
    Donc maintenant ma toolschain fonctionne pas contre je souhaite utiliser rpi-gpio-2.c malheureusement je rencontre un problème car je n’ai pas les include linux/interrupt.
    Quelqu’un pourrais me dire ou les récupérer je pense avec apt-get linux header ou qq que chose comme ça.
    je suis sur une vm ubuntu 12.04 et dans /usr/include/linux les fichier ni sont pas.

    Merci a celui qui pourrais m’expliquer comme faire
    cyrille

    • cpb dit :

      Bonjour,

      Pour pouvoir compiler des modules pour le noyau Linux (comme c’est le cas pour rpi_gpio_1.c et rpi_gpio_2.c), il faut un Makefile particulier (comme celui indiqué dans l’article) dont on remplit la variable KERNEL_DIR avec le chemin des sources du noyau de la cible.

      Il ne faut donc pas lui donner le chemin des sources de votre PC (ce que vous obtiendrez avec apt-get install linux-headers) mais celui du noyau du Raspberry Pi.

      Si vous l’avez compilé vous même (à la manière décrite dans ces articles) vous avez les sources du kernel à disposition.

      Si vous utilisez sur le Raspberry Pi une distribution comme Raspbian, les en-têtes du noyau ne sont malheureusement pas fournis. Une solution relativement simple (mais qui va demander initialement un temps de compilation très long) est décrite dans cet article.

      • cyrille dit :

        Merci de ta réponse

        je n’ai fais aucune des 2 solutions d’écrites donc je vais faire la 2 ème :

        Si vous utilisez sur le Raspberry Pi une distribution comme Raspbian, les en-têtes du noyau ne sont malheureusement pas fournis. Une solution relativement simple (mais qui va demander initialement un temps de compilation très long) est décrite dans cet article.

        je commence de suite à moins que quelqu’un a déjà une image de faite ?

        par avance merci

  22. cyrille dit :

    Alors donc voila maintenant je peux utiliser les interrupts par contre j’ai besoin d’utiliser le stdio or j’ai une erreur.
    J’ai vérifié pour les includes interrupt = rpi-kernel/include/linux/interrupt.h
    par contre le stdio = /usr/include/stdio.h

    Comment faire pour l’utilisé du faite qu’il n’est pas dans le folder include.
    Par avance merci

    Cyrille

  23. cyrille dit :

    Aussi j’aurai une autre petite question après avoir activé le bouton qui est sur la GPIO 23 et bien je constate que l’utilisation du cpu ne fais que monté

    CPU0
    3: 55632 ARMCTRL BCM2708 Timer Tick
    16: 0 ARMCTRL bcm2708_fb dma
    32: 802570 ARMCTRL dwc_otg, dwc_otg_pcd, dwc_otg_hcd:usb1
    52: 24098 ARMCTRL BCM2708 GPIO catchall handler
    65: 7 ARMCTRL ARM Mailbox IRQ
    66: 1 ARMCTRL VCHIQ doorbell
    75: 1 ARMCTRL
    77: 21270 ARMCTRL bcm2708_sdhci (dma)
    83: 19 ARMCTRL uart-pl011
    84: 69625 ARMCTRL mmc0
    193: 24098 GPIO rpi_gpio_2
    FIQ: usb_fiq

    —————————————————————————————
    193: 32832 GPIO rpi_gpio_2
    —————————————————————————————
    193: 45614 GPIO rpi_gpio_2

    etc …
    Est ce que cela est normal?

    pour liberé la mémoire j’utiliserai free par contre je ne sais pas pour le CPU
    Cyrille

  24. cyrille dit :

    j’ai un petit problème car je ne peux pas utiliser stdio j’en ai besoin pour utiliser system() afin d’executer un script bash.

    j’ai suivi le tuto qui permet de re-compiler le kernel du raspberry https://www.blaess.fr/christophe/2014/03/06/compilation-native-de-modules-kernel-sur-raspberry-pi/

    Maintenant je peux utiliser interrupt par contre pas stdio
    Quelqu’un aurai une idée sur le sujet svp
    Cyrille

    • cpb dit :

      On ne doit pas appeler de code qui s’exécute en mode utilisateur (fichier exécutable invoqué par un system() par exemple) ni de script shell depuis un module qui fonctionne en espace noyau. C’est pour cela qu’il n’y a pas de <stdio.h> ou < dans les fichiers d'en-tête du kernel.

      • cyrille dit :

        l’objectif et de copier les fichiers d’origine après le clique sur le bouton.
        genre un reset configuration.
        Donc le faite d’avoir ton script plus haut permet d’écouter une action à tous moment ce qui m’intéresse .

  25. Adrian dit :

    Bonjour,

    J’ai pu voir que vous étiez spécialisé dans tout ce qui tourne autour de linux embarqué.
    Je suis de métier et de formation en informatique industrielle (plutôt soft) et je me mets progressivement à la programmation embarqué j’ai des bonnes connaissances en C mais je bloque un peu sur les datasheet de vrai cartes de développement (par d’arduino ou des raspbbery pi car les communautés sont énormes et les explications nombreuses). Je ne comprends pas comment et quelles informations allé chercher afin de pouvoir piloter tous les périphériques de n’importe qu’elle carte (en particulier les GPIO), mon souhait serait de pouvoir être autonome sur n’importe qu’elle carte pouvant embarquer linux juste en se débrouillant avec la datasheet de la carte et sans utilisé les script dans sys/class/gpio…..
    http://www.geekbuying.com/item/Firefly-RK3288-Quad-Core-Cortex-A17-Processors-Development-Board-2G-16G-Android-Ubuntu-Dual-System-2-4G-5G-WIFI-HDMI-2-0-Bluetooth-1000M-Ethernet-336460.html par exemple.

    merci d’avance

    • cpb dit :

      Bonjour,

      Pour gérer des entrées/sorties de type GPIO sous Linux, il y a principalement trois possibilités

      • Utiliser les accès via sysfs (par l’intermédiaire de scripts ou de programmes compilés) ce qui est la méthode la plus simple et la plus adaptable d’une plate-forme à l’autre. Si la carte qui vous intéresse supporte Linux, ces accès sont très probablement disponibles.
      • Utiliser les accès directs en faisant un mmap() de /dev/mem et en accédant directement aux ports du contrôleur de GPIO : efficace et rapide mais déconseillé car potentiellement dangereux et non portable (y compris vis-à-vis des évolutions d’une même carte comme la Raspberry Pi dont les accès ont changé entre la B et la B+).
      • Écrire un driver qui permettra de gérer dans le noyau le périphérique concerné et offrira une interface de haut-niveau pour l’espace utilisateur : méthode la plus satisfaisante intellectuellement mais relativement complexe pour une bonne écriture du code noyau.
  26. Thierry dit :

    Bonjour,
    J’arrive bien aprés la bagarre, mais ce tuto est vraiment excellent donc merci cpb.
    Cependant la RasPi a évoluée et nous en sommes aujourd’hui à la Pi3.
    Je ne retrouve nul part le répertoire /linux et ses sources …
    J’utilise actuellement la bibliothèque wiringPi de Gordon mais sur un simple exemple de recopie d’état d’une entrée sur une sortie comme le votre, il me manque des fronts !!!
    Y aurait-il moyen d’utiliser une autre librairie sur la Pi3 ?
    Merci pour l’info.
    Thierry

  27. kaka83136 dit :

    Article très intéressant,

    Par contre quand j’envoi une commande en python au port 24 configurer en OUT, cela se passe bien puis le GPIO 24 retourne à sa valeur par defaut IN.

    je suis obliger de refaire un gpio export 24 out après chaque commande

    Je comprends pas pourquoi.

    Merci à vous

  28. Franck dit :

    Bjr,
    merci pour votre article. De mon coté je cherche l’adresse de base du GPIO pour le RPI5. Ensuite comment écrire sur un port (ex port 17) en assembleur arm64 ou arm32 sans avoir l’erreur de segmentation à l’exé ou au debuggage (segmentation fault).
    FR

URL de trackback pour cette page