venerdì 13 dicembre 2013

Prossimamente..

A causa di impegni non ho potuto scrivere con la solita frequenza di sempre sul blog, ma non disperate, sarà presto online il nuovo articolo su ASF in cui vedremo nel dettaglio SPI e sul fronte FPGA.. novità in arrivo, tenetevi forte!

domenica 6 ottobre 2013

FPGA: Rilevazione di fronti

In passato la rilevazione dei fronti si è effettuata tramite codice VHDL come

code

In cui non veniva richiesto l’utilizzo di alcuna libreria ed il funzionamento abbastanza semplice era pensato per il tipo nativo di dato BIT.

La libreria IEEE.STD_LOGIC_1164 introduce assieme al tipo STD_LOGIC le funzionalità rising_edge e falling_edge così definite:

stdlogic2[4]

Cosa cambia nella pratica tra l’utilizzo delle nuove funzioni e il vecchio modo di rilevare fronti?

Purtroppo sulla rete sono spesso presenti imprecisioni o informazioni incomplete che non coprono tutta la possibile casistica di casi.

Per capirlo dobbiamo analizzare alcune funzioni, di particolare importanza per la comprensione del codice la funzione To_X01 sotto riportata:

x01

Questa funzione a sua volta si affida ad una “tabella” per effettuare una conversione dal tipo std_ulogic ai soli valori X, 0 ed 1.

table

Le funzioni rising_edge e falling_edge gestiscono quindi in modo diverso l’intera casistica dei 9 possibili valori assunti dal tipo std_logic.

Il fronte di salita sarà scatenato solamente quando il valore precedente convertito in X01 sarà 0, ovvero solamente durante le transizione dal valore logico 0 o L al valore 1 convertito in X01, quindi effettivamente al valore logico 1 o H. Analoghe considerazioni per il fronte di discesa.

Per chiarificare vediamo un semplice esempio:

code

Con la relativa simulazione

sim

In cui è possibile notare il differente comportamento nel passaggio dai vari stati logici al valore logico 1, mentre col vecchio codice si ha sempre (a parte giustamente nel passaggio da 1 a 1 in cui non c’è un fronte) un effettivo fronte di salita, con la funzione rising_edge non viene invece scatenato in alcuni casi per una migliore corrispondenza tra hardware sintetizzato e simulato.

Concludendo consiglio sempre di utilizzare le nuove funzioni rising_edge e falling_edge per i nuovi progetti.

martedì 24 settembre 2013

FPGA: Approfondiamo il confine tra il linguaggio VHDL e le librerie standardizzate

Chi inizia a studiare il VHDL spesso assume per parte intrinseca del linguaggio la libreria Std_Logic_1164 perché, magari senza pensarci troppo, ha sempre scritto così l’inizio dei propri file VHDL:

library

Lo scopo di questo articolo è fare chiarezza tra i confini del linguaggio e delle librerie, seppur standardizzate.

Lo standard IEEE 1164 definisce un package che definisce una rappresentazione dei valori logici nel linguaggio VHDL, tale package non fa però parte del linguaggio ma è una libreria standardizzata fornita da tutti i principali programmi di sintesi come Quartus o ISE Design Suite.

Il linguaggio definisce invece un package denominato standard, compilato dai programmi di sintesi nella libreria VHDL std ed inclusa automaticamente in tutti i file VHDL, non è quindi necessario “importare” tale libreria nei propri file.

In Quartus il package standard è accessibile tramite il file standard.vhd nel percorso C:\altera\13.0\quartus\libraries\vhdl\std e ne è sotto riportato uno stralcio

standard

E’ possibile notare come nel package vengano definiti alcuni tipi come boolean, bit, integer, etc.. ed altri come natural, positive, etc.. siano creati a partire da tipi creati precedentemente restringendone ad esempio il range di valori ammissibili.

E’ quindi possibile scrivere del codice senza utilizzare la libreria Std_Logic_1164 ma utilizzando semplicemente il tipo bit, previsto nativamente dal linguaggio VHDL come ad esempio

bit

E’ sempre consigliato utilizzare la libreria Std_Logic_1164, l’esempio serve però per capire meglio il confine tra sintassi intrinseca del linguaggio e le librerie.

