domenica 7 maggio 2017

FPGA: Computer Vision con D8M-GPIO (prima parte)

Un campo promettente per le FPGA è sicuramente l’elaborazione di flussi video in tempo reale (anche detta elaborazione di immagini). Sebbene le schede grafiche diventino sempre più potenti sotto molti punti di vista, pensiamo a settori come l’automotive dove tematiche come la guida automatica o sistemi Advanced Driver Assistance Systems (ADAS) sono sempre di maggiore attualità. I requisiti sono bassi consumi energetici, elaborazione in tempo reale e riprogrammabilità; in scenari come questo l’utilizzo delle logiche programmabili comporta, sopratutto riguardo ai consumi, grandi vantaggi.

Il primo passo di qualsiasi sistema di visione è l’acquisizione dell’immagine da elaborare, vediamo come è possibile compiere questo passo con la scheda FPGA DE0-Nano ed il modulo Digital Camera D8M-GPIO di Terasic, evoluzione per certi versi del modulo D5M. Nell’immagine seguente è mostrato a sinistra il modulo collegato alla scheda ed a destra la vista frontale del modulo.

de0-nano d8m              de0-nano d8m

Abbiamo già parlato della DE0-Nano in diverse occasioni, vediamo adesso cosa ci offre il D8M.

Architettura

d8m architectureSostanzialmente ci fornisce un sensore CMOS OV8865 da 8 Megapixel prodotto da Omnivision assieme ad una lente con focus regolabile e tutta la circuiteria necessaria per dialogare facilmente con questi elementi.

Facendo un rapido calcolo, la quantità di dati generata da un sensore d’immagine a 30 fps e piena risoluzione (8 MP) è di: 3264 x 2448 pixel x 30 fps x 10 bit / pixel = 2.397.081.600 bit/s = 2,23 Gbps a cui si aggiungono in realtà altri dati per la sincronizzazione (overhead LVDS, segnali HSYNC, VSYNC, etc...). E’ facilmente intuibile come problematiche di integrità dei segnali non siano da porre in secondo piano.

Il sensore CMOS vista la grande quantità di dati che genera, comunica tramite 4 linee con standard elettrico LVDS (Low-voltage differential signaling) ad alta velocità, ogni linea infatti può trasferire fino a 1.2 Gbps. Il sensore supporta inoltre lo standard MIPI CSI-2 che indica come interpretare in dati i segnali elettrici.

Per semplificare il collegamento con la FPGA il modulo converte i segnali LVDS in segnali paralleli tramite un integrato TC358748XBG di Toshiba, visibile al centro della scheda. Il convertitore supporta un uscita parallela con frequenza fino a 100 MHz e una certa flessibilità, necessita però dell’appropriata programmazione.

E’ di lato mostrata l’architettura del modulo D8M dove è anche possibile osservare che sia il convertitore sia il sensore CMOS dispongono di un’interfaccia di controllo I2C.

 

 

 

Sistema di messa a fuoco

Non è evidenziato nello schema precedente ma l’interfaccia I2C è utilizzata anche per controllare tramite l’integrato VM149C un piccolo motore VCM (Voice Coil Motor) che serve a regolare la messa a fuoco spostando la posizione della lente e quindi la distanza di quest’ultima dal sensore.

Curiosità: Il nome Voice Coil Motor proviene dalle sue prime applicazioni, la vibrazione del cono di carta degli altoparlanti.

Questo tipo di motore è molto semplice e la lo spostamento generato è proporzionale al flusso di corrente che attraversa la bobina del motore, per questo l’integrato è un driver a corrente costante. L’accuratezza nel posizionamento di questo tipo di motori può essere molto elevata, anche inferiore al micron. E’ di seguito riportato lo schema di funzionamento del VM149C:

VCM architecture

Analizzando “in linea” le immagini ottenute è possibile creare un sistema di messa a fuoco automatica, nei reference design di Terasic è possibile trovare un esempio di semplice autofocus scritto in Verilog, anche se purtroppo non è documentato molto bene.

Sistema ottico

Per quanto riguarda la lente, elemento spesso sottovalutato ma molto importante in un sistema di acquisizione immagini, le caratteristiche principali riportate sono:

Lens Type 1/4 inch   1/3.2 inch
Effective Focal Lenght (EFL) 3.37 mm
F-number 2.8
Distorsion < 1%
Lens Module Dimensions 8.5 x 8.5 x 5.4 mm

