Forum: FPGA, VHDL & Co. Frage zu variable counter : std_logic_vector(2 downto 0) := "100";


von Reinhard J. (rvj)


Lesenswert?

Hallo Forum,
ich bemühe mich derzeit in meinem ersten VHDL Projekt einen Zähler in 
einem Prozess zu implementieren. Ziel ist es zwei Encoder zu einem 
Strang zu addieren, wobei die Encoderfrequenz verringert wird.
Der Zähler soll mit "100", also dezimal 4, initialisiert werden. Bei 
"110", dezimal 6, wird ein Schritt vor erzeugt und der Zähler auf "100" 
zurückgestellt. Bei "010", dezimal 2, wird ein Schritt zurück erzeugt 
und dann zurück auf "100" gestellt.
Das sieht dann so aus:
1
  process(ce_1, ce_2) is
2
    variable state        :   std_logic_vector(1 downto 0);
3
    variable counter      :   std_logic_vector(2 downto 0) := "100";
4
    
5
  begin
6
    -- den ersten Kanal auswerten
7
    if  ( rising_edge(ce_1) )  then
8
      if (up_down_1 = '1' and error_1 = '0') then
9
        counter := counter + 1;
10
      elsif (up_down_1 = '0' and error_1 = '0') then
11
        counter := counter - 1;
12
      else
13
        counter := counter;
14
      end if;
15
    end if;
16
    -- den zweiten Kanal auswerten
17
    if  ( rising_edge(ce_2) )  then
18
      if (up_down_2 = '1' and error_2 = '0') then
19
        counter := counter + 1;
20
      elsif (up_down_2 = '0' and error_2 = '0') then
21
        counter := counter - 1;
22
      else
23
        counter := counter;
24
      end if;
25
    end if;
26
    -- zusammenfuehren der Kanaele: Es geht ein Schritt vor  
27
    if counter >= "110" then
28
      case state is
29
        when "10" =>  A_out <= '1'; B_out <= '1'; state := "11";     -- A high, B low  => A high, B high
30
        when "11" =>  A_out <= '0'; B_out <= '1'; state := "01";     -- A high, B high => A low, B high
31
        when "01" =>  A_out <= '0'; B_out <= '0'; state := "00";     -- A low, B high => A low, B low
32
        when "00" =>  A_out <= '1'; B_out <= '0'; state := "10";     -- A low, B low => A high, B low
33
        when others => null;
34
      end case;
35
      counter := counter - 2;
36
    end if;
37
    -- zusammenfuehren der Kanaele: Es geht ein Schritt zurueck  
38
    if counter <= "010" then
39
      case state is
40
        when "10" =>   A_out <= '0'; B_out <= '0'; state := "00";     -- A high, B low => A low, B low
41
        when "11" =>   A_out <= '1'; B_out <= '0'; state := "10";     -- A high, B high => A high, B low
42
        when "01" =>   A_out <= '1'; B_out <= '1'; state := "11";     -- A low, B high => A high, B high
43
        when "00" =>   A_out <= '0'; B_out <= '1'; state := "01";     -- A low, B low => A low, B high
44
        when others => null;
45
      end case; 
46
      counter := counter + 2;
47
    end if;
48
      
49
  end process;

Leider erhalte ich folgende Fehlermeldung:

Analyzing Entity <incremental_encoder_adder> in library <work> 
(Architecture <behavioral>).
ERROR:Xst:827 - 
"C:/Xilinx_Projects/EncoderAdder_02/incremental_encoder_adder.vhd" line 
50: Signal counter cannot be synthesized, bad synchronous description. 
The description style you are using to describe a synchronous element 
(register, memory, etc.) is not supported in the current software 
release.

Kann mir jemand sagen wie ich eine derartige Funktionalität 
implementieren kann?

Gruß Reinhard

von Gothaer (Gast)


Lesenswert?

Am besten bei sowas niemals die komplette Entity posten, damit man auch 
ja noch Arbeit hat, wenn man das selbst mal ausprobieren will.

Am besten auch nie irgendwelche Softwareversionen nennen, damit man 
nicht evtl. bekannten Probleme nennen kann.

Am besten auch nie mal selbst eine bekannte Suchmaschine bemühen. Lieber 
einfach fragen.

Ach! Hast Du ja schon. Na denn...

von Reinhard J. (rvj)


Lesenswert?

Hallo Gothaer,

erst mal Danke dass Du Dir das angeschaut hast. Nun zu Deinen Punkten:

