Lettura encoder ottici

Sezione dedicata alle logiche programmabili

Lettura encoder ottici

Postby filosofo » 15 Mar 2012, 21:02

Scusate, sto cercando in vari forum.

Si potrebbe implementare su una fpga un hardware in grado di contare in quadratura gli impulsi provenienti da 8 encoder ottici,
quelli con due uscite : CHA e CHB per interderci.
Dovrei leggere contemporaneamente almeno 8 di questi encoder che hanno una risoluzione di 500 impulsi per giro.
Non posso leggerli con un micro tipo un arduino(ho visto che non ce la fà) e allora avevo pensato di creare un hardware con dei componenti discreti. Ma penso che sia meglio mettere tutto su una fpga e via...
Purtroppo non so da dove cominciare... qualcuno mi potrebbe aiutare?

vi ringrazio..
filosofo
 
Posts: 74
Joined: 23 Oct 2011, 09:52
Location: Dintorni di Roma

Re: Lettura encoder ottici

Postby flz47655 » 15 Mar 2012, 21:19

Forse anche una mena costosa CPLD da 1-2 euro (es. Max3000 da 32 o 64 LEs) con un package umano tipo PLCC44 può farcela ma aspetta risposta da qualcuno più esperto, non ho mai provato ad implementare un encoder su CPLD o FPGA.

Ciao
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby deluca » 17 Mar 2012, 12:39

Salve,
Per implementare un decoder / contatore di encoder incrementali ottici su logiche programmabili è necessario implementare
vari moduli VHDL.
Chiaramente una CPLD tipo MAX II basterebbe per implementare uno di questi (forse), ma se vuoi implementarne più di uno (otto) hai
necessità di passare ad una fpga magari del tipo tqfp con un numero di piedini e un quantità di LE adeguati.

Considera 3 pin x 8 segnali encoder CHA, CHB, Index = 24
pin di reset per ogni contatore / addressable = 4
bus 8/16 bit per la lettura dei dati (paralleli) = 16
almeno una decina di segnali per il controllo = 10

Chiaramente non è solo un aspetto legato al numero dei pin ma se vuoi un conteggio a 32 bit per canale
avresti necessità di realizzare :

1) 8 filtri digitali - ingresso 2 canali
2) 8 logic decoder per la rilevazione degli stati in quadratura degli encoder
3) 8 position counter a 32 bit con preload e reset
4) 8 position latch a 32 bit
5) 8 bus i/f logic a 32 bit
6) hardware per la decodifica e multiplexing dei dati paralleli

Facendo un pò i conti ti posso dire che necessitano circa 1000 LE
Una EP1C6T144 potrebbe andare al caso tuo.

Fammi sapere...
ciao
Ciao
Il mio sito: http://www.delucagiovanni.com ......e la chat: chat/
User avatar
deluca
Site Admin
 
Posts: 1104
Joined: 19 Jun 2011, 10:44
Location: 95123 - Catania (Italy)

Re: Lettura encoder ottici

Postby flz47655 » 17 Mar 2012, 14:27

Mi hanno corretto, di positivo c'è che ho imparato qualcosa anch'io :)
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby filosofo » 17 Mar 2012, 16:59

Grazie della risposta,
ma cavolo non credevo fosse così complicato realizzare un decoder per un encoder.
adesso la mia visione si è complicata moltissimo.... troppi moduli e non so proprio da dove iniziare.
mi avevano detto che era semplicissimo e che bastavano poche porte logiche !!!! .azzz

cerco di capire a cosa serve il filtro e poi gli altri pezzi......
anche perchè adesso gli encoder sono diventati 10 o forse 16.

devo studiare e vedere come iniziare.... giovanni, spero sarai disponibile come sempre a darmi qualche delucidazione
se incontrerò problemi.

intanto grazie
filosofo
 
Posts: 74
Joined: 23 Oct 2011, 09:52
Location: Dintorni di Roma

Re: Lettura encoder ottici

Postby filosofo » 18 Mar 2012, 14:58

Code: Select all
LIBRARY ieee ;
USE ieee.std_logic_1164.all;

ENTITY digital_filter IS
 PORT (
      CHA_inp : IN std_logic;
      CHB_inp : IN std_logic;
      Clk        : IN std_logic;
      RST        : IN std_logic;
      CHA_out  : OUT std_logic;
      CHB_out  : OUT std_logic
      );
END digital_filter;