Essendo il sensore CMOS da 1/3.2 di pollice la lente risulta il collo di bottiglia del sistema per ottenere immagini di qualità superiore, è comunque una qualità accettabile in svariate applicazioni.

UPDATE: Dopo aver segnalato il problema al produttore è stato corretto il datasheet cambiando il tipo di lente da 1/4 di pollice a 1/3.2 pollici. Kailaptech ha motivato il cambiamento di specifiche come errore di battitura.

Dato che: F-number = Focal Lenght / Aperture Diameter abbiamo 2.8 = 3.37 / Aperture Diameter da cui ricaviamo un diametro di apertura di 1.2 mm che corrisponde effettivamente alla dimensione dell’apertura fisica della lente.

La profondità di campo (Depth of View) risulta limitata essendo proporzionale all’F-number, le immagini saranno però più luminose rispetto ad F-number maggiori in quanto la quantità di luce entrante sarà maggiore.

aperture dof lens

La lunghezza focale (Focal Lenght) molto ridotta permette un angolo di campo (o Angle of View) molto elevato, la lente abbinata al sensore OV8865 permette una visuale di circa 70° da datasheet. Il perché è facilmente intuibile dal seguente schema:

focal lenght lens

La lente ed il sensore sono in realtà a loro volta un modulo con identificativo JAL-OV8865-A898B con tanto di connettore, è quindi possibile sostituire questo modulo in caso di necessità, fermo restando che il nuovo modulo dovrà essere per forza di cosa pin-to-pin compatibile.

Sensore CMOS

Il sensore OV8865 è, come tutti i sensori moderni, un oggetto relativamente complesso, vediamo alcune delle caratteristiche principali:

Active array size 3264 x 2448
Lens Size 1/3.2 inch
Pixel Size 1.4 um x 1.4 um
Output format 10-bit RAW (BG/GR Bayer pattern)
Sensitivity 940 mV/Lux-sec
Dynamic Range 68.8 dB
Scan mode Progressive (Electronic Rolling Shutter)

La risoluzione è un parametro abbastanza intuitivo, è il numero di pixel attivi che possiamo ottenere, in questo caso 8 MegaPixel. In realtà il sensore presenta anche dei pixel otticamente isolati che leggeranno quindi sempre il valore corrispondente al valore nero. Questo in poche parole serve per determinare l’eventuale rumore a cui sono soggetti i pixel e rimuoverlo dai pixel attivi.

La dimensione del sensore, in questo caso 1/3.2 pollici, influenza direttamente la dimensione e quindi la capacità di raccogliere la luce dei pixel. Non è chiaramente comparabile con sensori full-frame di macchine reflex ma è comunque già una dimensione utilizzata su sensori di smartphone di fascia alta.

Il sensore utilizza il pattern di Bayer, ovvero davanti ad ogni pixel è presente un filtro ottico per far passare solamente la luce di un determinato colore secondo uno schema che alterna linee con sequenze di Blu/Verde a righe con sequenze Verde/Rosso.

d8m bayer

L’immagine originale prima della demosaicizzazione è quindi un’immagine dove la posizione di ogni pixel e la luminosità ne determinano il colore. Essendo i pixel verdi doppi rispetto ai pixel rossi e blu le immagini RAW risultano di tonalità molto verde. Ogni pixel è rappresentato da 10 bit corrispondenti alla luminosità, il colore nell’immagine finale viene stimato grazie ad un algoritmo di demosaicizzazione che può consistere in una semplice interpolazione lineare per applicazioni a basse prestazioni oppure in algoritmi molto sofisticati per risultati migliori.

raw image false color raw image demosaicized

Esempio di immagine RAW in falsi colori

Stessa immagine RAW demosaicizzata linearmente

Nel caso in cui il colore non sia richiesto è possibile ottenere una maggiore sensitività utilizzando sensori in bianco e nero senza quindi il filtro di bayer che introduce, seppur minimamente, una perdita di luminosità. In alternativa è spesso necessario scegliere un sensore di dimensioni maggiori se non è possibile modificare l’illuminazione o il sistema ottico.

