Tips & Tricks - PIC

 

I/O senza glitch

  • Commutare lo stato di un pin di IO senza produrre glitch
  • Note

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.

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 latchato 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.

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.
Va anche considerato che la commutazione rapida di un IO da origine a fenomeni di disturbo elettromagnetico e a consumo di energia.

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.


Note

  1. Va considerato che 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. Va compreso che 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 17/10/10 .