Giovanni,
sto iniziando a scrivere l'entity del decoder.
l'impostazione dell'entity del filtro va bene ?
sono questi i segnali che occorrono?

Quanto deve essere la frequenza di Clk per poter leggere tranquillamente gli impulsi
degli encoder con risoluzione di 500 impulsi per giro che vanno ad una velocità di 6000 RPM?
filosofo
 
Posts: 74
Joined: 23 Oct 2011, 09:52
Location: Dintorni di Roma

Re: Lettura encoder ottici

Postby deluca » 19 Mar 2012, 16:34

Quanto deve essere la frequenza di Clk per poter leggere tranquillamente gli impulsi
degli encoder con risoluzione di 500 impulsi per giro che vanno ad una velocità di 6000 RPM?


Considerando di avere 6000 rpm abbiamo 6000/60 = 100 rotazioni di asse motore al secondo
Poi abbiamo 500 impulsi x 4 perchè in quadratura = 2000

A questo punto otteniamo 2000 x 100 = 200.000 = 200 KHz
Visto che per filtrare gli ingressi abbiamo di bisogno una frequenza almeno tripla della freq massima otteniamo:

200 KHz x 3 = 600 KHz (clock)

Di sicuro la freq di clock generata dal cristallo a bordo di qualsiasi schedina di sviluppo va bene visto che di morma
tutte le schede con FPGA/CPLD sono equipaggiate con un cristallo da 25/50 MHz

Spero sia stato chiaro
Ciao
Il mio sito: http://www.delucagiovanni.com ......e la chat: chat/
User avatar
deluca
Site Admin
 
Posts: 1104
Joined: 19 Jun 2011, 10:44
Location: 95123 - Catania (Italy)

Re: Lettura encoder ottici

Postby flz47655 » 21 Mar 2012, 11:10

Ho trovato delle interessanti informazioni: http://www.delucagiovanni.com/files/FPGA%20quadrature%20encoder.htm :D
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby filosofo » 28 Mar 2012, 17:27

Scusate, come avevo postato prima......
sto cercando di scrivere un vhdl per filtrare i segnali provenienti da un encoder rotativo.
Ho visto l'architettura sulla documentazione di gio però non trovo un esempio da cui partire.
si potrebbe avere un indizio ?
Io sto usando una schedina con una ep1c6.... purtroppo non ci sto ricavando un bel nulla e mi sto scoraggiando.
intanto vorrei capire meglio il perchè del primo stadio filtro.....

vi ringrazio tanto per la pazienza....
filosofo
 
Posts: 74
Joined: 23 Oct 2011, 09:52
Location: Dintorni di Roma

Re: Lettura encoder ottici

Postby flz47655 » 29 Mar 2012, 19:30

Hai provato a dare un'occhiata a http://www.fpga4fun.com/QuadratureDecoder.html?
Magari non è proprio quello che vuoi fare ma ti da qualche spunto.
Direi che è inutile farsi scrivere il codice da qualcun'altro, ti conviene partire magari da esempi più semplice con difficoltà via via crescente ed imparare meglio il VHDL per poi crearti da solo l'encoder.
Io ti posso consigliare il libro "Rapid Prototyping of Digital Systems" se hai già buone basi di reti logiche. E' il libro più pratico (stile tutorial) che ho trovato per il momento, nella SOPC edition parla anche di NIOS II, il soft-processor, che per il momento comunque non dovrebbe interessarti.
Se invece hai bisogno dell'encoder ma non vuoi farlo da solo puoi provare a cercare su open-cores o farlo scrivere da qualche professionista (giustamente dietro compenso).
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby filosofo » 30 Mar 2012, 07:17

Scusa, flz
grazie per la segnalazione
ma ieri su questo sito ho visto qualcosa ma era solo in verilog di cui non capisco una mazza.
http://www.fpga4fun.com/QuadratureDecoder.html

ecco il codice:
Code: Select all
module quad(clk, quadA, quadB, count);
input clk, quadA, quadB;
output [7:0] count;

reg quadA_delayed, quadB_delayed;
always @(posedge clk) quadA_delayed <= quadA;
always @(posedge clk) quadB_delayed <= quadB;

wire count_enable = quadA ^ quadA_delayed ^ quadB ^ quadB_delayed;
wire count_direction = quadA ^ quadB_delayed;

reg [7:0] count;
always @(posedge clk)
begin
   if(count_enable)
   begin
     if(count_direction) count<=count+1; else count<=count-1;
   end
end

endmodule


