Generatore toni + KeyPad con IGLOO-NANO-KIT

Dopo aver presentato  la scheda di sviluppo a basso costo per FPGA della famiglia IGLOO di ACTEL/Microsemi, sperimentiamo un primo progetto dove utilizziamo un controllo di tastiera per la generazione di toni.

Per incominciare a sperimentare progetti utilizzando l’AGL-NANO-KIT, completo di sorgenti in linguaggio Verilog. Gli strumenti necessari al test, insieme al KIT, sono una tastiera a matrice e un semplice buzzer. La tastiera richiesta originariamente è una matrice sei righe per tre colonne, per un totale di diciotto tasti, in grado di gestire non solo i toni, ma anche altre funzioni. Per provare la sezione toni sarà comunque sufficiente anche una semplice e più facilmente reperibile tastiera 4x4.

Struttura del progetto: schema a blocchi

Con l’ambiente libero 8.5 regolarmente installato, se avete scaricato il progetto, è sufficiente, dopo aver lanciato libero 8.5, selezionare menu Project > Open project e con un doppio click su file di progetto  PRJ aprirlo (figura 1).

Figura 1: il file di progetto aperto in Libero 8.5.

Figura 1: il file di progetto aperto in Libero 8.5.

Si noti che essendo già compilato correttamente, le icone di sintesi e Place and Route sono colorate in verde. Il progetto come schema a blocchi è invece presentato in figura 2.

Figura 2: schema a blocchi del progetto.

Figura 2: schema a blocchi del progetto.

Qui possiamo evidenziare il PLL che utilizza il clock di scheda a 20 MHz, la sezione di controllo della tastiera a matrice (Keyscan e shift register), oltre che del blocco generatore toni. A schema si evidenzia anche la presenza di un blocco di ricezione trasmissione dati di tipo asincrono a 19200 BAUD. Pur essendo presente in progetto, questa sezione non sarà approfondita, per motivi di spazio. Tramite un pin (nel nostro progetto il pin 20) è possibile attivare la generazione dei toni e anche di melodie, usando dei comandi in arrivo dal PC, in alternativa ai comandi di tastiera. Nel nostro caso poiché il pin 20 è stato posizionato in modalità HW, tutti i comandi possibili potranno arrivare solo dalla tastiera.  I pin da utilizzare per questo progetto sono decisamente pochi: sei pin per la scansione delle righe di tastiera, tre pin per la lettura delle colonne, pin di reset (attivo basso), pin di clock, pin di selezione fra modalità SW o HW, output audio oltre che dei pin RX e TX della sezione seriale.

Top level  del progetto

La figura 3 ci introduce alla parte codice sorgente del progetto. Il top del progetto è il Top_tone_ip.

Figura 3: struttura gerarchica del progetto

Figura 3: struttura gerarchica del progetto

In questo file sono dichiarati  il modulo Tone_ip.v (che è il progetto vero e proprio) e i  moduli per la gestione del clock di sistema. Sempre guardando la figura 3 osserviamo che esistono tre moduli, come struttura gerarchica, per la gestione del clock di ingresso: clk_by_2.v, divideby5.v e PLL_20_10. Sia il clk_by_2.v  che il divideby5.v sono due semplici file verilog, dove il clock in arrivo dall’esterno viene diviso per due o per cinque. Il PLL_20_10  è invece una IP creata direttamente nell’ambiente di sviluppo, che ha configurato il PLL disponibile sul chip Actel. Cliccando infatti due volte sull’icona PLL_20_10, si apre automaticamente la videata di configurazione grafica della periferica (figura 4).

Figura 4: la finestra di configurazione grafica della periferica PLL.

Figura 4: la finestra di configurazione grafica della periferica PLL.

Qui è possibile inserire la frequenza di ingresso come valore (per noi 20 MHz) e scegliere se la sorgente è un pin di tipo Globale ad alto fan out (Hard-wired I/O), un ingresso standard / External I/O, oppure in arrivo da una net interna del progetto. Scelto l’ingresso, si definisce  il valore della frequenza di uscita, che nel nostro caso è 10 MHz. Va fatto notare che questo PLL è in grado di genere fino a tre frequenze, partendo da un’unica sorgente (uscite GLA, GLB e GLC) e le uscite supplementari, se selezionate, attivano i relativi campi, dove inserire le frequenze  desiderate.  I valori in blu sono le frequenze che realmente il PLL è in grado di generare; ricordiamo infatti che i registri di moltiplicazione e divisione sono unici per tutte e tre le frequenze generabili. Nel progetto la frequenza da 10 MHz, che viene usata dal modulo tone_ip.v, è quella generata tramite il PLL.

Controllo  della  tastiera

Proseguendo nell’analisi del progetto, troviamo il modulo tone_ip.v, nel quale i vari moduli sottostanti vengono dichiarati e collegati. Il  controllo della tastiera a matrice viene sviluppato dal modulo Keyscan.v. Questo modulo provvede alla generazione dei segnali di scansione per le sei righe della tastiera e all’acquisizione del tasto premuto, controllando  i tre ingressi delle colonne, infine consente il relativo salvataggio su uno shift register a 18 bit. Il  listato 1 riporta una parte di codice, che provvede alla scansione.