Analizziamo adesso il sorgente della libreria Std_Logic_1164, accessibile tramite il file std_1164.vhd nel percorso C:\altera\13.0\quartus\libraries\vhdl\ieee

stdlogic1

Notiamo come vengano definiti ulteriori tipi come std_ulogic e std_logic (non mostrato, std_logic è un tipo “risolto” rispetto a std_ulogic, permette cioè di modellare logica con driver multipli, come i bus tristate) con la relativa implementazione, nel file sono presenti inoltre alcune funzioni non native del linguaggio come rising_edge e falling_edge di cui è possibile studiarne l’implementazione

stdlogic2

I codici dei file VHDL di package standardizzati ma non parte del linguaggio come numeric_std, math_real, etc.. sono presenti nella stessa cartella del file std_1164.vhd, hanno grande valore educativo seppur non siano consigliati come materiale di studio iniziale per imparare il linguaggio VHDL. Rappresenta una ricca fonte di documentazione e il loro esame permetterà di scoprire anche i dettagli più intimi del VHDL per padroneggiare al meglio il linguaggio.

giovedì 29 agosto 2013

FPGA: Verifica della memoria AL422B tramite SignalTap II Logic Analyzer

Precedentemente abbiamo parlato del chip di memoria AL422B, vediamo oggi come verificarne in prima battuta il corretto funzionamento tramite un design su logiche programmabili che simuli una scrittura di dati veloce ed una lettura più lenta dalla memoria FIFO.

Nel nostro design avremo diversi domini di clock tutti derivati dal clock principale generato dall’oscillatore a 50 MHz presente sulla scheda che confineremo in distinte entità per evitare problematiche assai poco piacevoli e suddividere in parti più piccole il tutto.

Possono infatti nascere problemi durante l’analisi e sintesi con processi sensibili contemporaneamente a più fronti di salita all’interno di macchine a stati (es. costrutto VHDL case).

schematic

Abbiamo già parlato dell’entità SyncReset in precedenti articoli, riassumendo brevemente serve per rendere sincrona la de-asserzione del segnale reset cercando così di evitare stati metastabili.

L’entità AL422B_Reader simula la lettura dei dati e gestisce il reset della scrittura dei dati implementando una semplice macchina a stati scandita dal clock rck a 0.25 MHz (simulando ad esempio la lettura da parte di un lento microcontrollore) generato a partire dal clock a 50 MHz.

state machine

Al reset la macchina a stati parte dallo stato wait_state in cui vengono attesi 0.1ms per inizializzare il chip AL422B come descritto nel relativo datasheet prima di passare allo stato reset_write_state in cui viene riavviata la scrittura da parte dell’entità AL422B_Writer. Dopodiché si passa allo stato reset_read_state in cui viene resettato l’indice di lettura interno alla memoria per iniziare nello stato process_state la lettura dalla prima locazione di memoria. Una volta letto il valore 192 (scelto arbitrariamente) la lettura è ultimata e si passa nuovamente allo stato reset_write_state.

Sotto riportato un estratto della macchina a stati AL422B_Reader (alla fine dell’articolo il progetto è interamente scaricabile):

fstate

In cui è possibile notare la gestire dei segnali REn, WEn, RRSTn, writer_reset. In particolare è da notare che al reset della lettura della memoria tramite RRSTn il segnale REn è portato al livello logico alto (lettura disabilitata), come consigliato dall’ultima versione del datasheet e dall’articolo precedente.

Passiamo all’entità AL422B_Writer così definita:

entity writer 

Analizziamo solamente il processo write_proc tralasciando la generazione del clock da 25 MHz ottenuta tramite un contatore. Il processo si occupa di scrivere sulla memoria FIFO tramite il bus ad 8 bit data_in i numeri progressivi da 0 a 192 per poi fermarsi fino alla riattivazione col segnale di reset che fa ripartire il conteggio.

writer_impl

La verifica del codice tramite la sola simulazione richiede l’emulazione del chip AL422B, eseguibile ad esempio tramite dei processi fifo_write e fifo_read come

testbench emulate

Che però andrebbero migliorati per imitare il perfetto comportamento del chip. Seguiamo in questo caso, anziché concentrarci sull’emulazione, una strada alternativa: utilizzeremo un analizzatori di stati logici per verificare a “runtime” il nostro progetto.

