Tips & Tricks - PIC

 

I/O senza glitch


Glitch.

Il termine glitch è usato per indicare un picco breve ed improvviso, inatteso, in una forma d'onda.
La presenza di impulsi inaspettati può essere causa di seri problemi negli apparati elettronici che impiegano contatori, latch, flip-flop, ecc.
Un glitch può dipendere anche da una non corretta azione durante il cambio di condizioni dell'uscita che comanda la linea del segnale.

Possono essere le stesse sequenze di istruzioni a produrre glitch.

La prima delle cause che generano un glitch la troviamo in una non corretta esecuzione dell'inizializzazione degli I/O del microcontroller.


Glitch al cambio di direzione di un I/O.

All'avvio, i pin dei PIC sono configurati come ingressi, il che si riflette con tutti i bit del registro di direzione TRIS uguali a 1.
Solitamente incontriamo la necessità di modificare la direzione, dato che alcuni pin serviranno come uscite per comandare dispositivi esterni.
Nella maggior parte degli esempi che troviamo nel WEB, la sequenza tipica delle istruzioni è questa:

  TRISA = 0            // all pin on PORTA=out
  PORTA = 0b11110000   // RA<7:4>=1, RA<3:0>=0

ma non è corretto, in quanto questo può generare glitch della durata di una ciclo istruzione. Vediamo perchè

Dopo il reset iniziale (POR) il registro TRIS è presettato a 1, ma i latch di uscita del port assumono un valore casuale. 

Prendiamo, ad esempio, il bit 7: al POR il suo latch contiene 1. Nel momento in cui portiamo la direzione da ingresso ad uscita, il latch si collega al buffer del pin, che assume un livello 1. 
Con la seconda istruzione, forziamo un valore nei latch; per il bit 7 è 1 e quindi non ci sono variazioni di stato.
Però, sempre come esempio, il latch del bit 2 al POR contiene pure 1. Come sopra, nel momento in cui portiamo la direzione da ingresso ad uscita, il latch si collega al buffer del pin, che assume un livello 1.
Ma la seconda istruzione porta il bit a 0: avremo il pin che, per la durata di un ciclo ha avuto un glitch alto.

il problema è subdolo in quanto la logica della sequenza di istruzioni è perfettamente corretta.

La presenza di questo impulso può essere del tutto indifferente per il dispositivo comandato dal pin, ma può anche non esserlo. In ogni caso, è del tutto inutile creare un impulso che, al minimo, aumenterà il rumore elettrico del circuito.

La soluzione è molto semplice: basta invertire la sequenza.

  PORTA = 0b11110000   // preset latch RA<7:4>=1, RA<3:0>=0
  TRISA = 0            // all pin on PORTA=out  

Prima carichiamo i latch con i valori desiderati, poi commutiamo la direzione come uscita: i valori caricati si presenteranno ai pin senza la generazione di impulsi indesiderati.
Ancor meglio se abbiamo a disposizione i registri LAT, come nei PIC18 e negli Enhanced Midrange:

  LATA = 0b11110000   // preset latch RA<7:4>=1, RA<3:0>=0
 
TRISA = 0           // all pin on PORTA=out   



Evitare glitch all'accensione.


In ogni caso va considerato con attenzione il fatto che, subito dopo il reset, i pin sono configurati come ingressi, quindi ad alta impedenza e non possono fornire corrente per comandare un carico. In effetti,il livello logico è indeterminato e questa è la condizione iniziale per qualsiasi pin.

Condizione che, all'arrivo della tensione di alimentazione, può protrarsi per un tempo sensibile che comprende la somma di vari tempi:
- l'uscita dal reset
- l'eventuale presenza del PowerOnTimer (PWRT)
- le istruzioni necessarie ad arrivare alla definizione dei livelli logiciai pin
tempo che, complessivamente, può arrivare oltre 100ms.

Molti oggetti collegati ai pin del PIC, come ad esempio LED, non risentono minimamente di questi problemi, ma altri dispositivi possono avere terminato il loro reset prima di quello del microcontroller è trovarsi le linee di ingresso a livelli indeterminati, dato che tutti gli I/O sono ancora configurati come ingressi (ad alta impedenza).
Ad esempio, comandi di motori o bobine, carichi e periferiche complesse, ecc. possono trovarsi in condizioni critiche se agli ingressi appaiono tensioni nell'area indeterminata tra i livelli logici ammessi.

Se quanto collegato al microcontroller richiede che, all'arrivo della tensione di alimentazione, ci siano livelli logici certi, si rende indispensabile una soluzione.

Anche qui la soluzione è semplice: basta collegare sulle linee di uscita del microcontroller dei pull-up o pull-down: fino a che il programma non ha preso il controllo delle uscite, il loro livello sarà determinato dalle resistenze esterne, che assicurano una situazione adeguata per la periferica collegata.