Continuando nell’analisi delle caratteristiche è possibile notare una gamma dinamica di 68.8 dB, simile ai sensori degli smartphone di qualche anno fa e non comparabile coi sensori più avanzati HDR (High Dynamic Range) attuali che possono raggiungere 90 dB. Ad ogni modo è capace di cogliere buone immagini in condizioni di illuminazione adeguata.

La scansione dell’immagine avviene riga per riga, l’immagine non è quindi letta tutta contemporaneamente e in caso di movimenti molto veloci può sussistere un artefatto del movimento. Questa modalità è chiamata Electronic Rolling Shutter, è elettronica in quanto non è presente un otturatore meccanico e si differenzia dal Global Shutter per la sua lettura progressiva.

Vedremo più avanti altre caratteristiche e funzionalità offerte da questo sensore, così come interfacciarlo nella pratica alla FPGA.

Per concludere questa panoramica vi lascio un immagine del software che sarà disponibile prossimamente sul mio GitHub per gestire il modulo D8M collegato alla DE0-Nano dal PC tramite JTAG. Il programma, assieme al design FPGA, sarà disponibile anche per altre schede di sviluppo come la BeMicro CV A9 e la DE1-SoC e permetterà di provare numerose impostazioni del sensore in modo semplice e veloce senza richiedere il collegamento ad uno schermo esterno VGA o HDMI, interfacce non disponibili tra l’altro su tutte le schede di sviluppo.

fpga d8m image software

Alla prossima.

UPDATE: Ecco alcune foto di una Dahlia a risoluzione 1600x900 (1.4 MP) scattate con la D8M ed il progetto di cui parleremo prossimamente nel blog, la curva del blu è stata leggermente corretta con Gimp per rendere maggiormente acceso il giallo ed una foto è stata leggermente ritagliata. Facendo click sulle foto è possibile vederle a piena risoluzione.

fpga d8m dahlia image 

fpga d8m dahlia image

sabato 20 agosto 2016

FPGA: Comunicazione tramite JTAG UART con C#

Le schede di sviluppo come la DE1-SOC così come le più compatte DE0-Nano o BEMICRO-CV-A9 non dispongono di un’interfaccia di comunicazione semplice ed interoperabile verso un computer per i propri progetti.

La soluzione più diffusa è l’aggiunta di un modulo USB-Seriale esterno, il che comporta però degli svantaggi quali: costi aggiuntivi, ulteriori dimensioni del sistema finale e utilizzo dei pin di I/O, non sempre disponibili agevolmente su schede di fascia elevata.

usb-uart-moduleEsempio di modulo USB-Seriale a basso costo

Nel caso in cui i propri design non utilizzino bus AXI o Avalon è però senza ombra di dubbio la scelta più semplice per il collegamento a dispositivi host USB come computer (classici o raspberry, etc..).

E’ però già disponibile nella quasi totalità delle schede di sviluppo, una porta USB per la programmazione, collegata ad un circuito USB-Blaster o equivalente di cui il componente principale è generalmente una CPLD collegata tramite interfaccia JTAG alla FPGA.

L’utilizzo della porta nei propri design su FPGA necessità però di IP dedicati come l’Altera Virtual JTAG di non semplice utilizzo e di programmi server lato computer come quartus_stp.exe. Per chi fosse interessato ad ogni modo ad intraprendere questa strada (su dispositivi Altera) ecco un buon tutorial.

E’ possibile utilizzare IP come l’Altera Avalon Jtag Uart per nascondere la complessità del protocollo sottostante. Se utilizzato assieme a soft-core come NIOS II è possibile nascondere anche i dettagli di comunicazione grazie ai driver inclusi nell’IP e disporre di un interfaccia stream standard STDIN, STDOUT per una programmazione molto semplice lato firmware.

Lato computer però la situazione è ancora abbastanza complicata in quanto è necessario utilizzare il programma nios2-terminal in modalità standalone o tramite la versione di Eclipse dedicata inclusa negli strumenti di sviluppo di Altera, il che però presuppone l’installazione di tutto il pacchetto EDA di svariati GB.

nios-ii-terminal
Programma nios2-terminal

eclipse-terminal
Finestra Nios II Console all’interno di Eclipse personalizzato per NIOS II

Lato computer è invece spesso necessaria un interfaccia API utilizzabile tramite qualsiasi linguaggio di programmazione, per poter automatizzare nel modo più comodo la comunicazione.