Quartus II include l’utilissimo tool SignalTap II Logic Analyzer (richiede l’attivazione del talkback, vedi precedente articolo per l’abilitazione) che permette di esaminare in tempo reale il comportamento dei segnali interni senza utilizzare pin aggiuntivi ma tramite l’interfaccia JTAG. Il circuito esterno composto dal chip AL422B con relativi condensatori bulk e di disaccoppiamento dovrà naturalmente essere collegato alla FPGA (con GND in comune) durante il debug con SignalTap.

diagram

Avremo quindi gratuitamente un analizzatori di stati logici virtuale con tanto di trigger, l’unico prezzo da pagare sarà in termini di risorse (LEs e memoria) sulla FPGA in quanto verrà caricato assieme al nostro design. Le risorse utilizzate dipenderanno dal numero di funzionalità e di campioni da memorizzare

Creiamo innanzitutto un nuovo file SignalTap tramite il menù File / New scegliendo SignalTap II Logic Analyzer File

new

Apparirà l’interfaccia grafica del programma

signaltap

Come prima cosa tramite il pulsante Setup scegliamo il nostro programmatore JTAG, dopodiché indichiamo tramite il pulsante sfoglia (i puntini ) sulla destra nella finestra Signal Configuration il segnale di clock che servirà a SignalTap per campionare gli altri segnali. Assicuriamoci che sia il segnale a frequenza maggiore per evitare la perdita di eventi, l’analisi delle tempistiche di Quartus riporterà la frequenza massima campionabile.

L’analizzatore logico campionerà i dati ad ogni fronte di salita, Altera raccomanda l’utilizzo di un segnale globale non gated di clock sincrono ai segnali da acquisire.

Premuto il pulsante sfoglia apparirà una finestra Node Finder che permetterà di scegliere un nodo dal nostro design. Scegliamo pre-synthesis nelle opzioni per visualizzare i nomi prima della sintesi e portiamo il pin clock nei nodi selezionati tramite un doppio click o selezionandolo e premendo il pulsante >.

node_finder

I segnali pre-sintesi elencati esistono dopo l’elaborazione del design ma prima di ogni ottimizzazione di sintesi, se non si sta utilizzando la compilazione incrementale aggiungere solamente questa tipologia di segnali.

Sempre nella finestra Signal Configuration è possibile scegliere il numero di campioni da visualizzare al trigger impostando Sample depth, nell’Instance Manager in alto apparirà il corrispondente utilizzo di risorse e sarà possibile capire se il nostro dispositivo sarà in grado di contenere l’analizzatore con le impostazioni scelte risparmiandoci così eventualmente una compilazione con esito negativo.

signaltap_2

Nell’immagine sopra la FPGA utilizzata dispone solamente di 26 blocchi di memoria di medie dimensioni, coi nodi selezionati da monitorare ed una profondità di 2K campioni (altre impostazioni di default) verranno utilizzati 15 blocchi (circa 56k bits) ed 828 LEs.

Nell’area centrale della finestra (nella scheda Setup) è possibile aggiungere tramite doppio-click i nodi da visualizzare e configurare eventuali trigger. Scegliendo Basic AND il trigger verrà valutato se tutte le condizioni impostate saranno verificate mentre scegliendo Basic OR basterà una sola delle condizioni per scatenare il trigger. Sono disponibili inoltre opzioni avanzati di Trigger che non vedremo in questo articolo.

Prima di iniziare il monitoraggio sarà necessario ricompilare il progetto e caricare nuovamente sulla FPGA il nostro design dopodiché tramite il pulsante Run Analysis (cerchiato in rosso nell’immagine seguente) al verificarsi di trigger sarà possibile visionare i nodi monitorati.

instance manager

Impostando ad esempio un trigger su data_in 5 allo scatenarsi dell’evento nella scheda data sarà visionabile l’andamento dei segnali

signaltap_3

Il programma permette di impostare la visualizzazione di bus di segnali con codifiche predefinite (es. unsigned decimal, Hexadecimal, etc..) o tramite tabelle mnemoniche (utile per visualizzare gli stati) e contiene altre funzioni che lasciamo scoprire al lettore.

Analizziamo adesso tramite questo potente strumento il nostro design:

1.reset pressed_2

Alla pressione del pulsante di reset lo stato iniziale passa a wait sul fronte di salita di rck