Ich habe selbstverständlich bevor ich fragte auf einer Suchmaschine 
gesucht und nichts gefunden, was ich verstehen konnte. Ferner bin ich 
ohne Ergebnis durchs Forum gestreift. Da ich mit VHDL anfange mag ich 
das eine oder andere nicht erkannt haben.

Ich nutze Xilinx ISE Design Suite 13.4.

Und den ganzen Code habe ich unten eingefügt.

Gruß Reinhard
1
----------------------------------------------------------------------------------
2
-- Company: 
3
-- Engineer: 
4
-- 
5
-- Create Date:    19:49:45 11/24/2013 
6
-- Design Name: 
7
-- Module Name:    incremental_encoder_adder - Behavioral 
8
-- Project Name: 
9
-- Target Devices: 
10
-- Tool versions: 
11
-- Description: 
12
--
13
-- Dependencies: 
14
--
15
-- Revision: 
16
-- Revision 0.01 - File Created
17
-- Additional Comments: 
18
--
19
----------------------------------------------------------------------------------
20
library IEEE;
21
use IEEE.STD_LOGIC_1164.ALL;
22
use IEEE.NUMERIC_STD.ALL;
23
use IEEE.STD_LOGIC_UNSIGNED.ALL;
24
25
-- Uncomment the following library declaration if using
26
-- arithmetic functions with Signed or Unsigned values
27
--use IEEE.NUMERIC_STD.ALL;
28
29
-- Uncomment the following library declaration if instantiating
30
-- any Xilinx primitives in this code.
31
--library UNISIM;
32
--use UNISIM.VComponents.all;
33
34
35
36
entity incremental_encoder_adder is
37
    Port ( up_down_1   :   in    STD_LOGIC;
38
           ce_1       :   in    STD_LOGIC;
39
           error_1     :   in    STD_LOGIC;
40
           up_down_2   :   in    STD_LOGIC;
41
           ce_2       :   in    STD_LOGIC;
42
           error_2     :   in    STD_LOGIC;
43
           A_out       :   out    STD_LOGIC;
44
           B_out       :   out    STD_LOGIC);
45
end incremental_encoder_adder;
46
47
architecture Behavioral of incremental_encoder_adder is
48
49
begin
50
  process(ce_1, ce_2) is
51
    variable state        :   std_logic_vector(1 downto 0);
52
    variable counter      :   std_logic_vector(2 downto 0) := "100";
53
    
54
  begin
55
    -- den ersten Kanal auswerten
56
    if  ( rising_edge(ce_1) )  then
57
      if (up_down_1 = '1' and error_1 = '0') then
58
        counter := counter + 1;
59
      elsif (up_down_1 = '0' and error_1 = '0') then
60
        counter := counter - 1;
61
      else
62
        counter := counter;
63
      end if;
64
    end if;
65
    -- den zweiten Kanal auswerten
66
    if  ( rising_edge(ce_2) )  then
67
      if (up_down_2 = '1' and error_2 = '0') then
68
        counter := counter + 1;
69
      elsif (up_down_2 = '0' and error_2 = '0') then
70
        counter := counter - 1;
71
      else
72
        counter := counter;
73
      end if;
74
    end if;
75
    -- zusammenfuehren der Kanaele: Es geht ein Schritt vor  
76
    if counter >= "110" then
77
      case state is
78
        when "10" =>   A_out <= '1'; B_out <= '1'; state := "11";    -- A high, B low  => A high, B high
79
        when "11" =>  A_out <= '0'; B_out <= '1'; state := "01";     -- A high, B high => A low, B high
80
        when "01" =>  A_out <= '0'; B_out <= '0'; state := "00";     -- A low, B high => A low, B low
81
        when "00" =>  A_out <= '1'; B_out <= '0'; state := "10";     -- A low, B low => A high, B low
82
        when others => null;
83
      end case;
84
      counter := counter - 2;
85
    end if;
86
    -- zusammenfuehren der Kanaele: Es geht ein Schritt zurueck
87
    if counter <= "010" then
88
      case state is
89
        when "10" =>   A_out <= '0'; B_out <= '0'; state := "00";    -- A high, B low => A low, B low
90
        when "11" =>   A_out <= '1'; B_out <= '0'; state := "10";     -- A high, B high => A high, B low
91
        when "01" =>   A_out <= '1'; B_out <= '1'; state := "11";     -- A low, B high => A high, B high
92
        when "00" =>   A_out <= '0'; B_out <= '1'; state := "01";     -- A low, B low => A low, B high
93
        when others => null;
94
      end case; 
