Interrupt esterno su Esp32 che parte anche quando non dovrebbe

di il
8 risposte

Interrupt esterno su Esp32 che parte anche quando non dovrebbe

Dispongo di una schedina Heltec wifi kit 32 V3, e' la classica Esp32-S3 con piccolo display oled, si programma via usb con ide Arduino

Vorrei leggere un encoder incrementale, coi classici due segnali A-B sfasati di 90 gradi tra loro

L'idea e' di settare uno dei due pin sui quali fornisco i segnali A e B come sorgente di un interrupt, e quando viene rilevato l'evento dalla cpu, nella routine di gestione dell'interrupt verificare se l'altro pin sia alto o basso e di conseguenza aumentare o diminuire il contatore che tiene conto dei ‘colpi’ encoder letti

Il codice usato e' quello riportato sotto

L'interrupt viene settato sul fronte di discesa del segnale A (collegato al pin GPIO4 nel mio caso, il pin 15 di J2)

Rilevo un'anomalia sostanziale, la routine di gestione dell'interrupt viene fatta partire sia sul fronte di salita che su quello di discesa del segnale A, e questo lo vedo chiaramente perche' nella routine di gestione dell'interrupt alzo un pin uscita e lo abbasso prima di terminare la routine isr, e mi consente di ‘vedere’ con l'oscilloscopio l'attivita' del codice, e quindi sono sicuro che lesecuzione della routine isr avviene sia sul fronte di salita che su quello di discesa del segnale A

Sto usando il fronte di discesa perche' e' quello piu' ripido tra i due e quindi immagino possa funzionare meglio a livello elettrico del fronte di salita che e' leggermente meno rapido

Riguardando il codice, non riesco a trovare nessuna anomalia che porti a pensare il motivo per cui l'isr parta anche in corrispondenza del fronte di salita, dovrebbe partire solamente sul fronte di discesa del segnale A, ma cosi' non e' purtroppo

Qualcuno di voi ha usato questa scheda o simili ed ha rilevato lo stesso problema?

#define pin_A         4 		          // pin 15 - J2
#define pin_B         2		            // pin 17 - J2
#define pin_CALIBRATE 6               //  pin 13 - J2
#define pin_CLOCK_sync_interrupt  42

// Variabile per il conteggio
volatile unsigned int verso = 0;
volatile unsigned long conteggio   ; // Esempio di valore iniziale per test

void IRAM_ATTR pin_A_isr() {
  digitalWrite(pin_CLOCK_sync_interrupt, HIGH);
  
  // Leggi lo stato del pin B
  bool stato_b = digitalRead(pin_A);

  if (stato_b == HIGH) {
    // Rotazione in senso orario
    // Aggiungi qui il codice per la rotazione in senso orario
    verso=1;
    conteggio++;
    } else {
    // Rotazione in senso antiorario
    // Aggiungi qui il codice per la rotazione in senso antiorario
    verso=0;
    conteggio--;
    }
    
    delay_rob(50);
    digitalWrite(pin_CLOCK_sync_interrupt, LOW);
  }

void delay_rob(unsigned long attesa_microsecondi) {
  unsigned long tempoInizio = micros();  // Registra l'istante iniziale
  while (micros() - tempoInizio < attesa_microsecondi) {
    // Questo loop vuoto permette agli interrupt di essere eseguiti
    // mentre si attende che passino 'attesa_microsecondi'
    } 
  }

void setup() {
  Serial.begin(115200);
  
  pinMode(pin_CLOCK_sync_interrupt, OUTPUT);  digitalWrite(pin_CLOCK_sync_interrupt, LOW); // Assicurati che il pin sia basso all'avvio
 
  pinMode(pin_A,INPUT_PULLUP);
  pinMode(pin_B,INPUT_PULLUP);
  pinMode(pin_CALIBRATE,INPUT);
  
  attachInterrupt(digitalPinToInterrupt(pin_A), pin_A_isr, FALLING);
  conteggio=8000000;
  Serial.println("----------------------");
  }


void loop() {
  Serial.println(String(conteggio));
  }

							

