ESP32 adafruit et mcp: guru meditation

Bonsoir
Bon j'ai acheté un MCP23017 que je connecte en i2C sur ESP32.
La bibliothèque que j'utilise est Adafruit MCP23017 Arduino library.

Je cherche à savoir quel bouton a été appuyé lorsqu'une interruption est déclenchée. Voici le code:

//#include <Wire.h>
#include <Adafruit_MCP23X17.h>
bool buttonWasPressed = 0;
uint8_t pin;

Adafruit_MCP23X17 mcp;

void IRAM_ATTR handleInterrupt() {
  buttonWasPressed = 1;
  pin = mcp.getLastInterruptPin();
}

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("start");

  // Initialiser le MCP23017
  if (!mcp.begin_I2C()) {  //initialise mcp i2c
    Serial.println("Error.");
    while (1)
      ;
  }

  // Configurer les broches connectées aux boutons comme entrées
  mcp.pinMode(0, INPUT);
  mcp.pinMode(1, INPUT);

  // Configurer l'interruption pour les broches d'entrée
  mcp.setupInterrupts(true, false, LOW);
  mcp.readGPIOAB();  // Réinitialiser l'interruption

  // Attacher l'interruption à la fonction handleInterrupt()
  attachInterrupt(digitalPinToInterrupt(mcp.getLastInterruptPin()), handleInterrupt, CHANGE);
}

void loop() {
  if (buttonWasPressed = 1) {
    buttonWasPressed = 0;
    Serial.println("appui détecté");
    // Détecter quel bouton a été pressé
    if (pin == 0) {
      Serial.println("Bouton 0 pressé !");
    } else if (pin == 1) {
      Serial.println("Bouton 1 pressé !");
    }

    // Réinitialiser l'interruption
    mcp.digitalRead(pin);
  }
}

J'obtiens un message d'erreur, j'ai déjà eu un GURU MEDITATION parce que je demandais à la fonction IRAM_ATTR de faire beaucoup trop de choses, mais cette fois je ne lui demande quand-même pas la lune:

Backtrace: 0x400d2bd4:0x3ffb2210 0x400d2bf9:0x3ffb2240 0x400d1505:0x3ffb2260 0x400d4166:0x3ffb2290

ELF file SHA256: 0b6f23e5884f7e8b

Rebooting...

ets Jun 8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)

configsip: 0, SPIWP:0xee

clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00

mode:DIO, clock div:1

load:0x3fff0030,len:1344

load:0x40078000,len:13924

ho 0 tail 12 room 4

load:0x40080400,len:3600

entry 0x400805f0

bonjour kamo ,
comment l'esp32 sait sur laquelle de ses broches est raccordée la ligne d'interruption du mcp ?

Bonjour kammo

Tu fais:

attachInterrupt(digitalPinToInterrupt(mcp.getLastInterruptPin()), handleInterrupt, CHANGE);
Or, l'interruption, en l'occurence, doît être une pin de l'Arduino où est raccordée la pin INTA du MCP23017 et c'est dans la fonction handleInterrupt que tu peux faire mcp.getLastInterruptPin()

Dans l'exemple de la bibliothèque mcp23xxx_interrupt.ino c'est INT_PIN qui doit déclencher l'interruption:
attachInterrupt(digitalPinToInterrupt(INT_PIN), handleInterrupt, CHANGE);

Cordialement
jpbbricole

doit être déclarée volatile car modifiée sous interruption

Merci, c'est corrigé, bien vu.

#include <Adafruit_MCP23X17.h>

bool buttonWasPressed = false;
volatile uint8_t pin;
byte interrPin = 19;

Adafruit_MCP23X17 mcp;

// la fonction d'interruption
void IRAM_ATTR handleInterrupt() {
  pin = mcp.getLastInterruptPin(); //récupère le numéro du bouton qui a provoqué l'interruption
  buttonWasPressed = true; 
}

