Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

9
voti

UART TX su FPGA

Indice

Introduzione

Questo piccolo articolo nasce per puro caso. Ultimamente sto armeggiando con le Low Level Library (LL) della ST e più scendo a basso livello più rimango affascinato dall'elettronica. Per me non è tanto veder funzionare le cose quando pensare a come sono fatte dentro, nel piccolo e poi ancora più nel piccolo. E così, visto che è estate e che le lezioni non sono ancora incominciate, ho colto il consiglio di un utente del forum che ogni volta che si parla di FPGA lui consiglia "fate una UART così che potete parlare col PC". Avevo già lavorato con le FPGA scrivendo in VHDL ma mi piaceva l'idea di lasciare qualcosa sul forum di un argomento non molto "user friendly" rispetto ai più comuni microprocessori che (a parte Arduino) sono comunque moooolto più usati dalla grande massa.

Dove sta la differenza?

Non partirò dagli albori a spiegare le ovvie differenze tra FPGA e microcontrollori nella teoria di funzionamento. Piuttosto è interessante vedere come si lavora con l'hardware su livelli di astrazione diversi. In un mictrocontrollore ci sono già dei pezzi di puzzle (UART, ADC, DAC, SPI.... ) e sta all'utente configurarli e montarli insieme. Si passa praticamente sempre per un primo processo di setup in cui si scelgono, ad esempio, numero di bit, parità, baudrate, DMA e altre impostazioni; fatto questo al programmatore non resta che scrivere il dato da mandare dentro un registro apposito e dare il via. Quello che succede da quel momento in poi non è più competenza del programmatore: ha impostato un blocchetto e adesso quel blocchetto sta funzionando, che si vuole di più dalla vita? A me piace scrivere anche quel blocchetto e farmelo felicemente a modo mio. E' ovvio che quello che io progetto come trasmettitore UART sarà mooolto meno elaborato del blocchetto che è presente in un micro, sarà meno ottimizzato, avrà meno funzioni, ma sarà mio. Le softwarehouse mettono a dispozione delle blackbox chiamate IPCore che sono anche questi dei pezzi prefatti da copincollare che funzionano alla grande. Ma in questo modo si ritorna al più semplice mettere insieme cose fatte da altri e non si scende nel dettaglio del protocollo e dell'implementazione. Tutto questo sproloquio per dire che mi sono messo a scrivere un trasmettitore (e nel prossimo capitolo anche il ricevitore) con protocollo UART su FPGA.

La FPGA

Sono un povero studente che vuole imparare, non ho molti soldi e mi è sempre piaciuto fare le cose con le mie mani. Invece di prendere una board (ad esempio della Xilinx) che ha già a bordo programmatore, display, pulsanti e tanto altro per divertirsi con una scheda mono-blocco, ho deciso di prendere una piccola ed economica (e cinese) board della Altera. Quello che c'è a bordo è: alimentazione, FPGA, basta. Il programmatore preso a parte costa anche lui una miseria. La board ha i pin tutti su connettori header maschi quindi connetterci altri dispositivi è facile e anche cablarla su millefori viene comodissimo. Cyclone II Mini Board: 15€

altera-cyclone-ii-ep2c5t144-cpld-fpga-development-

altera-cyclone-ii-ep2c5t144-cpld-fpga-development-

Il programmatore è sempre della Altera e non riserva particolari sorprese apparte il prezzo: 6€. E così con meno di 20€ si ha a disposizione una FPGA che apre lo svilupatore a un nuovo mondo diverso dai micro a cui è abituato.

Il trasmettitore UART

Specifiche:

  • Word: 8bit
  • BaudRate: dipendente dal clock (see later)
  • No parity bit
  • Segnale in uscita che indica quando il trasmettitore è pronto a ricevere un nuovo dato
  • Segnale in ingresso di Start che indica che il dato è pronto e può iniziare la trasmissione

Assolutamente nulla di neanche lontanamente speciale. Si tratta di:

  • aspettare il segnale di start
  • quando arriva "fotografare" l'ingresso da trsmettere
  • trasmettere lo start bit (basso)
  • trasmettere il dato (8 bit)
  • trasmettere lo stop bit
  • comunicare all'esterno che si è pronti per una nuova trasmissione

Insomma: una "macchinetta" a stati senza pretese.

La Entity

La entity è il contenitore del nostro componente. Quando compriamo un operazionale ci viene dato un cosino nero con tutti i piedini e a noi interessa sapere (dal datasheet) a cosa corrispondono quei piedini! Anche senza avere la minima idea di che struttura abbia all'interno quell'operazionale serve sapere per lo meno dove stanno alimentazioni, entrate ed uscite: questa è la entity.

Immagine.png

Immagine.png

La architecture

Se premessimo sul "+" che sta in alto a sinistra nell'immagine della entity ci troveremmo di fronte ad un po' di Flip Flop, adder, mux e comparatori opportunamente connessi. Per fortuna il VHDL e i sintetizzatori ci permettono di non scrivere ad uno ad uno tutti i gate e tutte le funzioni logiche ma possiamo effettuare una descrizione più ad alto livello, sintatticamente vicina ad esempio al C ma teoricamente molto diversa. La seguente è l'idea di funzionamento:

Spiegato brevemente a parole:

  • finchè l'output è 1 e ready è 1 non sto trasmettendo: controllo se l'enable è alto
  • se Enable è basso vuol dire che non sto trasmettendo e non devo neanche iniziare a farlo: tutto fermo
  • se Enable è alto vuol dire che inizia la trasmissione: salvo il registro di ingresso, start bit, trasmetto i dati, stop bit, ready alto, si ricomincia