8 Risposte

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Guarda che per la quadratura ti serve sia il fronte di salita che quello di discesa sia di A che di B: se triggeri solo la discesa di A, come fai, ad esempio, a sapere se sei ancora nella stessa posizione a seguito di un'oscillazione sul posto oppure quattro passi avanti? È lo step/direzione dove puoi fare solo fronte di salita o solo fronte di discesa del treno di impulsi. Inoltre, la risoluzione dell'encoder e/o la velocità di rotazione devono essere adeguatamente basse, altrimenti ti serve un micro con una periferica dedicata.

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Si certo, ed infatti nella routine  pin_A_isr  il codice va a verificare se in quel momento la linea B e' alta oppure bassa

    A seguito della verifica incrementera' o decrementera' il contatore dei passi encoder

    “..seguito di un'oscillazione sul posto oppure quattro passi avanti..” questa non l'ho capita, se stai ipotizzando che il segnale elettrico non sia adeguatamente stabile direi che bisogna intervenire sul segnale elettrico, non stiamo parlando di un pulsante dove i rimbalzi sono una certezza ed un buon debounce da codice e' indispensabile, ma di un segnale che di suo deve essere a posto, se gia' l'uscita encoder e' ballonzolante allora bisogna metterci un trigger di schmidt o sistema analogo per ‘ripulirlo’ dalle ambiguita', ma quel che deve saltar fuori sono due onde quadre sfasate tra loro di un quarto del periodo, la frequenza potra' pure variare e quindi il segnale allargarsi o stringersi, ma elettricamente deve essere a posto

    Per quanto riguarda la velocita' rotazione mi e' sufficiente leggere una coppia di segnali tra 0 e 4 KHz max, e quindi restiamo nella zona delle centinaia di microsecondi tra un fronte e l'altro, non mi sembra un segnale particolarmente rapido almeno per la schedina usata

    Quello che davvero non riesco a capacitarmi e' come mai dopo aver impostato

    attachInterrupt(digitalPinToInterrupt(pin_A), pin_A_isr, FALLING);

    mi ritrovo la routine di gestione interrupt che parte sia sul fronte di discesa del segnale A (come mi aspetto che sia) sia sul fronte di salita del segnale A (e questo e' totalmente incomprensibile visto il codice)

    In effetti il programma reale e' molto piu' complesso del frammento sopra, ma anche lanciare in esecuzione solamente le trenta righe indicate sopra consente di riprodurre correttamente il problema, provato anche su seconda schedina uguale, stesso problema

    Sto iniziando a pensare che il pin GPIO4 non sia idoneo ad essere usato come fonte esterna di un interrupt, ma dalle ricerche che ho fatto trovo che dovrebbe essere possibile usarlo come segnale da collegare ad un interrupt interno

    https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-reference/peripherals/gpio.html#gpio-summary

    “…The ESP32-S3 chip features 45 physical GPIO pins (GPIO0 ~ GPIO21 and GPIO26 ~ GPIO48). Each pin can be used as a general-purpose I/O, or be connected to an internal peripheral signal…”

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Ma non funziona così la quadratura

    metti che l'encoder sta oscillando nel punto indicato dalla croce: se tu triggeri solo sulla transizione bassa di A  (da sinistra a destra), quando l'encoder torna indietro (da destra a sinistra) tu non conti il passo indietro perché non triggeri sulla transizione alta; quando torni a destra aggiungerai un altro passo, e così via, insomma aggiungi sempre passi a destra ma l'encoder è fermo

    è giusto che la routine di interrupt sia sia sul fronte di salita che quello di discesa. Rivedi un attimo la logica

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Si hai ragione, la logica usata, anche se attualmente funziona, non e' corretta

    Resta il problema del post, di capire come mai parte la routine di servizio dell'interrupt anche sul fronte di salita del segnale, anche se impostata per partire solamente sul fronte di discesa

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Tu comincia a scrivere il codice corretto, con CHANGE al posto di FALLING e con digitalRead(pin_A) e 
    digitalRead(pin_B)  su due variabili booleane diverse (il codice originale non era comunque corretto visto che leggevi lo status di B dal pin A).

    Se usi solo un pin (A) per l'interrupt, dimezzi la risoluzione, ma comunque puoi scrivere una logica corretta.

    Una volta che hai scritto il codice corretto, puoi procedere alle analisi del caso e vedere anche se Arduino sbaglia qualcosa a basso livello. Puoi pure fregartene se sbaglia qualche impostazione che, comunque, nel tuo caso non serve…

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Ringrazio per la risposta, ma relativamente alla domanda posta, non e' di nessuna rilevanza

    La domanda e'   “.. interrupt esterno su Esp32 che parte anche quando non dovrebbe..”

    Il fatto che il segnale venga usato per leggere un encoder, in questo caso non ha nessuna importanza, avrebbe potuto essere la lettura della durata periodo di un segnale o altra misura simile

    Quello che desidero capire e' il motivo per cui la scheda si comporta in modo diverso da quello che dovrebbe descrivere il programma

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    Il codice di Arduino è un wrapper: l'impostazione della porta è a basso livello. Finché non controlli quella non puoi dire che il micro non sia adeguato.

    Se davvero triggera il rising quando imposti solo il falling, vai sul forum di supporto con il codice semplificato che isola il problema (imposti e utilizzi solo quel pin) e gli screenshot dell'oscilloscopio.

    Anche se fosse confermato l'errore, se vuoi solo il falling comunque avresti a disposizione un workaround semplice: all'interno dell'interrupt fai un if sullo status del pin.

  • Re: Interrupt esterno su Esp32 che parte anche quando non dovrebbe

    25/05/2024 - Weierstrass ha scritto:


    Il codice di Arduino è un wrapper: l'impostazione della porta è a basso livello. Finché non controlli quella non puoi dire che il micro non sia adeguato.

    Vuoi dire che ipotizzi che il codice Arduino, pure usando le librerie di base, potrebbe non funzionare correttamente? 

    Se davvero triggera il rising quando imposti solo il falling, vai sul forum di supporto con il codice semplificato che isola il problema (imposti e utilizzi solo quel pin) e gli screenshot dell'oscilloscopio.

    Gia' fatto

    Anche se fosse confermato l'errore, se vuoi solo il falling comunque avresti a disposizione un workaround semplice: all'interno dell'interrupt fai un if sullo status del pin.

    Gia' fatto

    Restava la curiosita' di capire come mai sta scheda non obbedisca ai comandi

Devi accedere o registrarti per scrivere nel forum
8 risposte