Attenzione: i weak pull-up integrati, in questa fase, NON possono essere utili in quanto NON sono abilitati fino a che questo non viene comandato dall'esecuzione del programma 

Una ulteriore possibilità è quella, dove possibile, di mantenere resettata la periferica fino a quando il programma del microcontroller ne ha preso il comando, ad esempio usando un pin del microcontroller stesso o un reset controller esterno che tenga bloccata la periferica fino a che il programma non ne ha preso il controllo.

.In ogni caso, è opportuno considerare le necessità dei dispositivi collegati ai pin del PIC e le loro esigenze ed operare sempre per eliminare possibili situazioni problematiche.


Commutare lo stato di un pin di IO senza produrre glitch

Spesso è necessario agire su un pin di IO variandone lo stato in funzione di una condizione di una altro registro o di un flag. Questo può essere una causa di glitch inaspettati.

Caso tipico è lo shift di un byte di dati su una linea sincrona (comando di shift register, periferiche seriali data+clock, ecc).

Una soluzione elegante prevede un preset del bit di destinazione e questo consente di risparmiare linee di codice:

; set IOpin equal to carry saving 1 cycle
    bcf      IOPin          ; preset IO pin low
    btfsc    STATUS, C      ; if carry 0, branch and no op
    bsf      IOPin          ; otherwise set IO pin

A fronte di una riduzione del tempo di esecuzione, si viene però a creare la possibilità di un glitch, ovvero di un impulso indesiderato di breve durata.
Vediamo quando può succedere questo.

Se STATUS,C = 0, la sequenza viene eseguita così:

; IOpin è a livello 1
; set IOpin equal to carry saving 1 cycle

1    bcf      IOPin          ; il pin viene presettato a 0
2    btfsc    STATUS, C      ; se C=0, salta la riga successiva
       bsf    IOPin          ; non eseguita
   istruzione successiva

Ovvero la riga 1 presetta il IOPin = 0, il branch viene eseguito e l' impostazione del pin non viene cambiata dal test. Nessun impulso indesiderato.

Ma se STATUS,C = 1, la sequenza viene eseguita così:

; IOpin è a livello 1
; set IOpin equal to carry saving 1 cycle

1    bcf      IOPin         
; il pin viene presettato a 0
2    btfsc    STATUS, C     
; se C=1, esegue la riga successiva
3    bsf      IOPin          ; IOpin viene riportato a 1
   istruzione successiva
  • Inizialmente IOPin = 1  
  • La riga 1 presetta IOPin = 0
  • Il branch non viene eseguito
  •  e l' impostazione del pin a 1 viene invertita dalla riga 3

Ecco generato un impulso indesiderato!
La sua durata è due cicli (btfsc non eseguito = 1 ciclo + 1 ciclo del  bsf seguente)  

Solamente se il branch viene eseguito il glitch non viene generato. 
E questo può renderlo "pseudo casuale" (la sequenza da origine al glitch solo se il test non è eseguito), mettendo a dura prova le capacità di debug dello sviluppatore.

Il fatto può non provocare conseguenze, ma in vari casi il rapido impulso sull' IO può essere accolto dalle periferiche collegate e dare origine a conseguenze inaspettate. Ad esempio, se si comanda il clock di uno shft register, di un contatore o di un flip flop o si scambiano dati seriali.

Anche qui, il problema è subdolo in quanto la logica della sequenza di istruzioni è perfettamente corretta e il programmatore non considera questa possibilità; quindi il caso è estremamente difficile da debuggare.
E' come detto prima, va anche considerato che la commutazione rapida di un I/O da origine a fenomeni di disturbo elettromagnetico e a consumo di energia, soprattutto se si applica ad un carico di potenza.

Per evitare questa situazione bisognerà ricorrere ad un ciclo a 4 istruzioni, che, a fronte di un codice di dimensione maggiore e quindi più lento, non produce alcun glitch in uscita

; Set IOpin equal to carry, but w/o glitch 
    btfsc    STATUS, C      ; branch if carry = 0
    bsf      IOPin          ; if not (carry = 1) set pin
    btfss    STATUS, C      ; branch if carry = 1
    bcf      IOPin          ; if not (carry = 0) clear pin

Con questo non sono eseguite commutazioni inutili perchè lo stato dell' IO viene cambiato solo in conseguenza a uno dei due  test: se prima dei test il pin era a 0 e il Carry è 0, il pin resterà a 0; sarà portato a 1 solamente se il Carry è a 1.

  1. Se il cambio di stato del bit non è diretto ad un IO, ma ad un altro registro interno, il problema del glitch non si pone, in quanto non ha alcun riflesso all'esterno del chip ed è allora preferibile la prima sequenza di istruzioni, perchè più breve.
     
  2. Quanto evidenziato non ha nulla a che fare con il problema dell' R-M-W: si tratta di una diversa questione.


Copyright © afg . Tutti i diritti riservati.
Aggiornato il 08/08/19 .