Altera non rende disponibile una documentazione ufficiale, ma tramite la libreria jtag_atlantic fornita con Quartus, la stessa utilizzata internamente da nios2-terminal, è possibile gestire la comunicazione. La libreria jtag_atlantic utilizza a sua volta la libreria jtag_client, che sarà quindi necessario avere anch’essa (sempre inclusa con Quartus).

Il progetto non ufficiale https://github.com/thotypous/alterajtaguart offre gli header della API e degli esempi per poter utilizzare jtag_atlantic tramite C/C++.

Per i linguaggi .NET come il C#, molto utili per la prototipazione rapida di software, non esiste purtroppo una libreria pronta all’utilizzo. Per ovviare al problema ho quindi scritto una libreria che risolvesse il problema. Oltre ad offrire gli header C# delle API eleva il livello di programmazione offrendo una classe di semplice utilizzo che incapsula al contempo tutte le funzionalità.

Vediamone rapidamente la struttura. La classe principale con cui interfacciarsi è chiamata JtagUart, il cui diagramma è sotto mostrato:

ClassDiagram1

Dispone di metodi intuitivi come Open, Read, Write e Close per gestire la comunicazione ed implementa il pattern Dispose per chiudere automaticamente la connessione dopo l’utilizzo. La classe presenta inoltre alcuni metodi per semplificare la lettura di stringhe, per leggere e scrivere singoli byte e per recuperare informazioni sulla connessione. E’ ben documentata nel possibile, visto che comunque la libreria jtag_atlantic non è ufficialmente documentata.

NB: Nel caso la propria applicazione richieda la lettura di una gran quantità di dati è consigliabile chiamare GetAvailableBytes per verificare se sono effettivamente disponibili ed evitare chiamate multiple alla funzione Read. Tramite la scheda di sviluppo DE1-SOC è possibile raggiungere una velocità di circa 850 KBytes/secondo durante la trasmissione al PC di informazioni.

Assieme alla classe è fornito un esempio di di classico ECHO che richiede lato firmware NIOS un programma di echo come il seguente:

nios-ii-firmware

Per progetti in cui è richiesto lo scambio di valori int32, double, etc.. tra PC e NIOS II è possibile estendere senza grossi problemi con funzioni ReadInt32, ReadDouble, WriteInt32, WriteDouble, etc.. la classe.

Con la libreria, abbinata ad un interfaccia utente, è possibile ottenere sicuramente dei risultati accattivanti. Buona comunicazione... tramite JTAG. Scarica il progetto

domenica 5 giugno 2016

Cyclone V SoC: Configuriamo ARM DS-5

Precedentemente avevamo visto come collegare la scheda DE1-SoC al computer tramite cavo ethernet, vediamo adesso come configurare al meglio il software DS-5 per essere maggiormente produttivi nella scrittura del software.

In particolare all’interno dello stesso programma riusciremo ad avere sotto controllo il filesystem, i processi ed un terminale per interagire col nostro sistema ed il debug remoto dei nostri programmi.

Come prima operazione cambiamo la password al nostro sistema Linux tramite il comando passwd,questo ci permetterà di collegarci tramite SSH in quanto una password, per quanto semplice sia, è mandatoria.

passwd

Apriamo adesso Eclipse for DS-5 e scegliamo il menù Window / Open Perspective / Other come mostrato nella figura seguente:

ds5_menu_perspective

Scegliamo Remote System Explorer e confermiamo con OK

open_perspective

Apparirà un nuovo pannello, facciamo click col tasto destro del mouse su Local e scegliamo New / Connection

new_connection

Alla richiesta del tipo di sistema remoto scegliamo Linux e facciamo click su Next. Specifichiamo adesso i dati di connessione della scheda e premiamo nuovamente Next.

new_connection_first_step

Selezioniamo ssh.files tra le configurazioni disponibili per utilizzare il protocollo Sftp per accedere al filesystem e premiamo Finish.

new_connection_files

Espandendo la voce DE1SOC e navigando tra i menù avremo adesso la possibilità di copiare file tramite drag-and-drop, visionare e terminare processi ed interagire col sistema tramite terminale.

ds5

NB: Verrà chiesta la password prima di accedere alle risorse del sistema remoto e la prima volta un messaggio di Warning ci informerà che l’autenticità dell’host non può essere stabilita, premete semplicemente Yes in quanto con una connessione diretta tramite ethernet non ci sono particolari problematiche di sicurezza.