95
      counter := counter + 2;
96
    end if;
97
      
98
  end process;
99
100
end Behavioral;

von Reinhard J. (rvj)


Lesenswert?

Ergänzung:
Bei der um 11:57 eingefügten entity handelt es sich um eine component, 
die wie unten gezeigt als COMP3 arbeiten soll. Bei den component-en 
COMP1 und COMP2 handelt es sich um den VHDL Beispiel Code aus dem 
Artikel Drehgeber
http://www.mikrocontroller.net/articles/Drehgeber. Ich hoffe es wird 
klar, was mir als mein erstes VHDL Projekt vorschwebt.
1
        ---------------------------------------------
2
       |       -------               -------         |
3
A1 --> | A -->| COMP1 |--> upd1  -->|       |        |
4
B1 --> | B -->| DREH  |--> ce1   -->|       |        |
5
       |      | GEBER |--> err1  -->|       |        |
6
       |       -------              |       |        |
7
       |        ^                   |       |        |
8
       |        |                   | COMP3 |--> Aout|--> A3
9
clk -> | -------                    | ADDER |        |
10
       |        |                   |       |--> Bout|--> B3
11
       |        v                   |       |        |
12
       |       -------              |       |        |
13
A2 --> | A -->| COMP2 |--> upd2  -->|       |        |
14
B2 --> | B -->| DREH  |--> ce2   -->|       |        |
15
       |      | GEBER |--> err2  -->|       |        |
16
       |       -------              |       |        |
17
       |                             -------         |
18
        ---------------------------------------------

: Bearbeitet durch Moderator
von Christian R. (supachris)


Lesenswert?

Hm, also erst mal wird das so nicht richtig klappen, da deine Prozesse 
nicht mit dem Takt gesteuert werden, sondern mit dem CE des 
Drehgeber-Dekoders.
Wäre es insgesamt nicht sinnvoller, zwei Zähler zu beschreiben, dann die 
Summe auszurechnen und diese Summe dann im 2-Bit Gray-Code auszugeben? 
Aber so 100% klar ist mir dein Vorhaben nicht, muss ich zugeben.

von Reinhard J. (rvj)


Lesenswert?

Hallo Christian,

Danke für die Antwort.

Du hast mein Vorhaben durchschaut. Ich will die steigenden Flanken der 
CEs ausnutzen, um die Summe zu bilden und daraus ein neues 
Drehgebersignal bauen.

Folgende Anwendung hatte ich bereits in AVR Assembler gebastelt:

1. Ein Zweiachsenteleskopantrieb mit zwei Motorencodereinheiten fahren 
in die gleiche Richtung.
2. Beide bewegen sich manhmal zusammen und manchmal alleine.
3. Zur Positionsauswertung benötige ich aber eine Encoderpulsfolge, die 
die Gesamtbewegung wiedergibt.

Mit AVRs komme ich bei schnellen Pulsraten ins Schlingern. Darum habe 
ich die Anwendung auf mehrere AVRs verteilt.
Vom Artikel Drehgeber 
http://www.mikrocontroller.net/articles/Drehgeber. inspiriert versuche 
ich nun mein Glück in VHDL. VHDL wird eine harte Nuss für mich.

Deinen Lösungsansatz mit den zwei Zählern verstehe allerdings nicht.

Vielleicht sollte die component COMP3 ADDER auch mit clk versorgen und 
auf die CEs abfragen. In meiner Frage Fragen zum VHDL Drehgeber Code 
Beitrag "Fragen zum VHDL Drehgeber Code" lernte ich, dass up_down 
aus dem Drehgeber http://www.mikrocontroller.net/articles/Drehgeber 
code für einen Takt auf '1' steht. Ich probiere das und beschreibe hier 
das Ergebnis.

Mit meiner ursprünglichen Frage wollte ich eigentlich nur wissen, warum 
ich den Fehler

ERROR:Xst:827 -
"C:/Xilinx_Projects/EncoderAdder_02/incremental_encoder_adder.vhd" line
50: Signal counter cannot be synthesized, bad synchronous description.
The description style you are using to describe a synchronous element
(register, memory, etc.) is not supported in the current software
release.

kassiere.

Gruß und nochmals Danke
Reinhard

von Achim S. (Gast)


Lesenswert?

Reinhard J. schrieb:
> Du hast mein Vorhaben durchschaut. Ich will die steigenden Flanken der
> CEs ausnutzen

