1. #1
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    avril 2011
    Messages
    126
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Arts - Culture

    Informations forums :
    Inscription : avril 2011
    Messages : 126
    Points : 67
    Points
    67

    Par défaut MCP23017 et les interruptions

    Bonjour à tous !
    Dans mon projet, j'utilise un MCP23017 sur mon RPI3 (distribution Raspbian).
    Mon but est de déclencher une action lorsqu'on appuie sur un bouton poussoir sur l'entrée GPA0 ou GPA3 du MCP23017.
    J'ai écrit le programme python suivant :
    Code python : 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
    62
    63
    64
    65
    66
    67
    #-------------------------------------------------
    # Test for interrupt detection on GPA0 or GPA3
     #-------------------------------------------------
    import RPi.GPIO as GPIO 
    import smbus
    import time
    
    DEVICE  = 0x20 # Device address (A0-A2)
    IODIRA  = 0x00 # Pin direction register for GPA
    GPINTENA= 0x04 # Enable interrupt for GPA
    DEFVAL  = 0x06 # Reference values for the interruptions on GPA
    INTCONA = 0x08 # Interruption mode -- 1:compare to DEFVAL, 0:compare to its old value
    INTCAPA = 0x10 # value stored after an interruption
    GPIOA   = 0x12 # GPA register for input
    GPIOINT = 26   # GPIO pin for the interruption line
    GPA0    = 1    # decimal value of GPA0 in the GPA register
    GPA3    = 8    # decimal value of GPA3 in the GPA register
    
    bus = smbus.SMBus(1)
    
    # Set GPA1,2,4,5,6,7 as output the GPA0,3 as input
    bus.write_byte_data(DEVICE,IODIRA,0x09)
    
    # Define the reference values for the GPAs
    bus.write_byte_data(DEVICE,DEFVAL,0x00)
    
    # Define the interruption mode for GPAs
    bus.write_byte_data(DEVICE,INTCONA,0x09)
    
    # Enable interrupt on GPA0 and GPA3
    bus.write_byte_data(DEVICE,GPINTENA,0x09)
    
    # set up BCM GPIO numbering 
    GPIO.setmode(GPIO.BCM)  
    
    # set GPIOINT as input : pin GPIO26 of the RPI3 linked to INTA 
    GPIO.setup(GPIOINT, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) 
    
    def trigger_callback(channel):
        reg_interrupt_a = bus.read_byte_data(DEVICE,INTCAPA)
        if GPIO.input(channel) == 1:
            print time.strftime("%d.%m.%Y %H:%M:%S"), "Channel " + str(channel) + " :"
            if reg_interrupt_a == GPA0:
                print "-- GPA0 has been triggered"
            elif reg_interrupt_a == GPA3:
                print "-- GPA3 has been triggered"
    
    # When a rising edge is detected on port GPIOINT,
    # the function trigger_callback will run
    # Add 75ms to avoid any bounce effect
    GPIO.add_event_detect(GPIOINT, GPIO.RISING, callback=trigger_callback, bouncetime=75)
    
    # Main loop
    while True:
        try:
            reg_input = bus.read_byte_data(DEVICE,INTCAPA) # **** Needed to trigger the interruption !!!!
            time.sleep(0.1)
        except KeyboardInterrupt:
            print "Program has ended with a CTRL C"
            print "Cleaning all..."
            GPIO.remove_event_detect(GPIOINT) # remove any event detection
            GPIO.cleanup() # clean up GPIO on CTRL+C
            exit()
    
    GPIO.remove_event_detect(GPIOINT)
    GPIO.cleanup()

    Mon problème est le suivant : je suis obligé de lire dans le registre INTCAPA (ou GPIOA) dans ma boucle (voir commentaire avec****) pour pouvoir déclencher la fonction 'trigger_callback'.
    Si je ne le fais pas, rien ne se passe !!!
    Si je le fais, tout se passe comme prévu...
    Pourquoi ? Ça ne me paraît pas très logique...ou j'ai raté quelque chose.
    J'ai lu la doc du MCP23017 (http://ww1.microchip.com/downloads/e...Doc/21952b.pdf) et rien n'est dit à ce sujet. Il est juste dit que les interruptions sont effacées à la lecture du INITCAPA ou GPIOA, ce que je fais dans le 'trigger_callback'.
    Ci-joint mon schéma de connection.
    Merci d'avance pour vos réponses ou débuts de réponses...Nom : montage_interruptions.jpg