3.wait-reset_write_2

Lo stato dopo 0.1ms passa a reset_write, il puntatore di scrittura della memoria viene azzerato tramite writer_reset che nell’entità AL422B_Writer porta wrstn al livello logico basso per attivare il reset (in questo caso già al livello basso). La scrittura viene abilitata e finito il reset potrà iniziare.

4.reset_write-read_2

Al fronte di rck successivo lo stato passa a reset_read per l’azzeramento del puntatore di lettura della memoria tramite il segnale rrstn. Il segnale wrstn sincronizzato col dominio di clock wck viene portato al livello logico alto tramite il segnale writer_reset, sincronizzato col dominio di clock rck. Inizia la scrittura progressiva dei numeri nella memoria tramite il bus data_in. Il primo fronte di salite wck dopo il reset non comporta la memorizzazione del numero, il numero 0 non sarà quindi scritto in memoria (vedi datasheet AL422-15 Write Cycle Timing)

7.full_2

Al fronte di rck successivo lo stato passa a process, il segnale rrstn di reset di lettura della memoria viene disabilitato ed inizia la lettura della memoria dopo il ciclo disabilitato (vedi datasheet AL422-14 Read Cycle Timing). In data_out è possibile vedere i dati correttamente letti dalla memoria che iniziano dal valore 1 e progrediscono fino al valore 192 dopodiché la macchina a stati passa a reset_write

8.full

Nello stato reset_write il bus data_out assume il valore 193 in quanto la disabilitazione della lettura tramite il segnale ren ha effetto dal ciclo successivo (vedi datasheet AL422-14 Read Cycle Timing). Come visto dal diagramma di stato lo stato passa poi nuovamente a reset_read e a process ripetendo la scrittura / lettura della memoria

Dopo un’ispezione manuale è possibile constare che in prima approssimazione il chip AL422B funziona correttamente e sarà possibile utilizzarlo con maggiore sicurezza anche con microcontrollori lenti senza scomodare facilmente un analizzatore di stati logici reale.

Scarica il progetto analizzato nell’articolo

Nota: Il progetto scaricabile utilizza la scheda di sviluppo EP2C5 Mini Board, cambiare il dispositivo ed i pin con le impostazioni della scheda di sviluppo utilizzata

lunedì 12 agosto 2013

Introduzione ad ASF (sesta parte) – USB

Indice degli articoli su ASF

Microcontrollori come AVR UC3 ed XMega hanno in alcuni modelli un modulo hardware per la comunicazione USB, la scrittura del software per gestire il protocollo non è però banale e molto articolata, la libreria ASF ci viene in aiuto tramite uno stack USB che può risparmiarci molti mesi di lavoro permettendo di focalizzarsi su cosa rende unica la nostra applicazione.

xmega_usb

Non analizziamo in questo articolo nel dettaglio tutto lo stack USB che offre molteplici possibilità ma vediamo in modo semplice come sostituire la vecchia comunicazione seriale con la più moderna USB presente su tutti i dispositivi di ultima generazione.

Utilizzeremo la classe USB CDC (Communication Devices Class), non una classe del mondo della programmazione ad oggetti ma un insieme di specifiche a cui attenerci che ci esonera dallo scrivere uno specifico driver per l’Host USB (il sistema operativo lato pc ad esempio) in quanto già presente per generici dispositivi USB CDC ed utilizzabile sotto Windows con un semplice file .inf. La comunicazione verrà semplicemente vista come una porta seriale virtuale utilizzabile con semplicità da un software sul sistema operativo.

Esistono anche altre classi USB ed è possibile crearne personalizzate, sotto una tabella riassuntiva (non completa) per rendere meglio l’idea di cosa possono offrire alcune classi USB ed alcuni vantaggi/svantaggi.

usb_class

Lo stack USB di Atmel è composto da tre moduli: UDC, UDI ed UDD

usb_stack

UDC (USB Device Controller) fornisce un’astrazione di alto livello del dispositivo USB, presenta metodi come udc_start(), udc_stop() per avviare e fermare lo stack USB, udc_attach(void), udc_detach() per collegare il dispositivo al bus quando la tensione è idonea e scollegarlo dal bus rimuovendo le resistenze interne di pull-up sulle linee D- e D+.