rsa_fingerprint

Creiamo adesso un nuovo progetto scegliendo File / New / C Project. Scegliamo GCC come Toolchain, utilizzeremo gli strumenti gratuiti inclusi nella versione ARM DS-5 Community Edition.

w2

Il progetto creato sarà inizialmente vuoto, aggiungiamo un file sorgente scegliendo New / Source File ricordandoci di aggiungere l’estensione .C al nome del file.

w3

Creiamo un semplice Hello Arm con il seguente codice e compiliamo tramite Project / Build All:

hello

Selezioniamo Debug Configurations premendo il triangolino vicino al pulsante Debug, come illustrato nell’immagine seguente:

w5

A questo punto scegliamo come target Linux Application Debug / Application Debug / Connections via gdbserver / Download and debug application visto che andremo a fare il debug di un applicazione Linux. La versione più completa di DS-5 mostrerà in questa schermata anche altre opzioni di cui però non ci occuperemo.

w6

Spostandoci nella scheda adiacente Files scegliamo come Application on host to download tramite il pulsante Workspace l’eseguibile creato in precedenza.

w7

Nei campi Target download directory e Target working directory impostiamo il percorso /home/root

Confermiamo con Apply e chiudiamo la finestra di dialogo. Siamo adesso pronti ad effettuare un debug remoto con strumenti quali breakpoint, esecuzione passo passo e la visualizzazione di dati relativi a variabili e thread. Premiamo semplicemente il pulsante Debug per iniziare.

w8

Una volta terminata la sessione di Debug esplorando i file presenti nel sistema remoto noteremo la presenza dell’eseguibile, che sarà richiamabile anche in modo tradizionale tramite terminale.

fs

Nonostante questo articolo sia meno tecnico del solito, avere a disposizione la corretta procedura può accelerare la messa a punto della propria postazione di sviluppo. Alla prossima.

martedì 24 novembre 2015

FPGA: Numeri a virgola fissa (seconda parte)

Dopo aver introdotto i numeri fixed point vediamo un semplice blocco in VHDL che calcola la circonferenza di un cerchio dato il raggio.


Possiamo vedere come sia stata definita una costante two_pi che intuitivamente conterrà il valore 2 * pi greco.

La costante è valorizzata tramite la funzione to_ufixed che provvederà a convertire un numero REAL (ma funziona anche con INTEGER, SIGNED e UNSIGNED)  nel tipo per l'appunto UFIXED senza dover convertire "a mano" il numero nella stringa di bit "00110010", approssimazione di 6.28 data la rappresentazione del numero con soli 3 bit per la parte decimale.

Il valore effettivo ottenuto sarà però 6.25, c'è quindi da porre particolare attenzione alla precisione con la quale si eseguono questo tipo di calcoli, il codice VHDL può infatti facilmente trarre in inganno.

Il raggio è costituito da un numero fixed point ad 8 bit mentre il risultato, per evitare overflow, è un numero di 16 bit, dato che è il prodotto di una moltiplicazione.

Per evitare errori in fase di compilazione bisogna tassativamente seguire le regole di dimensionamento, concepite per evitare problemi involontari di overflow, sotto riportate:



Nel nostro caso ci serviamo della riga A * B della tabella. A'left assume il valore INTEG_BIT-1, dato dal bound sinistro scelto nel tipo ufixed del segnale radius, mentre analogamente B'left vale INTEG_BIT-1, dato dalla costante two_pi.

A'right ed B'right avranno entrambi il valore -DECIM_BIT.

Il risultato dovrà avere, seguendo la tabella, un range pari a 2*(INTEG_BIT-1)+1 downto -2*DECIM_BIT, ovvero 9 downto -6 quindi un numero di 16 bit come già detto.

Il VHDL 2008 coi fixed point ci offre una funzione di ridimensionamento con saturazione (per problematiche di overflow) ed arrotondamento (per problematiche di underflow) chiamata resize per eventualmente adattare il risultato ad un numero con diversa risoluzione, vediamone un esempio:


Dove abbiamo come argomenti di resize il numero da ridimensionare, il bound sinistro ed il bound destro del risultato. In tal modo l'uscita circumference avrà la stessa dimensione di 8 bit dell'ingresso.