Affichages : 42
Taille : 30,0 Ko

  2. #2
    Modérateur
    Avatar de Vincent PETIT
    Homme Profil pro
    Ancien développeur matériel électronique (Hard/Soft)
    Inscrit en
    avril 2002
    Messages
    1 737
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ancien développeur matériel électronique (Hard/Soft)
    Secteur : Service public

    Informations forums :
    Inscription : avril 2002
    Messages : 1 737
    Points : 5 555
    Points
    5 555

    Par défaut

    Salut,
    Le fait de lire INTCAPA efface le flag de l'interruption pour le coup d'après (reset ou réarmement de l'interruption).

    Peut être que tu démarres avec une mauvaise initialisation.

    Essaye ceci :

    Code PYTHON : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    # Set GPA1,2,4,5,6,7 as output the GPA0,3 as input
    bus.write_byte_data(DEVICE,IODIRA,0x09)
     
    # Interruption "sur évenement" activée sur GPA0 et GPA3 
    bus.write_byte_data(DEVICE,GPINTENA,0x09)
     
    # On compare l'évenement avec l'état précédent de GPA0 et GPA3 (donc à chaque changement on génère une interruption) 
    bus.write_byte_data(DEVICE,INTCONA,0x00)
     
    # Interruption active INTA = High sinon alors INTA = Low
    bus.write_byte_data(DEVICE,IOCONA,0x02)

    Ensuite avec ton Raspberry, tu scrutes la broche d'interruption GPIOINT donc la broche 26 du Raspberry et si elle passe à High, ce qui devrait être la cas à chaque fois que tu touches a un bouton (attention : relâché ou enfoncé), alors tu lis INTCAPA bus.read_byte_data(DEVICE,INTCAPA) pour d'une part savoir quelle bouton a été enfoncé et d'autre part pour réarmer l'interruption.

    D'après ce que j'ai compris dans la doc, il peut être intéressant de lire aussi INTFA car si jamais deux interruptions se sont produites l'une juste derrière l'autre, tu peux le voir tandis que INTCAPA semble verrouiller l'état du PORTA dès qu'une interruption est activée ce qui te permettra de voir que la première des deux interruptions qui se suivaient.
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  3. #3
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    avril 2011
    Messages
    126
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Arts - Culture

    Informations forums :
    Inscription : avril 2011
    Messages : 126
    Points : 67
    Points
    67

    Par défaut

    Salut !
    Merci pour ta réponse Vincent...

    Ensuite avec ton Raspberry, tu scrutes la broche d'interruption GPIOINT donc la broche 26 du Raspberry et si elle passe à High, ce qui devrait être la cas à chaque fois que tu touches a un bouton (attention : relâché ou enfoncé), alors tu lis INTCAPA bus.read_byte_data(DEVICE,INTCAPA) pour d'une part savoir quelle bouton a été enfoncé et d'autre part pour réarmer l'interruption.
    Oui, c'est ce que j'ai pu voir en faisant mes tests. De ce côté, ça marche. A noter que mon bouton poussoir ne maintient pas la position, il laisse passer du 5V tant que mon doigt le maintient enfoncé.

    D'après ce que j'ai compris dans la doc, il peut être intéressant de lire aussi INTFA car si jamais deux interruptions se sont produites l'une juste derrière l'autre, tu peux le voir tandis que INTCAPA semble verrouiller l'état du PORTA dès qu'une interruption est activée ce qui te permettra de voir que la première des deux interruptions qui se suivaient.
    J'ai aussi testé la lecture de INTFA. Lorsque je rentre dans la fonction d'interruption, ce registre a malheureusement déjà été reseté. C'est sûrement dû à la lecture de INTCAPA dans la boucle principale dont je veux m'affranchir.
    J'ai pu le voir changer de valeur dans la boucle principale de manière furtive...

    # On compare l'évenement avec l'état précédent de GPA0 et GPA3 (donc à chaque changement on génère une interruption)
    bus.write_byte_data(DEVICE,INTCONA,0x00)
    Avec la particularité de mes boutons poussoirs (5V si maintenu enfoncé), cela ne risque pas de générer des problèmes ? Du genre, 2 interruptions au lieu d'une ?

    # Interruption active INTA = High sinon alors INTA = Low
    bus.write_byte_data(DEVICE,IOCONA,0x02)
    Bit 1 : INTPOL --> Cela revient à définir la polarité du INTA : 1 à Active-high et 0 à active-low. Ce n'est pas déjà le cas par défaut ?

    Quoiqu'il en soit, je vais essayer ton intialisation sur INTCONA et IOCONA : je vais prendre ton initialisation et supprimer l'initialisation de DEFVAL puis supprimer la lecture du INITCAPA dans ma boucle principale...
    et je te tiens au courant...

  4. #4
    Modérateur
    Avatar de Vincent PETIT
    Homme Profil pro
    Ancien développeur matériel électronique (Hard/Soft)
    Inscrit en
    avril 2002
    Messages
    1 737
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Pas de Calais (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Ancien développeur matériel électronique (Hard/Soft)
    Secteur : Service public

    Informations forums :
    Inscription : avril 2002
    Messages : 1 737
    Points : 5 555
    Points
    5 555

    Par défaut

    Citation Envoyé par PatSan Voir le message
    Avec la particularité de mes boutons poussoirs (5V si maintenu enfoncé), cela ne risque pas de générer des problèmes ? Du genre, 2 interruptions au lieu d'une ?
    Ah ok ! J'avais mal lu le message d'origine, désolé.

    En effet il faut passé par DEFVAL sinon, comme tu le dis, il y aura deux interruptions.

    Dans ton premier programme je pense que c'est juste la condition de démarrage qui n'est pas bonne, d'où la nécessité d'effacer le flag une fois lors du démarrage.

    Citation Envoyé par PatSan Voir le message
    Bit 1 : INTPOL --> Cela revient à définir la polarité du INTA : 1 à Active-high et 0 à active-low. Ce n'est pas déjà le cas par défaut ?
    Pour moi, par défaut si une interruption se produit alors la broche INTA passe de l'état haut à l'état bas. Je ne suis pas calé en Python car je suis seulement entrain de l'apprendre mais ne t'attendais tu pas à voir l'inverse ? C'est à dire que lorsque l'interruption se produit, de voir un passage de l'état bas à l'état haut ?
    La science ne nous apprend rien : c'est l'expérience qui nous apprend quelque chose.
    Richard Feynman

  5. #5
    Membre du Club
    Homme Profil pro
    Développeur Web
    Inscrit en
    avril 2011
    Messages
    126
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : Arts - Culture

    Informations forums :
    Inscription : avril 2011
    Messages : 126
    Points : 67
    Points
    67

    Par défaut

    mais ne t'attendais tu pas à voir l'inverse ? C'est à dire que lorsque l'interruption se produit, de voir un passage de l'état bas à l'état haut ?
    Oui, effectivement.

    Voici ce que j'ai testé à partir de tes remarques: définir DEFVALA, comme dans mon pgm initial, définir IOCONA (0x0A) avec la valeur 0x02, comme tu l'as suggéré et faire un reset des flags d'interruption (par lecture de INTCAPA) avant la boucle puis enfin, supprimer la lecture de INTCAPA dans la boucle.
    Résultat : je peux capter la première interruption mais après, plus rien n'est capté...

Discussions similaires

  1. Comment le SE Windows Gère les interruptions ?
    Par elmessoussi dans le forum Windows
    Réponses: 2
    Dernier message: 16/10/2005, 23h29
  2. Erreur dans BosoKernel pour les interruptions ?
    Par Edouard Kaiser dans le forum Assembleur
    Réponses: 6
    Dernier message: 09/08/2005, 13h18
  3. Les interruptions + ring 0 ?
    Par MonsieurAk dans le forum x86 32-bits / 64-bits
    Réponses: 12
    Dernier message: 29/09/2003, 08h51
  4. Les interruptions sous Windows et Linux
    Par Descartes dans le forum x86 32-bits / 64-bits
    Réponses: 7
    Dernier message: 07/06/2003, 22h42
  5. Tracer une ligne droite sans les interruptions
    Par Stef784ever dans le forum x86 16-bits
    Réponses: 4
    Dernier message: 25/11/2002, 01h22

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