UDI (USB Device Interface) il modulo è distinto per ogni classe di dispositivo che si vuole utilizzare, utilizzeremo UDI for CDC che offre metodi per controllare la linea seriale virtuale e gestire il trasferimento dati

UDD (USB Device Driver) fornisce un’astrazione di basso livello del dispositivo USB, gestisce eventi provenienti dall’hardware come interruzioni chiamando a sua volta funzioni dei moduli UDC e UDI, non utilizzeremo direttamente questo modulo.

Il funzionamento dello stack USB si basa sulle interruzioni, questa soluzione garantisce bassa latenza e non richiede cicli di attesa, bisogna porre però particolare attenzione. Le interruzioni USB hanno bassa priorità e possono essere bloccate da interruzioni con priorità maggiore o sezioni critiche di codice.

Le specifiche USB impongono un tempo massimo di 2ms per assegnare l’indirizzo USB, procedura di basso livello che si svolge durante l’enumerazione, al collegamento del dispositivo.

Gli host USB usano poi un timeout, non previsto dalle specifiche USB, per rilevare e resettare un dispositivo che non risponde ai messaggi di controllo, sotto una tabella di esempio dei tempi di timeout

timeout
CBW: Command Block Wrapper, ZLP: Zero Lenght Packet, CSW: Command Status Wrapper

Tralasciando le varie sigle che si riferiscono a meccanismi di basso livello del protocollo USB di cui non parleremo in questo articolo, è possibile notare che per avere compatibilità con i principali sistemi operativi la MCU deve rispondere entro 5 secondi a delle richieste particolari ricevute tramite USB.

L’utilizzo delle funzionalità di Debug (es. Debug con AVR Dragon) può interferire con il funzionamento del modulo hardware USB del microcontrollore, con la modalità USB OCD break mode disabilitata eventuali breakpoint saranno immediatamente soddisfatti ma il comportamento USB sarà imprevedibile mentre con la modalità abilitata le transazioni USB verranno completate prima di fermare l’esecuzione del programma e il micro non accetterà ulteriori transazioni e risponderà con un messaggio NACK ad eventuali richieste dell’host.

Nota: Seppur non specificato nel datasheet o nel manuale del programmatore la modalità USB OCD break mode è automaticamente configurata dal debugger e non richiede intervento manuale. Fonte: supporto tecnico Atmel

Le funzioni più interessanti sono nel modulo UDI con singola interfaccia CDC, sotto riportate per comodità:

udi_cdc

Aggiungiamo prima di tutto al nostro progetto HelloASF creato negli articoli precedenti il modulo USB Device tramite il menù ASF / ASF Wizard come visto negli articoli precedenti per gli altri moduli, scegliamo la variante cdc_stdio dal menù a discesa come mostrato in figura e premiamo Apply 

asf_module

cdc_stdio fornisce al nostro progetto un’interfaccia Standard I/O (stdio) che implementa dietro le quinte la classe USB CDC permettendo così di utilizzare metodi come printf(), scanf(), getc(), puts(), etc.. le funzioni del modulo UDI for CDC rimangono però estremamente utili per inviare e ricevere byte o per attendere la ricezione di dati dall’host USB.

Verrà automaticamente aggiunto al nostro progetto tutto quello che serve per utilizzare l’USB con la classe CDC tramite stdio, notiamo dall’ASF Explorer l’aggiunta dei vari moduli dello stack USB.

asf_explorer

La prima operazione sarà adesso impostare il clock del modulo USB, nel file conf_clock.h eliminiamo i commenti ai #define relativi al clock usb come nell’immagine seguente

usb_clk

Per il modulo USB verrà quindi utilizzato l’oscillatore RC interno da 32 MHz con la calibrazione di fabbrica a 48 MHz, non sarà però utilizzabile direttamente per la CPU se perlomeno si vuole rimanere entro le specifiche raccomandate (32 MHz) ed evitare l’overclock della CPU.

Una possibilità è utilizzare i prescaler per ridurre la frequenze di clock a 24 MHz, è però anche possibile utilizzare un oscillatore esterno o l’oscillatore RC interno da 2 MHz e tramite il PLL moltiplicare per 16 la frequenza ed ottenere così 32 MHz, seguiremo quest’ultima strada:

clock_pll

