Esp32 che esegue codice routine servizio interrupt quando vuole lui

Jun 02, 2024 Last reply: 2 anni fa 9 Replies

Sto usando una schedina con Esp32-C3, in ambiente programamzione Arduino, per simulare un encoder con interfaccia ssi, la scheda/encoder viene letta da un plc con apposito modulo ssi inserito Il protocollo ssi e' una seriale sincrona con lunghezza 25 bit (o 13 o



32 in altre versioni)

E' tutto molto semplice, il plc invia alla scheda con l'esp32 un segnale che chiamero' Clock, normalmente alto, e ad ogni fronte di discesa del segnale Clock la scheda esp32 deve rispondere settando o resettando un pin, nel mio caso il Gpio47, linea Dati Dopo 25 fronti di discesa del segnale Clock, la lettura e' finita e la linea Dati viene portata alta, come di default



Di seguito il codice che ottiene l'effetto desiderato nella maggior parte delle volte, perche' alcune volte (una lettura ogni qualche migliaia) la sequenza di bit vien su scorretta



Vai a vedere i segnali elettrici, ed il problema sembra essere la linea dati, il pin gpio47 del micro che esegue i comandi previsti ma con precisione temporale molto bassa Qui un video che fa capire bene la variabilita' dei set/reset pin della linea Dati rispetto ai fronti di discesa della linea Clock



formatting link
In sostanza, ad ogni fronte di discesa della linea Clock, parte la routine pin_CLOCK_isr_falling() che va a settare o resettare il bit corrente (dal 25 a 0) sulla linea Dati, ma come si vede dal video il codice della routine di servizio dell'interrupt sembra partire una volta dopo 3 uSec, un'altra dopo 8 uSec, un'altra dopo 5 uSec, e questa imprecisione a volte provoca la lettura scorretta sul plc



Ipotizzo che sia qualcosa legato all'architettura dell'Esp32 che integra un sistema per consentire lo sfruttamento ottimale di tutte le periferiche, e quindi alcune volte fa un po' lui quello che gli pare, abbandonando il flusso del codice programma utente



Le domande sono:



- da cosa dipende esattamente la variabilita' dei tempi di risposta del codice nella routine di servizio dell'interrupt?



- come limitare/eliminare questo problema?


--------------------------------------------------------------------



#include <Arduino.h>



#include <Wire.h>



#define pin_CLOCK 26 #define pin_DATA 47



volatile unsigned long tempo_ingresso_clock=0; volatile unsigned long tempo_ingresso_clock_precedente=0; volatile int numero_bit_inviati = 0; volatile unsigned long conteggio_congelato_per_invio_a_plc = 0;