das macht man Logikbausteinen nicht so. Der folgende Block erzeugt 
einiges an kombinatorischer Logik (für den if - then - elseif Teil) und 
führt das über ein taktflankengesteuertes Flipflop, das von ce_1 
getaktet wird
(if rising_edge(ce1)).

Reinhard J. schrieb:
> if  ( rising_edge(ce_1) )  then
>       if (up_down_1 = '1' and error_1 = '0') then
>         counter := counter + 1;
>       elsif (up_down_1 = '0' and error_1 = '0') then
>         counter := counter - 1;
>       else
>         counter := counter;
>       end if;
>     end if;

Der darauf folgende Block

Reinhard J. schrieb:
> if  ( rising_edge(ce_2) )  then
>       if (up_down_2 = '1' and error_2 = '0') then
>         counter := counter + 1;
>       elsif (up_down_2 = '0' and error_2 = '0') then
>         counter := counter - 1;
>       else
>         counter := counter;
>       end if;
>     end if;

sagt dann, dass der Takteingang des Flipflops mit einem anderen Takt 
(ce_2) zu verbinden ist. Das geht nicht (das Flipflop hat nur einen 
Takteingang), daher die Meldung "bad synchronous design".


Such dir stattdessen eine einziges sauberes und hinreichend schnelles 
Taktsignal (z.B. 50 MHz von einem Quarz) und Lass deine ganze Logik 
synchron mit diesem Takt laufen.

Betrachte die Eingänge CE1 und CE2 nicht als Takt sondern als externe 
Eingänge, die erst mit dem 50MHz Takt einsynchronisiert werden müssen, 
bevor du sie weiter verwendest. Dann kannst du (wenn du das wirklich 
willst) auf den einsynchronisierten Signalen z.B. eine Flankenerkennung 
machen. Ich würde aber den Vorschlag von supachris folgen und zwei 
unabhängig Zähler implementieren, deren Summe ausgewertet wird.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Reinhard J. schrieb:
> in meinem ersten VHDL Projekt
Und das fängt schon mal gut an:
1
   variable state        :   std_logic_vector(1 downto 0);
2
   variable counter      :   std_logic_vector(2 downto 0) := "100";
Siehe den Beitrag "Variable vs Signal"


Und gleich danach 2 Takte, die auf das selbe Flipflop gehen:
1
    if  ( rising_edge(ce_1) )  then ...
2
        counter := counter + 1;
3
    ...
4
    if  ( rising_edge(ce_2) )  then ...
5
        counter := counter + 1;
Wie soll den so ein Bauteil mit 2 Takteingängen aussehen?
Daher kommt übrigens auch deine Fehlermeldung:
> Signal counter cannot be synthesized, bad synchronous description.
Es ist prinzipiell ganz, ganz böse (und vor allem unnötig), zwei Takte 
in einen Prozess reinzubringen...

Auch wenn deine Beschreibung "funktionieren" würde, hättest du laufend 
Probleme mit metastabilen Zuständen und/oder unterschiedlichen 
Laufzeiten im FPGA:
http://www.lothar-miller.de/s9y/categories/35-Einsynchronisieren

Und dann frei nach dem Motto "Viel hilft viel":
1
use IEEE.STD_LOGIC_1164.ALL;
2
use IEEE.NUMERIC_STD.ALL;
3
use IEEE.STD_LOGIC_UNSIGNED.ALL;
In den beiden Libs kommen so einige Definitionen doppelt vor (z.B. der 
Datentyp unsigned), das kann eigenartige Effekte hervorrufen.
Und da hätten wir den Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"

> Ich hoffe es wird klar, was mir als mein erstes VHDL Projekt vorschwebt.
Was hältst du denn davon, mit einer blinkenden LED anzufangen, dann ein 
Lauflicht, dann ... und dann die Geberauswertung eines Gebers. Und dann 
die Berechnung dessen, was du willst...
Ich kapiere übrigens meine Geberauswertung besser: 
http://www.lothar-miller.de/s9y/categories/46-Encoder  ;-)

> Ziel ist es zwei Encoder zu einem Strang zu addieren, wobei die
> Encoderfrequenz verringert wird.
> Das sieht dann so aus:
Zeig doch mal mit einem Bildchen, wie das aussehen könnte...
Welche Frequenzen kommen von deinen Gebern maximal? Kann mit die z.B. 
mit 50MHz überabtasten und dann auswerten. Dann wäre die Sache nämlich 
mit 1 Takt und ganz bequem zu erledigen. "Warum nur 1 Takt?" fragst du? 
Such hier im Forum mal nach meinen Postulaten...  ;-)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.