Il file conf_usb.h contiene le impostazioni di configurazione per l’USB CDC, è obbligatorio modificarne il Vendor ID con un identificativo rilasciato dietro pagamento dal consorzio USB per applicazioni commerciali.

Per utilizzare stdio_usb è necessario impostare alcuni #define a funzioni del modulo stdio_usb come mostrato di seguito

USB_conf

Da notare l’ #include finale al file <stdio_usb.h> per poter risolvere correttamente le funzioni aggiunte.

Dal file è possibile specificare tramite USB_DEVICE_ATTR se l’alimentazione è prelevata dal bus USB oppure no ed un eventuale risveglio remoto del dispositivo.

Nota per i dispositivi alimentati indipendentemente dal bus USB: E’ necessario un modo per rilevare lo stato della connessione USB, la scheda EWS utilizzata come è possibile vedere dallo schema sul pin PA7 presenta un divisore di tensione 1:3 per questo scopo, 5v saranno rilevati circa come 1,67 e sarà possibile misurarli senza problemi tramite l’ADC per esempio. Sarà poi necessario modificare la funzione stdio_usb_init() nel file stdio_usb.c mostrata di seguito

stdio_usb_init

Sostituendo il valore true del parametro di stdio_usb_vbus_event() con l’effettivo valore del bus USB.

Alimentando continuamente da bus USB il micro questa operazione non sarà però necessaria.

Le impostazioni di comunicazione infine permettono di impostare il data rate e gli altri parametri tipici di una comunicazione seriale che devono coincidere col programma sull’host usb.

Modifichiamo adesso il file main.c col seguente codice

main_code

Dopo l’inizializzazione del servizio sysclk notiamo che vengono abilitati gli interrupts, passaggio fondamentale dato che tutto lo stack USB si basa su essi per il funzionamento.

Con l’istruzione stdio_usb_init() inizializziamo il modulo ASF stdio_usb che si occuperò di avviare lo stack USB ed impostare stdin ed stdout all’implementazione USB CDC.

All’interno del ciclo while è stata utilizzata semplicemente l’istruzione printf() per inviare tramite USB una stringa di testo alla porta seriale virtuale.

Il micro è pronto, non rimane adesso che modificare il file .inf che il Wizard ha aggiunto al progetto con le informazioni corrette sul nostro dispositivo (VID, PID) e che dovremo indicare a Windows per l’installazione del driver. Nel progetto allegato, scaricabile alla fine dell’articolo è possibile trovare un esempio di come modificare il file.

Nell’immagine seguente il terminale PuTTY collegato al micro XMega.

terminale

Anche per oggi è tutto, la libreria ASF permette di nascondere le complessità dietro al protocollo USB e ci fornisce strumenti semplici da utilizzare per concentrarci sulla nostra applicazione e scambiare senza problemi dati ad esempio tra micro e pc. Spesso il supporto USB è un fattore rilevante e permette di abbattere il BOM (Bill of Materials) evitando l’utilizzo di un IC dedicato.

Scarica il progetto dell’articolo

venerdì 26 luglio 2013

FPGA: Approfondiamo la Metastabilità

Abbiamo visto nel precedente articolo cos’è la metastabilità e come minimizzare la sua propagazione tramite una catena di registri di sincronizzazione sotto riportata per comodità di lettura:

sync_reset[4]

I flip-flop realizzano la asserzione asincrona / de-asserzione sincrona.

Un eventuale reset asincrono che viola i tempi di recovery e removal potrà però causare metastabilità nel primo flip-flop provocandone l’uscita q0 ad un valore intermedio tra 1 o 0 e assestandosi poi ad un valore logico casuale.

Se l’ingresso asincrono (il segnale reset) rimane però stabile, al successivo fronte di salita del clock q0 assumerà il valore dell’ingresso e al periodo di clock successivo sarà propagato all’uscita sync_reset.

metastability

Se la metastabilità non si risolve prima del fronte di clock successivo potrebbe propagarsi nel secondo flip-flop (quindi all’uscita), la probabilità è però minore tanto minore è la frequenza del clock.

La soluzione circuitale è pertanto valida se il segnale asincrono è sovra-campionato dai flip-flop prima di una sua variazione ed è ammissibile un ritardo nel segnale di uscita non costante.

