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
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 }