che si trasforma nel seguente codice VHDL:


architecture Behavioral of UART_TX is
    signal ready: std_logic:= '1';
    signal buff: std_logic_vector( 7 downto 0) := (others => '0');
    signal counter: std_logic_vector (3 downto 0) := "0000";
begin
    process(CLK) begin
        if(rising_edge(CLK)) then
            if(ENABLE= '1' and ready='1') then
                    -- carica start bit, prendi registo, porta basso ready
                    TX_DATA_OUT <= '0';
                    buff<= TX_BUFFER;
                    ready <= '0';
            elsif(ready = '0') then
                if(counter = "1000") then
                     TX_DATA_OUT <= '1';
                     counter<= counter +1;
                elsif(counter= "1001") then
                    counter <= "0000";
                    ready <= '1';
                                   else
                    counter <= counter +1;
                --TX_DATA_OUT <= buff(7 - to_integer(unsigned(counter)));
		TX_DATA_OUT <= buff(to_integer(unsigned(counter)));
                end if;
            end if;
        end if;
    end process;
RTT<= ready;end Behavioral;

Il risultato di una prima simulazione è il seguente:

Immagine.png

Immagine.png

Click to zoom. In verticale c'è una linea gialla che evidenzia l'inizio della trasmissione. Appena l'enable va alto e la trasmissione deve partire si vede che la linea dati viene portata bassa e non si è più Ready To Transfer (RTT). La simulazione ha confermato il corretto funzionamento del dispositivo.

Caricare sulla board

La simulazione conferma che il trasmettitore fa il suo dovere quando usato nella maniera corretta e in simulazione è facile impostare i segnali di ingresso con i timing giusti e far cambiare l'ingresso per vedere le trasmissioni. Quando si vuole caricare il bitstream su una board e vedere effettivamente la trasmissione allora bisogna inventarsi un modo per "stimolare" il componente. Si può fare in tanti modi, quello che preferisco (e non è il più facile) è quello di creare un' altra entity che generi i dati e li passi al trasmettitore. Questo vuol dire ricominciare da capo con un'altro progetto e poi collegarli insieme ma abbiamo la garanzia di avere due oggetti separati: Device Under Test( DUT: il nostro trasmettitore) e un coso a parte del tutto separato che genera dati. La struttura finale è di questo tipo

Immagine.png

Immagine.png

Clock e BaudRate

L'ultima domanda che rimane è: come impostiamo il Rate di trasmissione? Il vantaggio che il VHDL offre è di poter avere una struttura di astrazione molto verticale. Quindi per ora il trasmettitore che ho descritto manda un bit ogni colpo di clock, bisogna impostare una frequenza di clock corretta per avere una trasmissione corretta. Starà a chi usa questo componente (sempre io) usare un divisore coerente con le necessità. Le altre due idee sono:

  • Modificare il clock prima: si usano delle specie di "define" che accettano la frequenza di clock da dividere e il baud rate e calcolano il divisore da usare. Nel momento in cui il sintetizzatore viene lanciato disegnerà già il circuto corretto: ottimizzato ma non modificabile runtime
  • Progettare un blocco di clock: si fa una nuova entity che avrà come ingressi dei parametri e come uscita il clock così da essere modificata runtime. Si può creare anche un macroblocco con trasmettitore e gestore di clock già all'interno così da usarlo come un blocco unico senza dover ogni volta fare i collegamenti tra i due.

Conclusioni

Compilato il codice, generato il bitstream e connesso i pin della scheda con una FTDI il pc riceve i dati senza problemi. Il prossimo step sarà un ricevitore così da avere una comunicazione completa col PC. Non metto bibliografia perchè è un articolo talmente banale che dovrei citare qualsiasi cosa. Non metto neanche foto del collegamento al PC perchè farvi vedere l'FPGA che dice "ciao" non è poi così entusiasmante per chi è dietro lo schermo (per me lo è stato eccome)!
Davide

3

Commenti e note

Inserisci un commento

di ,

Apri apri, buona idea. Ché è piú comodo che scrivere qui ;-)

Rispondi

di ,

Salve, sono contento che tu abbia letto l'articolo! Eh si, avevo avuto occasione in facoltà di fare altro su FPGA ma dopo la seconda volta che ti ho visto proporre una UART mi sono detto "challenge accepted"! Grazie di cuore del consiglio. Sono sicuro ci siano ben più di un paio di dettagli da migliorare, mi farebbe piacere aprire un 3d in cui ne parliamo un po' penso potrebbe essere interessante: che ne pensi? Davide

Rispondi

di ,

un utente del forum che ogni volta che si parla di FPGA lui consiglia "fate una UART così che potete paralare col PC"... non ho idea di chi tu intenda :-P Mi fa molto piacere vedere gente che si avvicina al VHDL o, piú in generale, al design digitale. E un tema complesso e hai fatto un bel lavoro. Ma ci sarebbero un paio di dettagli migliorabili. Se non ti dà fastidio, ti propongo di scrivere la parte RX, commentando un po' quello che faccio per capire il motivo di certe scelte diverse. In ogni caso, è un bell'articolo!

Rispondi

Inserisci un commento

Per inserire commenti è necessario iscriversi ad ElectroYou. Se sei già iscritto, effettua il login.

Tag Cloud

PDF by PrinceXML