Ipotizzando un ingresso che non causi metastabilità per semplicità il segnale di uscita (sync_reset) avrà un ritardo di 2 periodi di clock per passare da 0 a 1 mentre solamente un ritardo legato al tempo di reset asincrono del flip-flop nel passare da 1 a 0. Per questo si dice che realizzano la asserzione asincrona / de-asserzione sincrona.

syncreset

E’ da notare dalla simulazione che se il segnale reset sarà indeterminato l’uscita assumerà il valore 1 logico sempre dopo 2 periodi di clock.

Il sovra-campionamento è necessario in quanto se il segnale reset cambiasse prima del fronte di clock successivo e tornasse quindi a 0 e la metastabilità si risolvesse con il solito valore (valore precedente), il valore del segnale reset non sarebbe mai presentato in uscita.

metastability err

Il circuito visto non è quindi sempre applicabile in qualunque situazione ed è di fondamentale importanza la stabilità del valore di ingresso rispetto al periodo del clock, è però adatto per gestire l’ingresso proveniente da un segnale di reset filtrato preventivamente da anti-rimbalzo (debounced) come sulla scheda DE0-Nano.

La probabilità di propagazione ai successivi flip-flop e quindi all’uscita della metastabilità è calcolabili in termini di MTBF (Mean Time Between Failures), tempo medio tra guasti dovuti alla metastabilità, che Quartus ci permette di calcolare agevolmente.

La formula utilizzata è la seguente:

mtbf

con C1 e C2 costanti dipendenti dal dispositivo (es. processo produttivo) e dalle operazioni operative (es. temperatura), fCLK è la frequenza del clock utilizzato per ricevere il segnale asincrono, fDATA la frequenza del segnale asincrono in ingresso. tMET è il tempo a disposizione del segnale per risolvere la metastabilità.

La formula ci indica che possiamo esponenzialmente migliorare la situazione aumentando il tMET e linearmente riducendo fCLK o fDATA.

Specifichiamo tramite un file SDC (mostrato sotto) la frequenza del nostro clock (fCLK nella formula)

sdc

Abilitiamo l’analisi della metastabilità tramite il menù  Assignments / Settings ed impostando Synchronizer identification a Forced If Asynchronous, di default Quartus è abbastanza conservativo e l’identificazione è disattivata

setting

Apriamo adesso Assignments / Assignment Editor ed impostiamo per l’analisi l’analogo di fDATA nella formula, ovvero la frequenza del segnale di ingresso. Aggiungiamo una nuova voce scegliendo To *, Assignment Name Synchronizer Toggle Rate ed impostiamola a 50 milioni per simulare un ingresso commutante a 50 MHz. Questo valore può risultare eccessivo per un segnale di reset ma ci porrà sul lato sicuro e permetterà di mostrare le differenze di MTFB altrimenti non percettibili.

assign

Avviamo adesso una compilazione completa del design ed apriamo il Metastability Report sotto la cartella TimeQuest Timing Analyzer del report della compilazione.

report

Notiamo che con un clock di 50 MHz il MTBF tipico stimato è di oltre 1 miliardo di anni, un risultato niente male.

report50

Il tMET si può leggere dalla quarta riga è di 19.246 ns, molto elevato e comporta robustezza al nostro design.

Aumentando il clock a 400 MHz e ricompilando il MTBF si riduce notevolmente a 28.3 anni, la nuova constraints con le impostazioni di default del fitter non è soddisfabile è genera dei Warning Timing requirements not met durante la compilazione, il tutto comporterà fragilità nel design

report400

Il tempo di assestamento disponibile in questo caso notiamo essere di 1.439 ns, molto inferiore al caso precedente.

E’ possibile notare come modificando i parametri del progetto per una sintesi più aggressiva ed utilizzando Design Space Explorer di cui abbiamo parlato in un articolo precedente, ci si avvicini maggiormente a soddisfare la frequenza di 400 MHz (ancora senza soddisfarla in questo caso) ed il MTBF cambi sensibilmente passando a 39.700 anni, una variazione di soli 0.305 ns pari a circa il 21% del valore precedente nell’ Avaible Settling Time comporta dunque una situazione molto diversa come era intuibile dalla formula dell’MTBF.

report400better

Altera consiglia di utilizzare un minimo di tre flip-flop per sincronizzare segnali asincroni proprio perché il tempo di assestamento è uno strumento fondamentale per evitare la metastabilità.