Page 1 of 2
		
			
				Lettura encoder ottici
				
Posted: 
15 Mar 2012, 21:02by filosofo
				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..
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
15 Mar 2012, 21:19by flz47655
				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
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
17 Mar 2012, 12:39by deluca
				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
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
17 Mar 2012, 14:27by flz47655
				Mi hanno corretto, di positivo c'è che ho imparato qualcosa anch'io 

 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
17 Mar 2012, 16:59by filosofo
				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
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
18 Mar 2012, 14:58by filosofo
				- 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?
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
19 Mar 2012, 16:34by deluca
				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
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
21 Mar 2012, 11:10by flz47655
				
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
28 Mar 2012, 17:27by filosofo
				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....
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
29 Mar 2012, 19:30by flz47655
				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).
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
30 Mar 2012, 07:17by filosofo
				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.htmlecco 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
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
02 Apr 2012, 13:37by flz47655
				Non mi intendo di Encoder ottici, posso provare ad aiutarti però devi scrivere cosa vuoi ottenere dal filtro di ingresso 

 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
02 Apr 2012, 17:03by filosofo
				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
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
02 Apr 2012, 18:35by deluca
				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  
 
 - 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
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
02 Apr 2012, 21:06by flz47655
				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
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
02 Apr 2012, 21:37by flz47655
				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
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
02 Apr 2012, 22:06by flz47655
				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;
 
 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
03 Apr 2012, 11:27by deluca
				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.
			 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
04 Apr 2012, 11:41by flz47655
				Grazie 

 
			
		
			
				Re: Lettura encoder ottici
				
Posted: 
07 Apr 2012, 15:21by Tedesco
				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. 