// contatore di righe per scandire ed acquisire
always@(posedge SYS_CLK or negedge reset_l)
begin
 if(~reset_l)
  begin
                                     row <= 3’b000;
  end
 else if (re_kb_clk)                 // rising edge drive row data
  begin
                                     if(row == 3’b111)
                                          row <= 3’b000;
                                     else
                                          row <= row + 1;
    end
end
// Funzione per driving delle uscite tastiera righe tipo - ONE HOT
function [5:0] drive_key_scan;
input [2:0] row;
begin
 case(row)
     3’b000:                    drive_key_scan = 6’b000000;// scan inactive
     3’b001:                    drive_key_scan = 6’b000000;// scan inactive
     3’b010:                    drive_key_scan = 6’b000001;// scan active row 0
     3’b011:                    drive_key_scan = 6’b000010;// scan active row 1
     3’b100:                    drive_key_scan = 6’b000100;// scan active row 2
     3’b101:                    drive_key_scan = 6’b001000;// scan active row 3
     3’b110:                    drive_key_scan = 6’b010000;// scan active row 4
     3’b111:                    drive_key_scan = 6’b100000;// scan active row 5
     default:                   drive_key_scan = 6’b000000;// scan inactive
 endcase
end
endfunction

// copia valori drive_key_scan in uscita sui pin
assign KEYSCAN_OUT = drive_key_scan(row);

// legge lo stato delle colonne e le copia nello shift register a 18 bit
always@(posedge SYS_CLK or negedge reset_l)
begin
  if(~reset_l)
     begin
                              shift_reg <= 18’h00000;
                              keyscan_data <= 18’h00000;
      end
  else if (fe_kb_clk) // falling edge capture col data
      begin
   if (enable_ks)
      begin
        if(row == 3’b111)
        keyscan_data[17:0] <= {KEYSCAN_IN[2], KEYSCAN_IN[1],KEYSCAN_IN[0],shift_reg[17:3]};
        else
        shift_reg[17:0] <= {KEYSCAN_IN[2], KEYSCAN_IN[1],KEYSCAN_IN[0],shift_reg[17:3]};
        end
     end
end
Listato 1

Dal codice osserviamo che la funzione è sviluppata semplicemente codificando il valore row binario a tre bit, nella corrispondenza di tipo ONE HOT e copiandolo sui pin di uscita KEYSCAN_OUT.  Il valore row è a sua volta gestito da un semplice contatore, che viene incrementato alla velocità del clock di tastiera, che è 19,5 KHz, tale valore entra nel modulo Keyscan.v ed è generato dal modulo clk_gen.v. L’acquisizione dei valori di colonna viene eseguita attraverso una funzione, che testando il valore di row decide se caricare e shiftare il registro shift_reg[17:0] (valore in corso), oppure, accorgendosi che si è arrivati al massimo numero di righe con row = 111, concludere l’attività, copiando il valore sul registro keyscan_data, che è lo stato dei 18 tasti disponibili. Una volta acquisito il valore keyscan_data passa attraverso il modulo debounce.v, che provvede alla funzione di antirimbalzo.  Tale funzione è molto semplice ed è una rilettura del valore d’ingresso con aggiornamento del valore di uscita, solo in presenza di cambiamento di stato confermato alla seconda rilettura.

Generazione toni

La generazione dei toni è affidata al modulo tone_generator.v. Questo modulo utilizzando un PWM con variazione in durata e frequenza, permette la generazione dei toni, che per la gestione da tastiera sono coincidenti con la classica scala musicale. Come anticipato all’inizio dell’articolo il progetto, che è una estrapolazione di un sistema HMI (human machine interface) presenta anche la possibilità di ricevere via seriale comandi e valori per la generazione di toni. Pur non approfondendo la sezione seriale (che richiederebbe la spiegazione di tutto il protocollo comandi in arrivo dal PC), dobbiamo evidenziare che il modulo di generazione toni può ricevere comandi sia dal modulo di ricezione seriale serial.v, sia in HW dalla tastiera di sistema. La scelta fra le due opzioni è dettata dallo stato del pin HW_SW, che per le nostre prove deve essere posizionato allo stato logico alto (HW). Questa selezione viene fatta nel modulo tone_ip.v (listato 2).

// contatore di righe per scandire ed acquisire
always@(posedge SYS_CLK or negedge reset_l)
begin
  if(~reset_l)
   begin
                                    row <= 3’b000;
   end
else if (re_kb_clk)                 // rising edge drive row data
   begin
                                    if(row == 3’b111)
                                         row <= 3’b000;
                                    else
                                         row <= row + 1;
   end
end
// Funzione per driving delle uscite tastiera righe tipo - ONE HOT
function [5:0] drive_key_scan;
input [2:0] row;
begin
 case(row)
     3’b000:                              drive_key_scan = 6’b000000;// scan inactive
     3’b001:                              drive_key_scan = 6’b000000;// scan inactive
     3’b010:                              drive_key_scan = 6’b000001;// scan active row 0
     3’b011:                              drive_key_scan = 6’b000010;// scan active row 1
     3’b100:                              drive_key_scan = 6’b000100;// scan active row 2
     3’b101:                              drive_key_scan = 6’b001000;// scan active row 3
     3’b110:                              drive_key_scan = 6’b010000;// scan active row 4
     3’b111:                              drive_key_scan = 6’b100000;// scan active row 5
     default:                             drive_key_scan = 6’b000000;// scan inactive
 endcase