Sono disponibili diversi overload della funziona resize e rimando alla Fixed point package user’s guide per una descrizione esaustiva di tutte le funzioni.

Nella funzione resize di default sono abilitati l'arrotondamento e la saturazione, seppur è possibile scegliere di troncare e avvolgere (wrap) il valore per ottenere circuiti di velocità maggiore ed area minore.

Sotto è riportata la vista RTL del circuito generato con arrotondamento e saturazione abilitati

L'implementazione su Cyclone V è di 11 ALM ed 1 blocco DSP. Sotto è riportata una simulazione del blocco sopra descritto:



















E' possibile notare come l'uscita saturi a 31.875 (tutti i bit pari ad 1) in caso di valori d'ingresso eccessivi per la risoluzione utilizzata.

Disabilitando arrotondamento e saturazione, il circuito ottenuto sarà come è facile aspettarsi costituito dal solo moltiplicatore, implementato con un singolo DSP. Purtroppo spesso il risultato così ottenuto è poco utilizzabile.



Per modificare lo stile di arrotondamento e di overflow in tutte le operazioni è possibile modificare le costanti fixed_round_style e fixed_overflow_style nel file fixed_pkg_c.vhdl






Per gestire l'underflow, che può verificarsi quando la parte decimale non ha abbastanza risoluzione per rappresentare il risultato, si può utilizzare una modalità fixed_round in cui la parte decimale viene arrotondata al più vicino valore rappresentabile oppure una modalità fixed_truncate dove sono semplicemente persi i bit meno significativi.

L'underflow può verificarsi nella divisione, dove l'errore può accumularsi a causa della natura iterativa degli algoritmi. Per ridurre l'errore vengono inseriti automaticamente dei bit di guardia (guard bit) che aumentano temporaneamente la risoluzione della parte decimale nei calcoli intermedi. Di default il VHDL 2008 utilizza 3 bit di guardia per operazioni come la divisione.

Per gestire l'overflow è possibile utilizzar la modalità fixed_saturate oppure la modalità fixed_wrap che è spesso il "normale" comportamento dei calcolatori e non comporta l'utilizzo di hardware aggiuntivo, incrementando il numero più grande rappresentabile si otterrà il numero più piccolo.

Per singole operazioni è possibile utilizzare gli overload delle funzioni come per esempio









Non mi rimane che augurarvi buona aritmetica.. coi fixed point!


NB: Per rendere compatibile il codice mostrato con ModelSim e compilabile da Quartus 15 è stato modificato il nome della libreria ieee_proposed in ieee, modificando il file fixed_pkg_c.vhdl di cui si è parlato nel precedente articolo. In tale modo ModelSim non lamenterà la mancanza della libreria ieee_proposed, seppur sia possibile crearla. Compilando il codice con un sintetizzatore con supporto per i fixed point del VHDL 2008 non sarà così necessaria alcuna modifica.

giovedì 1 ottobre 2015

FPGA: Numeri a virgola fissa (prima parte)


Il linguaggio VHDL originariamente non prevede alcun supporto ai numeri decimali, con la ratificazione della versione VHDL-2008 si arricchisce finalmente del supporto per i numeri a virgola fissa ed a virgola mobile.

Sfortunatamente la diffusione del nuovo standard non è rapida e ancora oggi la maggior parte degli strumenti di sviluppo supporta un subset più o meno ampio di tutte le funzionalità.

Quartus e Vivado attualmente non supportano la sintesi dei numeri a virgola fissa (fixed-point) o mobile (floating-point), è però possibile scaricare da http://www.eda.org/fphdl una libreria di supporto che permette di fare da ponte da VHDL-93 a VHDL-2008, permettendone così la sintesi con gli strumenti attuali.

Per poter sintetizzare i fixed point è sufficiente aggiungere al progetto i file fixed_pkg_c.vhdl e fixed_float_types_c.vhdl e dichiarare l'utilizzo del package fixed_pkg tramite

library ieee_proposed;
use ieee_proposed.fixed_pkg.all;

Vediamo in questo articolo un'introduzione ai numeri in virgola fissa e le prestazioni delle principali operazioni aritmetiche.

I numeri a virgola fissa vengono rappresentati stabilendo in una posizione ben definita la virgola, ad esempio è possibile rappresentare il valore 3,25 tramite una stringa di bit composta da 1 bit per il segno, 4 bit per la parte intera e 3 bit per la parte decimale.


