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;
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
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;
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;
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.
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
1
USEieee.numeric_std.ALL;
OR the
1
useieee.std_logic_unsigned.all;
2
USEieee.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:
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?
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.
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.
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-Sinusausgabe-mit-PWM.html
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...
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.
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...
1
libraryIEEE;
2
--USE ieee.numeric_std.ALL;
3
useieee.std_logic_unsigned.all;
4
USEieee.std_logic_arith.all;
Do it this way instead:
1
libraryIEEE;
2
USEieee.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!
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.
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:
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.
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.
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?