end
endfunction
// copia valori drive_key_scan in uscita sui pin
assign KEYSCAN_OUT = drive_key_scan(row);
// legge lo stato delle colonne e le copia nello shift register a 18 bit
always@(posedge SYS_CLK or negedge reset_l)
begin
   if(~reset_l)
      begin
                                         shift_reg <= 18’h00000;
                                         keyscan_data <= 18’h00000;
      end
  else if (fe_kb_clk)                    // falling edge capture col data
      begin
   if (enable_ks)
      begin
       if(row == 3’b111)
       keyscan_data[17:0] <= {KEYSCAN_IN[2], KEYSCAN_IN[1],KEYSCAN_IN[0],shift_reg[17:3]};
       else
       shift_reg[17:0] <= {KEYSCAN_IN[2], KEYSCAN_IN[1],KEYSCAN_IN[0],shift_reg[17:3]};
       end
     end
end
Listato 2

Qui vengono caricati in maniera fissa i valori in formato HEX e come si vede per la gestione da tastiera, l’unica variabile è il periodo, che cambia a secondo del tono, mentre durata e duty cicle sono fissati al medesimo valore. Questi parametri sono invece gestibili dinamicamente attraverso la sezione seriale. L’abilitazione dei toni è legata alla presenza di tasto premuto sui tasti da 10 a 18. Il registro Key_detect viene utilizzato come operatore per il case, dove in base al suo valore viene assegnato al registro hw_buz_freq l’espressione esadecimale corrispondente alla nota prescelta. Key_detect è la copia dello stato dei tasti 10-18, mentre hw_tone_en è la funzione OR dei medesimi presi in uscita dal modulo antirimbalzo.  I tasti da 1 a 9 non sono utilizzati in questa sezione del progetto.

Implementazione pratica

Dopo aver brevemente analizzato la struttura del progetto, passiamo alla parte di prova. Come specificato in apertura, per la sperimentazione del progetto, oltre allo schedino KIT di prova, serve una tastiera e un buzzer. Poiché è molto più probabile avere in laboratorio una classica tastiera di tipo a matrice 4x4, abbiamo implementato  il progetto utilizzando solo quattro delle righe scandite dal keypad controller. Inoltre, come abbiamo visto nel codice esposto, soltanto nove tasti concorrono nella generazione dei toni. Pertanto su una tastiera 4x4 avremo tre righe di tasti attivi e per ogni riga tre tasti su quattro operativi. Lo schema è quindi quello visualizzato in figura 6, dove abbiamo riportato i due connettori J7 e J9 presenti sul nano KIT e il collegamento della tastiera e del buzzer. Scegliendo dal menu Project > Settings… potete accedere alla scelta del componente della famiglia IGLOO da utilizzare. Eseguito tale cambiamento potrete, senza alcuna altra modifica, lanciare la sintesi cliccando sull’icona Synplify di Libero 8.5 (figura 1) e una volta conclusa  lanciare il place e route utilizzando l’icona Designer. Il sw di Designer permette la configurazione fisica del componente sia come pin sia come selezione dei livelli logici sui banchi di I/O, oltre a moltissime altre caratterizzazioni e verifiche (dalle timing come prestazioni, ai consumi di corrente). L’interfaccia utente di Designer si presenta quindi come in figura 5.

Figura 5: l’interfaccia utente di Designer.

Figura 5: l’interfaccia utente di Designer.

In questa fase, se utilizzerete la copia del progetto presa dal web Actel, dovrete per forza modificare la scelta del componente selezionando dal menu Tools > Device selection... e scegliere AGLN250V2Z package 100 pin. Una volta compilato dovrete piazzare  i pin selezionando l’icona I/O attribute editor e il risultato finale sarà molto simile a quanto in figura 6.

Figura 6: la configurazione dei pin.

Figura 6: la configurazione dei pin.

Si noti l’inserimento delle resistenze di pull down sui segnali, che corrispondono alle tre colonne o ingressi della FPGA in arrivo dalla tastiera stessa. Posizionati  i pin non resta che lanciare il layout (utilizzando la medesima icona) e generare il file di programmazione. Generando questo file, ricordatevi di attivare la creazione del file nome_progetto.stp  oltre che del *.Pdb. Conclusa questa sezione e dopo averla salvata sarà sufficiente tornare all’ambiente libero 8.5 e lanciare il Sw di programmazione del chip selezionando l’icona FlashPro. Prima di quest’ultima operazione ricordiamo di collegare alla porta USB del PC la chiavetta HW di programmazione fornita con il Kit.

 

 

Scrivi un commento

EOS-Academy

Ricevi GRATIS le pillole di Elettronica

Ricevi via EMAIL 10 articoli tecnici di approfondimento sulle ultime tecnologie