questo poi mi sembra il conteggio vero e proprio ed io invece ho necessità di iniziare con il filtro d'ingresso dei canali a e b.

comunque grazie lo stesso
filosofo
 
Posts: 74
Joined: 23 Oct 2011, 09:52
Location: Dintorni di Roma

Re: Lettura encoder ottici

Postby flz47655 » 02 Apr 2012, 13:37

Non mi intendo di Encoder ottici, posso provare ad aiutarti però devi scrivere cosa vuoi ottenere dal filtro di ingresso ;)
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby filosofo » 02 Apr 2012, 17:03

Ho visto all'oscilloscopio che i segnali dell'encoder A e B non sono perfettamente puliti (vibrano) e allora leggendo tra la letteratura sugli encoder, ho visto che è necessario essere certi del livello di ogni canale e sopratutto della transizione.
Per fare questo ho visto che è necessario che il segnale di un canale venga combinato con il clock di modo che ogni impulso conti almeno 3 cicli di clock prima che venga elaborato e passato al modulo decoder quadratura... (tipo un antirimbalzo nei pulsanti).
Così facendo si dovrebbe migliorare l'immunità al rumore causato dalle vibrazioni del motore durante il movimento.

In sintesi questo è quello che dovrebbe fare il filtro....

Cmq grazie per l'interesse
filosofo
 
Posts: 74
Joined: 23 Oct 2011, 09:52
Location: Dintorni di Roma

Re: Lettura encoder ottici

Postby deluca » 02 Apr 2012, 18:35

Filosofo, ti mostro un code su come implementare un filtro digitale per l'encoder sotto torchio.
Certo questa non è la via giusta per imparare..... ma da qui puoi prendere il via per partire con il tuo progetto.
Vedremo cosa saprai fare :P

Code: Select all
----------------------------------------------------
-- Encoder Digital filter 
-- G. De Luca - INFN-LNS
-- 27/12/2010
-- non per usi commerciali - solo per studio
----------------------------------------------------

LIBRARY ieee ;
USE ieee.std_logic_1164.all;

ENTITY digital_filter IS
 PORT (
      CHA       : IN std_logic;
      CHB      : IN std_logic;
      Clk      : IN std_logic;
      RST      : IN std_logic;
      CHA_filt : OUT std_logic;
      CHB_filt   : OUT std_logic
      );
END digital_filter;

ARCHITECTURE arch_digital_filter OF digital_filter IS

SIGNAL  temp_CHA: std_logic;     
SIGNAL  temp_CHB: std_logic;       