void setup() {
  Serial.begin(115200);
  pinMode(19, INPUT);

  // Initialiser le MCP23017
  if (!mcp.begin_I2C()) {  //initialise mcp i2c
    Serial.println("Error.");
    while (1)
      ;
  }

  // Configurer les broches connectées aux boutons comme entrées
  mcp.pinMode(0, INPUT);
  mcp.pinMode(1, INPUT);

  // Configurer l'interruption pour les broches d'entrée
  mcp.setupInterrupts(true, false, LOW); // là je ne comprends pas bien ce LOW si quelqu'un peut expliquer en deux mots...
  mcp.readGPIOAB();  // Réinitialiser l'interruption

  // Attacher l'interruption à la fonction handleInterrupt()
  attachInterrupt(digitalPinToInterrupt(interrPin), handleInterrupt, RISING);
}

void loop() {
  if (buttonWasPressed) {
    Serial.println(pin); // affiche quel bouton a été pressé
    delay(250);

    // Réinitialiser l'interruption
    mcp.readGPIOAB();

    buttonWasPressed = false;
  }
}


Qu'est ce que je ne comprends pas ? Ca ne fonctionne toujours pas...
Bon entre temps j'ai demandé à chatGPT pour voir, il ajoute des erreurs XD

typiquement (mais ça peut aussi être l'inverse ... ) , l'état actif des sorties d'interruption du mcp23017 est "LOW"
donc , si je ne m'abuse , dans ton attachInterrupt(...) , la condition de niveau doit être "LOW" ou éventuellement "FALLING"

1 Like

La petite explication demandée:

	// Configurer les interruption pour le MCP23017
	// Leinterruptions A et B sont regroupées sur la pin INTA
	// false = INTA et INTB ont une résistance de PULLUP
	// low = signal actif à LOW donc FALLING
	mcp.setupInterrupts(true, false, LOW); // là je ne comprends pas bien ce LOW si quelqu'un peut expliquer en deux mots...

donc l'interruption de l'Arduino doit s'initialiser ainsi:
attachInterrupt(digitalPinToInterrupt(interrPin), handleInterrupt, FALLING);

La réinitialisation des interruptions ainsi:
mcp.clearInterrupts(); // clear

Tu n'as pas initialisé l'interruption des pin 0 et 1 du MCP:

  mcp.setupInterruptPin(0, LOW);
  mcp.setupInterruptPin(1, LOW);

As-tu une liaison entre la pin INTA du MCP et la pin interrPin de l'Arduino?

A+
Cordialement
jpbbricole

J'ai revérifié les câbles. J'ai bien mis ITA sur 19.
J'ai retouché le code comme suit:

#include <Adafruit_MCP23X17.h>

bool buttonWasPressed = false;
volatile uint8_t pin;
byte interrPin = 19;

Adafruit_MCP23X17 mcp;

// la fonction d'interruption
void IRAM_ATTR handleInterrupt() {
  pin = mcp.getLastInterruptPin();  //récupère le numéro du bouton qui a provoqué l'interruption
  buttonWasPressed = true;
}

void setup() {
  Serial.begin(115200);

  pinMode(19, INPUT);  //relié à ITA du mcp

  // Initialiser le MCP23017
  if (!mcp.begin_I2C()) {  //initialise mcp i2c
    Serial.println("Error.");
    while (1);
  }

  // Configurer les broches connectées aux boutons comme entrées
  mcp.pinMode(0, INPUT);
  mcp.pinMode(1, INPUT);

  // initialiser l'interruption
  mcp.setupInterruptPin(0, LOW);
  mcp.setupInterruptPin(1, LOW);

  // Configurer l'interruption pour les broches d'entrée
  mcp.setupInterrupts(true, false, LOW);  
  mcp.readGPIOAB();                       // Réinitialiser l'interruption

  // Attacher l'interruption à la fonction handleInterrupt()
  attachInterrupt(digitalPinToInterrupt(interrPin), handleInterrupt, FALLING);

  Serial.println("setup terminé");
}

void loop() {
  if (buttonWasPressed) {
     buttonWasPressed = false;
    Serial.println(pin);  // affiche quel bouton a été pressé
    delay(250);   
  }
}

Je téléverse et rien. Du coup je reboot l'esp32 avec les petit bouton et là je me prends ceci:

load:0x3fff0030,len:1344

load:0x40078000,len:13924

ho 0 tail 12 room 4

load:0x40080400,len:3600

entry 0x400805f0

E (143) esp_core_dump_f��͡� Core dump data check failed:

Calculated checksum='f2ab91e7'

Image checksum='ffffffff'

setup

setup terminé

y a un encore truc qui me chipote :

◆ getLastInterruptPin()
uint8_t Adafruit_MCP23XXX::getLastInterruptPin	(		)	
Gets the pin that caused the latest interrupt, from INTF, without clearing any interrupt flags.

la lecture des flags ne les efface pas , il faut sans doute faire une lecture du PORTA en fin de routine ...

Je dois bien admettre que je n'y comprends plus rien, là.
Les interruptions c'est quand-même un monde à part...
Le plus bizarre pour moi c'est de ne pas trouver un bête code d'exemple qui fonctionne avec quelques boutons.

Bonjour,

Certainement car ce n'est en général pas une bonne idée de traiter les boutons par une interruption.
Mais ça peut être un exercice intellectuel intéressant..

Si je veux pouvoir exécuter du code avec un peu d'algorithmique (jeu de lumières avec un ruban led) et qu'un compteur se stoppe net quand j'appuie sur un bouton, je pense que je n'ai pas vraiment le choix. Je peux me tromper. dans tous les cas, même si j'essaie autrement, il faut que je surveille chacun des boutons en boucle pour voir qui est appuyé... Je trouve ça tellement lourd...

C'est vrai, semble-t-il, mais honnêtement je ne comprends pas pourquoi. Les interruptions ne sont pas utilisables avec de la mécanique? Juste avec du hall ou de l'optique? C'est à cause des rebonds?
Je vois bien que je m'acharne à faire un truc débile mais je ne comprends pas pourquoi c'est si stupide

Bonjour kammo

Oui, mais, une fois que tu maîtrises, c'est super à utiliser.

Des boutons gérés par interruption, sont légion, c'est souvent "caché" dans une bibliothèque, par contre, dans ton cas, des boutons en interruption via un MCP23017, c'est vrai que je n'ai pas croisé souvent.
J'ai fait l'exercice sur un ESP32 (M5Stick) en faisant l'exemple de la bibliothèque Adafruit_MCP23X17.h mcp23xxx_interrupt.ino. Ca ne déclenche pas d'interruption au niveau de l'ESP, mais ça la signale, pour autant que tu aies relié la pin INTA du MCP à la pin que tu a désignée pour recevoir l'interruption (INT_PIN). Après ça, il te suffira de mettre un LOW sur l'entrée BUTTON_PIN de l'ESP pour voir dans le moniteur, à 9600:

Interrupt detected on pin: 1

Une fois que tu as maîtrisé ça, on fera marcher l'interruption sur l'ESP.

A+
Cordialement
jpbbricole

Pourtant ça permet d'exclure la gestion des boutons de la machine à état ou de devoir en gérer deux.

Bonjour kamill

J'avoue que je suis surpris par ton propos, pourquoi ce n'est poas une bonne idée?

J'abonde dans le sens de @kammo:

en effet, c'est lourd, alors qu'avec des interruptions, "on ne s'occupe plus de ça" on nous dit juste quand, c'est quand même plus simple?

A+
Cordialement
jpbbricole

Le temps d'appui sur un bouton par un humain va être de l'ordre de la centaine de ms (voire de plusieurs centaines de ms). Ce n'est en général pas la peine de prendre en compte cet appui à la microseconde.
On a le temps de lire le bouton dans la boucle principale pour peu qu'elle dure moins de 100 ms (c'est pour ça que j'ai écrit en général).

Oui mais justement, c'est le but, d'être au millième. Même si ça semble un peu tiré par les cheveux, je veux vraiment tirer le meilleur de la machine. Je comprends ce que tu veux dire mais l'idée sur ce truc, c'est vraiment d'être au millième.
je construis un jeu de la taupe où c'est l'ESP32 qui jouera et affrontera un humain. Mais ça, c'est top secret... :speak_no_evil:

Bonjour kamill

La question n'est pas là, comme l'a dit @kammo , sens dans lequel j'abonde:

Cordialement
jpbbricole