00011010 rappresenterà proprio 3,25 in quanto:
- il bit 0 indicherà il segno positivo
- 0011 il valore intero 3 con la classica codifica binaria
- 010 il valore decimale 0.25 in quanto l'unità sarà suddivisa in 3 bit, quindi 2^3=8 valori ed 1/8=0.125 e di conseguenza il valore 010, 2 in codifica binaria, rappresenterà 2*0.125=0.25

Per i numeri a virgola fissa i nuovi tipi introdotti sono sfixed ed ufixed, rispettivamente per i numeri con e senza segno.

I numeri negativi sono rappresentati come usuale in complemento due, invertendo i bit ed aggiungendo 1 al risultato.

Vediamo come dichiarare un segnale di tipo sfixed:

signal x : sfixed (4 downto -3);

Tramite il range possiamo specificare come suddividere la parte intera da quella decimale.
La virgola è situata tra l'indice 0 e -1, avremo quindi 5 bit per la parte intera (compreso il bit di segno) e 3 bit per la parte decimale.

NB: E' importante ricordarsi che la parte intera comprende l'indice 0, quindi la sintassi è più semplicemente: sfixed (INTEG-1 downto -DECIM) dove INTEG è il numero di bit per la parte intera (compreso il bit di segno) e DECIM il numero di bit per la parte decimale.

Vediamo adesso un semplice blocco sommatore:



Dove in particolare, oltre a quanto abbiamo visto, notiamo che la dimensione del risultato z è superiore di un bit rispetto ai due addendi per evitare overflow (ed errori in compilazione).

Vedremo in prossimi articoli ulteriori dettagli sui fixed-point.

Concludo l'articolo con una tabella relativa alle prestazioni dei numeri a virgola fissa con segno, estratte in riferimento ad un dispositivo Cyclone V 5CEFA9F23C8, come quello presente nella scheda BEMICRO CV A9.


NB: L'occupazione di risorse logiche (ALM) è stata misurata con logica puramente asincrona mentre le frequenze massime (in MHz) sono state ottenute registrando gli ingressi e le uscite, ovvero inserendo dei flip-flop per evitare di includere nella misurazione i tempi di propagazione verso i pin esterni e poter utilizzare l'analisi statica di TimeQuest per circuiti sincroni.

I bit sono stati equamente suddivisi tra parte intera+segno e parte decimale, ad esempio se la lunghezza dati in tabella è 8 bit per operando 4 bit rappresentano parte intera e segno e 4 bit la parte decimale. La lunghezza dati del risultata varia in base al tipo di operazione eseguita per non permettere overflow.

Dalla tabella è possibile notare come le prestazioni per somma e moltiplicazione siano in linea con le prestazioni degli interi.

I blocchi DSP della FPGA in oggetto non permettono un trattamento di dati di dimensione 32x32, per questo motivo per tale operazione sono stati utilizzati più blocchi DSP.

La divisione rappresenta sicuramente la nota dolente, in quanto è sintetizzata inferendo l'IP LPM_DIVIDE senza pipeline, per prestazioni di throughput migliori è consigliabile istanziare manualmente tale blocco specificando una pipeline di profondità adeguata per la propria frequenza target o sfruttare le funzionalità di retiming di sintetizzatori in grado di spostare i flip-flop all'interno della logica di divisione, come ad esempio Synplify.

lunedì 7 settembre 2015

Wave Sheet

Qualche volta può essere utile riflettere con carta e penna e nel ragionare sulle forme d'onda può essere comodo disporre di un foglio predisposto appositamente per abbozzare qualche idea.

Voglio condividere con voi un template che ho creato, da stampare in orizzontale:


L'utilizzo è abbastanza intuitivo, nella riga iniziale è possibile scrivere il titolo del foglio mentre sulle righe a sinistra il nome dei vari segnali il cui contenuto sarà scritto all'interno delle forme d'onda.

Spero vi faccia risparmiare tempo e magari contribuisca ad un maggiore ordine anche con questi antichi strumenti

NB: Sebbene sia possibile ottenere un risultato analogo con una tabella l'aspetto è più intuitivo per degli elettronici


FPGA: Engineering Change Orders