BEGIN
---------------------------------------------------
Channel_A:PROCESS(CLK, RST)
 
  VARIABLE Afilter: std_logic_vector(0 to 3);
 
  BEGIN
    IF RST = '0' THEN
      Afilter := "0000";
      temp_CHA <= '0';
    ELSIF (CLK'event AND CLK = '1') THEN
        Afilter(1 to 3) := Afilter(0 to 2);
        Afilter(0) := CHA;
        IF Afilter(1 to 3) = "000" THEN
           temp_CHA <= '0';
        END IF;
        IF  Afilter(1 to 3) = "111" THEN
           temp_CHA <= '1';
        END IF;
    END IF;
  END PROCESS;
  CHA_filt <= temp_CHA;
--------------------------------------------------
Channel_B:PROCESS(CLK, RST)
 
  VARIABLE Bfilter: std_logic_vector(0 to 3);
 
  BEGIN
    IF RST = '0' THEN
      Bfilter := "0000";
      temp_CHB <= '0';
    ELSIF (CLK'event AND CLK = '1') THEN
        Bfilter(1 to 3) := Bfilter(0 to 2);
        Bfilter(0) := CHB;
        IF Bfilter(1 to 3) = "000" THEN
           temp_CHB <= '0';
        END IF;
        IF  Bfilter(1 to 3) = "111" THEN
           temp_CHB <= '1';
        END IF;
    END IF;
  END PROCESS;
  CHB_filt <= temp_CHB;
--------------------------------------------------
  END arch_digital_filter;


Come puoi vedere dalla dichiarazione di entity
il modulo ha 2 ingressi per i canali A e B da collegare all'encoder ,
2 uscite A e B filtrate, il segnale di clock su quale devi applicare la frequenza (non meno di qualche mhz),
e il reset (puoi anche omettere questo segnale se vuoi)

Ciao, fammi sapere
Ciao
Il mio sito: http://www.delucagiovanni.com ......e la chat: chat/
User avatar
deluca
Site Admin
 
Posts: 1104
Joined: 19 Jun 2011, 10:44
Location: 95123 - Catania (Italy)

Re: Lettura encoder ottici

Postby flz47655 » 02 Apr 2012, 21:06

Interessante, in pratica funziona così, l'ho sintetizzato anch'io per divertimento, grazie giovanni!

E' uno shift register di 4 bit dove sul primo elemento di memoria si copia il valore di ingresso e poi si shifta verso destra, se gli ultimi tre bit sono tutti 0 allora il risultato sarà 0, se sono tutti 1 il risultato sarà 1.

Facendo girare il tutto ad una frequenza superiore al segnale da filtrare si riesce a "campionarlo" diverse volte, una modifica che mi sono auto-proposto per esercizio è questa, il risultato è il bit più frequente negli ultimi 3 bit (es. se c'è 101 il risultato è 1, se c'è 001 il risultato è 0), magari filosofo potresti provare a fare anche tu la modifica per vedere se hai capito il codice

Ciao
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby flz47655 » 02 Apr 2012, 21:37

Ho provato anche per diletto a riscrivere il codice di Giovanni e a ridurlo di lunghezza ed evitare "ripetizioni"

Code: Select all
LIBRARY ieee ;
USE ieee.std_logic_1164.all;

ENTITY digital_filter IS
 PORT (      
      CH      : IN std_logic_vector(0 to 1);
      Clk     : IN std_logic;     
      CH_filt : OUT std_logic_vector(0 to 1)   
      );
END digital_filter;

ARCHITECTURE arch_digital_filter OF digital_filter IS

SIGNAL  temp_CH: std_logic_vector(0 to 1);

BEGIN
Channel:PROCESS(CLK) 
   VARIABLE filter: std_logic_vector(0 to 7);   
   BEGIN
    IF (CLK'event AND CLK = '1') THEN
       
    for i in 0 to 1 loop   
      filter((i*4)+1 to (i*4)+3) := filter((i*4) to (i*4)+2);   
      filter(i*4) := CH(i);      
      IF filter((i*4)+1 to (i*4)+3) = "000" THEN
         temp_CH(i) <= '0';
      END IF;
      IF  filter((i*4)+1 to (i*4)+3) = "111" THEN
         temp_CH(i) <= '1';
      END IF;
    end loop;
           
    END IF;
  END PROCESS;
 
  CH_filt <= temp_CH;
 
END arch_digital_filter;


Il vantaggio è che con poche modifiche è possibile aumentare il numero dei canali senza fare copia/incolla di codice VHDL che porterebbe a sorgenti lunghissimi con molti canali.

Una cosa che ho scoperto che mi manca in VHDL è la possibilità di creare delle stringhe da sostituire prima della compilazione, i #define del C per intenderci.

In questo caso mi servirebbero per definire il numero di canali e limitare quindi al cambiamento di un numero il cambiamento dei numeri di canali.

Avete qualche idea di un surrogato del #define?

Ciao e grazie a tutti
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby flz47655 » 02 Apr 2012, 22:06

Ho provato con constant ma diviene difficile utilizzarla all'interno dell'Entity, in tutto per cambiare il numero di canali col seguente codice sono necessarie 3 modifiche mentre vorrei arrivare ad 1 sola modifica.

Code: Select all
LIBRARY ieee ;
USE ieee.std_logic_1164.all;

ENTITY digital_filter IS
 PORT (      
      CH      : IN std_logic_vector(0 to 5);    -- for number of channels
      CH_filt : OUT std_logic_vector(0 to 5);    -- change CH and CH_filt
      Clk     : IN std_logic
      );   
END digital_filter;

ARCHITECTURE arch_digital_filter OF digital_filter IS
constant NUM_CHANNELS: integer := 5; -- NUM_CHANNELS base 0
SIGNAL  temp_CH: std_logic_vector(0 to NUM_CHANNELS);
BEGIN
Channel:PROCESS(CLK)     
   VARIABLE filter: std_logic_vector(0 to ((NUM_CHANNELS+1)*4)-1);   
   BEGIN
    IF (CLK'event AND CLK = '1') THEN       
       for i in 0 to NUM_CHANNELS loop   
         filter((i*4)+1 to (i*4)+3) := filter((i*4) to (i*4)+2);   
         filter(i*4) := CH(i);      
         IF filter((i*4)+1 to (i*4)+3) = "000" THEN
            temp_CH(i) <= '0';
         END IF;
         IF  filter((i*4)+1 to (i*4)+3) = "111" THEN
            temp_CH(i) <= '1';
         END IF;
       end loop;           
    END IF;
  END PROCESS; 
  CH_filt <= temp_CH;   
END arch_digital_filter;
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby deluca » 03 Apr 2012, 11:27

Complimenti a flz per aver ottimizzato il codice del filtro.
Purtroppo però non è sempre consigliabile parametrizzare il codice e instanziare cicli for poichè in questo modo
il codice diventa meno leggibile.... (ti spiego perchè).

Se il codice è personale allora tutto questo può essere accettato.
ma se il codice deve essere usato in un contesto diverso è sempre bene esplicitare la descrizione dei vari processi
in quanto una descrizione hw iterativa con i cicli for non sempre semplifica la creazione di un Top Level Entiy
in quanto se si vuole crearlo in modalità schematic utilizzando moduli unitari il fatto di non avere una nomenclatura esplicita oggettiva
porta alla generazione di uno schema poco intelleggibile da parte di terze persone che collaborano al progetto (se si lavora in team).
ES: cosi non hai più CHA e CHB per ogni modulo, ma avrai una array di CH[x].
Trova il modo di esplicitare la nomenclatura... sulla descrizione dei PINs.


Comunque ..... ben fatto.
Ciao
Il mio sito: http://www.delucagiovanni.com ......e la chat: chat/
User avatar
deluca
Site Admin
 
Posts: 1104
Joined: 19 Jun 2011, 10:44
Location: 95123 - Catania (Italy)

Re: Lettura encoder ottici

Postby flz47655 » 04 Apr 2012, 11:41

Grazie :D
flz47655
 
Posts: 639
Joined: 19 Jan 2012, 21:16

Re: Lettura encoder ottici

Postby Tedesco » 07 Apr 2012, 15:21

Ciao a tutti,
sono nuovo del forum e lo trovo molto interessante.

Per quanto riguarda l'ottimizzazione del codice del filtro sono completamente d'accordo con deluca.
Infatti per i linguaggi di descrizione dell'HW la leggibilità del codice è veramente molto importante, forse più che per gli altri linguaggi di programmazione in quanto la concorrenzialità dei processi potrebbe facilmente confondere il progettista.
Pertanto propongo come evoluzione del codice scritto in precedenza il segente:

Code: Select all
ENTITY digital_filter IS
   generic(
      NUM_CHANNELS   : integer := 5 -- NUM_CHANNELS+1 base 0
      );
   PORT (     
      CH      : IN std_logic_vector(0 to NUM_CHANNELS);    -- for number of channels
      CH_filt : OUT std_logic_vector(0 to NUM_CHANNELS);    -- change CH and CH_filt
      Clk     : IN std_logic
      );   
END digital_filter;

ARCHITECTURE arch_digital_filter OF digital_filter IS

SIGNAL  temp_CH         : std_logic_vector(0 to NUM_CHANNELS):=(others=>'0');

BEGIN

filtri:for i in 0 to NUM_CHANNELS generate
signal filter: std_logic_vector(0 to 3):=(others=>'0');
begin
   Channel:PROCESS(CLK)     
   BEGIN
      IF (CLK'event AND CLK = '1') THEN       
         filter(1 to 3)    <= filter(0 to 2);   
         filter(0)       <= CH(i);     
         IF filter(1 to 3) = "000" THEN
            temp_CH(i) <= '0';
         END IF;
         IF  filter(1 to 3) = "111" THEN
            temp_CH(i) <= '1';
         END IF;
      END IF;
   END PROCESS;
end generate;

CH_filt <= temp_CH;

END arch_digital_filter;


E' un pò più snello? ;)
In questo modo per aumentare i canali basta solo modificare il valore nel generic in testa alla definizione dell'entity (1 modifica).
In VHDL purtroppo non sembra esistere un equivalente del #define del C. Si potrebbe creare una libreria da includere ad inizio progetto, ma è poco pratico in quanto deve essere ricompilato (da ModelSim per esempio, QuartusII o ISE Xilinx non lo permettono) ogni volta che si cambia qualche valore e sempre separatamente dalla compilazione del progetto. Quindi meglio il generic.

Un saluto a tutti,
e buona Pasqua. :D
Tedesco
 
Posts: 7
Joined: 06 Apr 2012, 21:39

Next

Return to FPGA & CPLD

Who is online

Users browsing this forum: No registered users and 4 guests