EmbDev.net

Forum: FPGA, VHDL & Verilog Quadrature decoder


Author: Chris (Guest)
Posted on:

Rate this post
0 useful
not useful
Can someone help please, I have a code for a quadrature counter in vhdl 
to a counter, this code will only count up and I cannot find a way to 
count down on opposite direction. I am interfacing a magnetic rotory 
encoder and plan on spinning up to 6k rpm, I don't believe I need a 
bunch of filtering being that it is a clean square wave from ic, and not 
optical. here is my code.

 LIBRARY ieee;
 USE ieee.std_logic_1164.ALL;
 USE ieee.numeric_std.ALL;
 use ieee.std_logic_unsigned.all;

 entity counter is
 Port ( Clk : in std_logic;
 A_In : in std_logic;
 B_In : in std_logic;

 data_out : out std_logic_vector(11 downto 0);

 Reset : in std_logic);

 end counter;
 architecture Behavioral of counter is
 SIGNAL Last_A, Last_B :std_logic;
 SIGNAL Current_A, Current_B : std_logic;
 SIGNAL Dir :  std_logic;
 SIGNAL up_down : std_logic;
 SIGNAL count:  UNSIGNED(11 downto 0):=(OTHERS =>'0') ;
 begin
 up_down <= (Current_A xor Last_A) xor (Current_B xor Last_B);
 Dir <= (Current_A xor Last_B) XOR (Current_B xor Last_A);

 process (clk, Reset)
 begin
 if rising_edge(clk) then
 Last_A <= Current_A;
 Last_B <= Current_B;
 Current_A <= A_In;
 Current_B <= B_In;

 end if;
 end process;

 process (clk, Reset) begin
 IF (Reset = '1') THEN
 count <= "000000000000";

 ELSIF (clk'EVENT AND clk= '1')THEN

 IF(up_down = '1') THEN
 IF(Dir='1')THEN
 count <= count + 1;
 ELSIF(up_down = '0') THEN
 IF(Dir='0')THEN
 count <= count - 1;
 END IF;
 END IF;
 END IF;
 END IF;
 data_out <= STD_LOGIC_VECTOR( count);
 END PROCESS;
 end Behavioral;

Author: Chris (Guest)
Posted on:

Rate this post
0 useful
not useful
The board is a Lattice Machx02 7000he breakout from digikey.

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Chris wrote:
> here is my code.
And what is the problem with it?

(I can see, that this code is nonsene for the desired task, but I want 
to encourage you to analyze your problem)

Look at my way to connect and decode a quadrature signal:
http://www.lothar-miller.de/s9y/categories/46-Encoder

: Edited by Moderator
Author: MaWin (Guest)
Posted on:

Rate this post
0 useful
not useful
Chris wrote:
> IF(up_down = '1') THEN

The whole section is up_down 1

>  IF(Dir='1')THEN
>  count <= count + 1;
>  ELSIF(up_down = '0') THEN

How should up_down ever be 0 ?

>  IF(Dir='0')THEN
>  count <= count - 1;
>  END IF;
>  END IF;
>  END IF;
>  END IF;

Author: Chris (Guest)
Posted on:

Rate this post
0 useful
not useful
well through a few more examples I was able to fix it, counts perfectly 
from 0 to 4095 on 12 led's in binary, up and down.

 LIBRARY ieee;
 USE ieee.std_logic_1164.ALL;
 USE ieee.numeric_std.ALL;
 use ieee.std_logic_unsigned.all;
 USE ieee.std_logic_arith.all;

 entity counter is
 Port ( Clk : in std_logic;
 A_In : in std_logic;
 B_In : in std_logic;
 data_out : out std_logic_vector(11 downto 0);
 Reset : in std_logic);
 end counter;
 architecture Behavioral of counter is
 SIGNAL Last_A, Last_B :std_logic;
 SIGNAL Current_A, Current_B : std_logic;
 SIGNAL Dir :  std_logic;
 SIGNAL up_down : std_logic;
 SIGNAL count:std_logic_vector(11 downto 0) :="000000000000";


 begin
 up_down <= Current_A xor Last_A xor Current_B xor Last_B;
 Dir <= CURRENT_A xor Last_B;

 process (clk, Reset)
 begin
  if Reset = '1' then
   Last_A <= '0';
    Last_B <= '0';
     Current_A <= '0';
      Current_B <= '0';
      elsif rising_edge(clk) then
     Last_A <= Current_A;
    Last_B <= Current_B;
   Current_A <= A_In;
  Current_B <= B_In;
 end if;
end process;

 process (clk, Reset) begin
  IF (Reset = '1') THEN
   count <= "000000000000";
    ELSIF (clk'EVENT AND clk= '1')THEN
     if up_down ='1' then
     if(dir='1') then count<=count+1; else count<=count-1;
   end if;
 end if;
end if;

 data_out <= count;

 END PROCESS;
 end Behavioral;

Author: Chris (Guest)
Posted on:
Attached files:

Rate this post
0 useful
not useful
I cannot make this work for the life of me, I have one code to grab 
encoder info via bit banged spi, works perfect, I have another code now 
for quadrature encoder reading with index as reset, also works perfect. 
both codes output info on 12 led's, but I am unable to find a method to 
run the spi code once, then transfer the binary position to the 
quadrature count, I either get count doesn't hold value between clock 
edges or spi data is not used. Ive been on this for 2 weeks now, need 
your help.

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Chris wrote:
> counts perfectly from 0 to 4095 on 12 led's in binary, up and down.
But it is not a quadrature decoder.
How did you find out that this code works "perfectly"?
Think about a state, where both of those signals remain on '1' steadily. 
Meaning the encoder whell isn't turnig. What will happen when the clk 
continues clocking?


Add either the
USE ieee.numeric_std.ALL;
OR the
use ieee.std_logic_unsigned.all;
USE ieee.std_logic_arith.all;
But NEVER ever ALL of them together! NEVER!
You want to know why not?
Its easy: have a look inside the source code of those packages. Then you 
will see some double type definitions. In certain cases this can lead to 
very strange behaviour with some operaotrs, lead to very misleading 
error messages.
A hint from me: use the numeric_std ONLY. It has all one needs to 
convert from vectors to integer and backwards:
http://www.lothar-miller.de/s9y/categories/16-Numeric_Std

BTW: did you see the short "manual" a few lines above the edit box? No?
Let me copy and paste it:
Reply
Rules — please read before posting
   ...
Formatting options
    ...
    [vhdl]VHDL code[/vhdl]
Try it. Its magic!

Author: Chris (Guest)
Posted on:

Rate this post
0 useful
not useful
Add mentioned it counts binary on 12 leds that I have connected to the 
machx02 7000he board. And it works on a 50mhz clock

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Did you think about the steady state  I wrote about?

Author: Chris (Guest)
Posted on:

Rate this post
0 useful
not useful
not sure what you mean, when im not turning the magnet the output 
doesn't change as desired, it is a 12 bit quadrature encoder that counts 
binary 0 to 4095 up and down so im not sure why you keep asking?

Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
Ive been trying to load your examples and I cant even get it to start 
compiling, seems like it will not accept a variable in the process.

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Chris wrote:
> when im not turning the magnet the output doesn't change as desired
OK, you are Wright. Your code is working. In a little bit unusual and 
archaical way, but its working...

Then let's face the second problem: How to pass the 12 bit value to that 
SPI engine.


Chris C. wrote:
> Ive been trying to load your examples and I cant even get it to start
> compiling, seems like it will not accept a variable in the process.
Then something is not set up correctly. As far as I know from responses 
the code is running fine on several platforms.

Author: Chris Customchris (customchris)
Posted on:
Attached files:

Rate this post
0 useful
not useful
this is what im working with right now, sometimes it works upon powerup 
and sometimes it doesn't. Just to clear of coarse, upon start up I want 
to have my bit banged spi function grab the 12 most significant bits and 
store them, then pass that position info to the quadrature process for 
a/b/I to increment, decrement, or reset to zero and handle from here on 
out. the encoder has spi interface and qei running simultaneously, the 
spi output is 16 bits long, first bit or 2 I believe is just a parody 
bit, and I don't need the 14bit position so I grab the 12 out that I do 
want. spi setup mearly requires that mosi of the encoder is pulled high, 
pull CSpin low, wait min 350ns, then send a clock pulse, only grabing a 
data bit on falling edges.

the overall desired effect is to know the encoder position internally 
and externally for diagnostics to led's, then trigger 7 different 
outputs based on encoder position  and an input state.

Also if it helps this in being done in lattice diamond, I'm very new to 
vhdl/fpga as a project with minimum experience with arduino, all self 
taught by examples and tinkering, no training or courses.

: Edited by User
Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
Should I be using and integer for count instead of a std_logic_vector(11 
downto 0);?

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Chris C. wrote:
> Should I be using and integer for count instead of a std_logic_vector(11
> downto 0);?
You must not use unconstrined std_logic vectors for calculations. 
Instead you should use unsigned or signed vectors, or integers (as I 
would do).

But that's a minor problem. The major problem to be solved is the 
integration of those two modules together in one module.

And here I would add a third "top level" module with all the connection 
to the "outer world"(input for the encoder, and output of the SPI 
signals). In this third module the existing two must be integrated as 
components. Have a look there:
http://www.lothar-miller.de/s9y/archives/57-Sinusa...
There I have a top level module SinusPWM wherein two submodules 
(http://www.lothar-miller.de/s9y/categories/31-DDFS and 
http://www.lothar-miller.de/s9y/archives/54-PWM.html) are instantiated 
and connected. And then the DDFS supplies a sine value, which is passed 
over to the PWM unit, which output is a pulse train.

And now you will have to do something fairly similar with your two 
modules...

Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
Something tells me that there has to be a simpler way, like when the spi 
function has run once and the clock counter has over run back to zero 
the data is shifted into a buffer or inout or register, then start the 
quadrature with the count initialized with the value that was stored 
from the spi function. Then quadrature can increment or subtract that 
number while displayed to the led's.

: Edited by User
Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Chris C. wrote:
> sometimes it works upon powerup and sometimes it doesn't.
Thats the usual description coming from using asynchronous resets. 
Always...
Very easy solution: synchronize the reset (as every external 
asynchronous signal!) with at least two flipflops. Then use it inside 
your design.

All in all: its not a googd design practise to smash all of the tasks 
into one file and muddle with it criss-cross so one ever will be able to 
understand it.
Insted you have 2 functions (quadrature decoder and SPI) and each of 
them is tested and fully functional for itself in one module. Then you 
add a third module that invokes those two tested modules as components 
(as I already mentioned). The way you do it now ist a kludge.

Chris C. wrote:
> Something tells me that there has to be a simpler way, like when the spi
> function has run once and the clock counter has over run back to zero
> the data is shifted into a buffer or inout or register, then start the
> quadrature with the count initialized with the value that was stored
> from the spi function. Then quadrature can increment or subtract that
> number while displayed to the led's.
WHAT should the whole thing do at all?
You want to put in an count number via SPI?
And that number should be changed by the encoder?
That sound fairly useless to me. What is it good for?


BTW: as I see now you're going backwards to ancient milleniums...
library IEEE;
 --USE ieee.numeric_std.ALL;
 use ieee.std_logic_unsigned.all; 
 USE ieee.std_logic_arith.all;
Do it this way instead:
library IEEE;
USE ieee.numeric_std.ALL;
Of course you will have to do minor changes to your code...

BTW2: do you know about "identation"?
If so: why don't you use it?
If not: learn about it, its a neat thing!

: Edited by Moderator
Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
the encoder is replacing 3 hall sensors mounted to a rotating shaft on a 
gearbox, each sensor having its own set of pulses per rotation, im 
creating this encoder to replace these sensors, the goal is to replicate 
their output perfectly upon startup, this is why  the spi is important, 
I can obtain the absolute position on power up, then use the more 
precise and faster quadrature after.

 for the libraries I had tried to remove the 2 you mentioned and it did 
not work, but when I removed std.all it worked again, these are things 
im still learning, most of the libraries included where attached with 
the example code I had found.

  to recap, the encoder I am using has spi and quadrature A,B,and I 
outputs, naturally quadrature is running blind till index gives the 
reset signal to zero the count, I cannot have that in this design, which 
is why I want to know the start up absolute position.

As for separating the 2 different functions and invoking by a third is 
beyond my scope of knowledge but I am eager to learn it.

Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Chris C. wrote:
> for the libraries I had tried to remove the 2 you mentioned and it did
> not work
Of course it will not work. You will have to pull the code and the 
design style straight for the numeric_std (Conversions and casts). Then 
it will work perfectly...

> the encoder is replacing 3 hall sensors mounted to a rotating shaft on a
> gearbox, each sensor having its own set of pulses per rotation, im
> creating this encoder to replace these sensors, the goal is to replicate
> their output perfectly upon startup, this is why  the spi is important,
> I can obtain the absolute position on power up, then use the more
> precise and faster quadrature after.
So the port definition is not the final. Because for me it would look 
more this way:
   PORT(
            Clk   : in std_logic;

            -- encoder interface
            A_In  : in std_logic;
            B_In  : in std_logic;

            -- SPI interface
            SS    : out std_logic;
            SCLK  : out std_logic;
            MISO  : in  std_logic;

            -- emulated hall sensors
            Hall  : out std_logic_vector(2 downto 0)
       ); 
Is that correct?

Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
you got it.

I had to spend the last few hours just getting a 50mhz clock off of an 
old board, installing it on the machx02 board and finding out how to get 
it running, appearently the fpga enables the clock, I haven't found out 
how they do it, but I did notice that a pin that  should be high was 
low, so I followed it to the chip, got the pin number and wrote it high 
in the code and now its working again, it was too much of a mess having 
a external clock fed from on old large board. this kind of stuff is 
where my limited time gets stuck on and lost.

: Edited by User
Author: Lothar Miller (lkmiller) (Moderator)
Posted on:

Rate this post
0 useful
not useful
Why not using the clock on the MachXO board itself...

Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
we've found that the internal oscillators start very slow in the cold, 
this has to be operational below freezing, some of our other projects we 
have found by just simply freezing the test board in a food freezer was 
enough to affect startup performance and took to long to reach desired 
speed, the external crystal did not exhibit this flaw in our tests.

Author: Chris Customchris (customchris)
Posted on:

Rate this post
0 useful
not useful
Still no progress here, I've stuck with just the spi master code, trying 
to get the position on power up and locking it into the leds. I can get 
amazing updates when free running, but I cannot figure out how to get 
the system to run once and keep the position loaded to the leds. The 
code starts a counter, 10 milliseconds after power on chip select goes 
low, about 350ns later I start a clock out for sck, every falling edge I 
store data into a register from 15 down to 0, then 350ns after chip 
select goes high and I send the 12msb's of data to a register called 
count, from here I would like the code to stop and display the 12 bits 
onto the leds. Any advice?

Author: Chris Customchris (customchris)
Posted on:
Attached files:

Rate this post
0 useful
not useful
this is the latest running example.

Reply

Entering an e-mail address is optional. If you want to receive reply notifications by e-mail, please log in.

Rules — please read before posting

  • Post long source code as attachment, not in the text
  • Posting advertisements is forbidden.

Formatting options

  • [c]C code[/c]
  • [avrasm]AVR assembler code[/avrasm]
  • [vhdl]VHDL code[/vhdl]
  • [code]code in other languages, ASCII drawings[/code]
  • [math]formula (LaTeX syntax)[/math]




Bild automatisch verkleinern, falls nötig
Note: the original post is older than 6 months. Please don't ask any new questions in this thread, but start a new one.