Sintesi dell'articolo: Modifichiamo senza una ricompilazione completa alcune parti del progetto come la frequenza di uscita del PLL tramite gli strumenti ECO di Quartus.

Durante il ciclo di sviluppo purtroppo le specifiche possono cambiare all'ultimo minuto, queste modifiche sono chiamate in gergo ECO (Engineering Change Orders) e possono  in alcuni casi essere introdotte per compensare problemi di design del sistema.

Vediamo un ipotetico caso semplificato di ECO e di come Quartus possa venirci ancora un volta incontro.

Supponiamo di avere un design su logiche programmabili ad elevata complessità, quindi con tempi di compilazione elevati, e di avere una specifica iniziale di frequenza di 300 MHz ma di aver scelto un dispositivo troppo lento per implementare a tale velocità il design. Purtroppo ci accorgiamo verso il completamento dei lavori che tale frequenza non è raggiungibile.




Il sistema, al solo scopo di facilitare la comprensione, è rappresentato semplicemente nel diagramma da un doppio moltiplicatore con pipeline.

Il design utilizza come usuale un PLL per generare la frequenza di sistema e dopo aver tanto atteso visualizziamo il fatidico Timing requirements not met da Quartus. La frequenza massima per il nostro sistema che TimeQuest riporta supera di poco i 250 MHz.


Non avendo ulteriore tempo a disposizione decidiamo di accettare 250 MHz come frequenza del nostro sistema.

La procedura "standard" richiederebbe di modificare i parametri del PLL e ricompilare il progetto, così facendo innanzitutto non è detto che la frequenza massima dopo la modifica sia sempre superiore ai 250 MHz.

E' però possibile evitare la compilazione completa, che in sistemi complessi può richiedere diverse ore, cambiando solamente le proprietà relative al PLL, vediamo come.

Nel report di compilazione del Fitter andiamo innanzitutto ad individuare la sezione PLL Usage nella categoria Resource Section, facendo click col pulsante destro sul pll scegliamo Locate Node / Locate in Resource Property Editor.


Verranno visualizzate le proprietà del PLL come mostrato nell'immagine seguente


I campi senza sfondo grigio sono modificabili, cambiamo quindi il moltiplicatore del clock da 6 a 5 nel nostro caso per ottenere un clock di uscita di 250 MHz al posto dei 300 MHz.



Il valore M del moltiplicatore verrà aggiornato di conseguenza e tutti i campi modificati verranno evidenziati in rosso.

Ricordiamo infatti l'equazione della frequenza di uscita del PLL in modalità normale:

Altre equazioni come quelle per la variazione della fase ad esempio sono reperibili nella documentazione di Altera.

Scegliamo adesso Edit / Check and Save All Netlist Changes per applicare le modifiche fatte


Dopo una breve compilazione parziale, composta dalla fase di Fitter parziale ed Assembler del file di programmazione il progetto a 250 MHz sarà pronto per essere caricato sulla FPGA  per la validazione.

Prima però eseguiamo TimeQuest per controllare se abbiamo effettivamente risolto tutti i problemi, le violazioni dei tempi di Setup sono sparite ed andando nella scheda Clocks è possibile vedere che la frequenza in uscita dal PLL è effettivamente stata modificata a 250 MHz.


Non ci rimane che provare il design a 250 MHz.

NB: TimeQuest Timing Analyzer è evidenziato di rosso perché sono presenti alcuni percorsi non vincolati nel design che però non hanno criticità per il semplice design utilizzato da esempio per illustrare le funzionalità ECO.

Quartus ci offre inoltre tramite la finestra Change Manager richiamabile dal menù View / Utility Windows che ci da un resoconto delle modifiche ECO così attuate


Lo strumento permette di esportare in file .TCL le modifiche o di riportare il tutto alla situazione originaria.

Questo flusso di sviluppo rapido è molto utile anche durante l'ottimizzazione di progetti in continua modifica per evitare di eseguire una doppia compilazione se la frequenza desiderata non è raggiungibile.

Oltre al PLL è possibile modificare altre celle elementari così come lo standard, lo slew rate ed il current strenght dei pin di I/O.

NB: A causa della differente struttura dei PLL nei dispositivi Cyclone V le funzionalità ECO non sono supportate, è possibile però utilizzare l'IP Altera PLL Reconfig come descritto nell'application notes 661 di Altera per variare i parametri del PLL a tempo di esecuzione.