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
:
Edited by Moderator
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 | USE ieee.numeric_std.ALL; |
OR the
1 | use ieee.std_logic_unsigned.all; |
2 | 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:
1 | Reply |
2 | Rules — please read before posting |
3 | ... |
4 | Formatting options |
5 | ... |
6 | [vhdl]VHDL code[/vhdl] |
Try it. Its magic!
Add mentioned it counts binary on 12 leds that I have connected to the machx02 7000he board. And it works on a 50mhz clock
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?
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.
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.
:
Edited by User
Should I be using and integer for count instead of a std_logic_vector(11 downto 0);?
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.
:
Edited by User
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 | library IEEE; |
2 | --USE ieee.numeric_std.ALL;
|
3 | use ieee.std_logic_unsigned.all; |
4 | USE ieee.std_logic_arith.all; |
Do it this way instead:
1 | library IEEE; |
2 | 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
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:
1 | PORT( |
2 | Clk : in std_logic; |
3 | |
4 | -- encoder interface
|
5 | A_In : in std_logic; |
6 | B_In : in std_logic; |
7 | |
8 | -- SPI interface
|
9 | SS : out std_logic; |
10 | SCLK : out std_logic; |
11 | MISO : in std_logic; |
12 | |
13 | -- emulated hall sensors
|
14 | Hall : out std_logic_vector(2 downto 0) |
15 | );
|
Is that correct?
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
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?
Please log in before posting. Registration is free and takes only a minute.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
Log in with Google account
No account? Register here.