void IRAM_ATTR pin_CLOCK_isr_falling() { tempo_ingresso_clock=micros();



if ((tempo_ingresso_clock - tempo_ingresso_clock_precedente)>300) { tempo_ingresso_clock_precedente=tempo_ingresso_clock;



// Manda in uscita il primo bit dei 25, il MSB della parola intera numero_bit_inviati = 25; conteggio_congelato_per_invio_a_plc = 6710886 ^ (6710886 >> 1); } else { // Manda in uscita il bit dei 25 della parola intera numero_bit_inviati = numero_bit_inviati - 1; }



digitalWrite(pin_DATA, (conteggio_congelato_per_invio_a_plc >> (numero_bit_inviati-2)) & 0x01);



if (numero_bit_inviati==0) { digitalWrite(pin_DATA, HIGH); }



}

void setup() { setCpuFrequencyMhz(240); pinMode(pin_CLOCK, INPUT_PULLUP); pinMode(pin_DATA, OUTPUT); digitalWrite(pin_DATA, HIGH); attachInterrupt(digitalPinToInterrupt(pin_CLOCK), pin_CLOCK_isr_falling, FALLING); }



void loop() { // ciclo vuoto per test tempi }


5-8 us mi sembrano tempi piu' che ragionevoli per la latenza degli interrupt, che dipende da cosa stava facendo la CPU nel momento in cui il segnale hardware di interrupt e' arrivato. Leggi ad esempio:
formatting link
ottenere timing accurati come vuoi tu col software, non so se sia fattibile configurando opportunamente una periferica dell'ESP.

Ciao,

Ringrazio molto per il link, che avevo gia' trovato e letto durante le ricerche precedenti, e onestamente mi pare ben strano perche' parlano di un 'context switch' da 15 us, che pur non avendo ancora approfondito sulla documentazione ufficiale, mi sembra davvero lunghetto Ad eventuali interessati all'argomento segnalo questo link dove si risponde ad un tizio che chiede se sia disabilitabile l'rtos

formatting link
Dici che 5-8 us sono tempi ragionevoli, su una cpu da 240 MHz? A naso, mi sembrano tempi abbastanza lunghetti, un po' troppo

Ho provato anche:

- portENTER_CRITICAL_ISR(&mux)/portEXIT_CRITICAL_ISR(&mux) ad inizio e fine routine interrupt, ma niente, tutto come prima

- disabilitare wifi e bt, identico a prima

15us di context switch in ambiente arduino sono veramente ragionevoli, anzi direi eccezionali...

Ti stai addentrando in un mondo dove per essere in grado di avere latenze e jitter piu' bassi le cose diventano molto piu' complicate se non impossibili. In qualunque progetto commerciale dove c'e' bisogno di quei numeri si mette una FPGA (o piu' ragionevolmente nel tuo caso un CPLD), non lo si fa in software

Ma stai scrivendo di 15 "microsecondi" ? A mia esperienza impiegare quel tempo solo per mettere via un po' di registri e saltare nella routine dell'interrupt sono un'enormita', considerando che stiamo parlando di una cpu che gira a 240 MHz

E non e' neanche la programmazione via ide Arduino che mortifica piu' di tanto le prestazioni, si qualcosa ci mettera' di suo ma sicuramente non decuplica il tempo per ogni istruzione

Piuttosto nel caso specifico dell'esp32 c'e' di mezzo quella specie di sistema operativo che di suo rende difficile avvicinarsi all'hardware Non ho ancora provato ma sono certo che una qualsiasi scheda/cpu compatibile col sistema programmazione arduino, e senza rtos di mezzo, dia risultati migliori in questo caso specifico Per quanto riguarda fpga e cpld le lascerei a chi ha compiti ben piu' complessi, a chi deve rispettare i nanosecondi, per 'parlare' con un plc va' piu' che bene andare a colpi di codice, semplicemente in questo caso il micro scelto non e' quello adatto a fare questo lavoro

Sempre ammesso che sta scrittura in seriale di 25 bit, sincrona col clock che arriva da fuori, non riesca a farla via hardware, usando una uart/i2c/spi o similare

E' vero, 15 us (ma tu hai rilevato tempi inferiori, mi pare) sono un mucchio di cicli di istruzione a 240 MHz. A proposito, non è che il massimo per il C3 sia 160 MHz? Almeno cosi' leggo qui:

formatting link
che non conosco il C3 che e' basato su RISC V, ma ad esempio il vecchio ESP32 sicuramente rischiava una importante latenza in caso di "cache miss", perche' la FLASH esterna QSPI veniva scaricata a banchi nella cache interna all'occorrenza e sicuramente questo poteva determinare latenze di parecchi us. Magari anche nel tuo caso succede qualcosa del genere.

Ciao,

Piu' che il tempo in se, comunque molto importante, e' la variabilita' del tempo impiegato per l'ingresso del codice isr Dal fronte di discesa del segnale di clock, alla partenza della routine dell'interrupt, passano 3-4 ma anche 8-10 microsecondi

Ed e' questa variabilita' che mi preoccupa ed alcune volte mi restituisce letture scorrette sul plc

Appena possibile recupero qualche schedina con cpu semplice e faccio dei test, sono convinto che la partenza codice routine interrupt sara' graniticamente legata al fronte di discesa del segnale di clock Probabilmente l'esp32 e' troppo gassato per fare ste robe qua, meglio una cpu liscia

Si, 15 MICRO secondi

La tua esperienza e' che ci mette il tempo che hai rilevato e che si attesta sui 15 microsecondi

Come dicevo, le cose diventano esponenzialmente piu' difficili quando si vuole arrivare cosi' vicini a certi limiti temporali. Inizi a dover fare a meno del sistema che ti gestisce due core, etc

Noi la FPGA la usavamo per rispettare compiti di 125us con un buon jitter, peace of mind

Io ho rilevato tempi ben inferiori su questa cpu, compresi tra i 2-3 ed i 8-10 usec per entrare nel codice dell'interrupt, che vista la velocita' del quarzo, mi sembrano tantini Quando parlavo di 'mia esperienza' intendevo le volte precedenti che ho usato un microcontrollore per fare queste cose, che non c'entra niente col problema/cpu descritto adesso

Veramente non mi pare di chiedere troppo da una cpu di questo calibro di tenere il 'qualche usec', mi pare solo di chiedere che faccia il suo mestiere, il problema ipotizzo stia nell'rtos di questa particolare cpu che impedisce di avere comportamenti ben determinati e prevedibili nel tempo Non avendo mai usato prima un'esp32, di questo stavo cercando conferma

Niente da obiettare, se avete scelto la strada dell'fpga vuol dire che anche usando quel dispositivo il problema vostro e' stato risolto Che e' diverso dal dire "qua serve una fpga" Io direi che nel mio caso e' sufficiente un qualsiasi microcontrollore, e pure scrauso, ma non un esp32, tutto qua

Non sono un esperto di esp32, ma probabilmente il problema principale è sicuramente il "sistema operativo" che ci gira sopra. Dalla risposta del link di prima si intuisce che durante le sue varie cose maschera gli interrupt per le sezioni critiche e poi toglie la maschera. Tutto poi dipende da quanto sono lunghe le sezioni critiche in cui gli interrupt restano mascherati.

Sicuramente avresti tempi certi e brevi se non ci fosse un task switch intorno a fare le sue attività

Join the Discussion

Have something to add? Share your thoughts — no account required.

Didn't find your answer?

Ask the community — no account required