Forum: FPGA, VHDL & Co. VHDL inout Problem


von Pit (Gast)


Lesenswert?

Hallo,

ich habe einen CPLD mit 4 Pins (Mini-CPLD) und möchte darüber Lesen und 
Schreiben.

Hier der Code:
1
entity TEST1 is
2
  Port 
3
  ( 
4
    DATA_INOUT  : inout STD_LOGIC_VECTOR (3 downto 0);
5
    CLK       : in STD_LOGIC
6
  );
7
end TEST1;
8
9
architecture Behavioral of TEST1 is
10
11
  signal DATA_IN    : STD_LOGIC_VECTOR (3 downto 0);
12
  signal DATA_OUT  : STD_LOGIC_VECTOR (3 downto 0);
13
  signal COUNTER    : STD_LOGIC_VECTOR (3 downto 0);
14
  signal MAX_COUNT  : STD_LOGIC_VECTOR (3 downto 0);
15
16
  signal READ_DATA  : STD_LOGIC;
17
18
begin
19
20
  process (CLK) 
21
  begin
22
    if rising_edge(CLK) then
23
      COUNTER <= STD_LOGIC_VECTOR(unsigned(COUNTER) + 1);
24
      
25
      if COUNTER = "0000" then
26
        READ_DATA <= '0';
27
        DATA_OUT <= "1010";
28
        if MAX_COUNT = "1111" then
29
          MAX_COUNT <= "0000";
30
        end if;
31
      else
32
        READ_DATA <= '1';
33
        MAX_COUNT <= DATA_IN;
34
      end if;
35
    end if;
36
  end process;
37
38
  process(READ_DATA, DATA_OUT)
39
  begin
40
    if READ_DATA = '1' then
41
      DATA_INOUT <= ( others => 'Z' );
42
      DATA_IN <= DATA_INOUT;
43
    else
44
      DATA_INOUT <= DATA_OUT;
45
    end if;
46
  end process;
47
48
end Behavioral;

Wenn ich das nun hiermit simuliere, dann geht DATA_INOUT auf konstante 
'1001' und DATA_IN bzw. DATA_OUT bleiben chronisch auf 'undefined':
1
ENTITY tb_TEST1 IS
2
END tb_TEST1;
3
 
4
ARCHITECTURE behavior OF tb_TEST1 IS 
5
 
6
    -- Component Declaration for the Unit Under Test (UUT)
7
 
8
    COMPONENT TEST1
9
    PORT(
10
         DATA_INOUT : INOUT  std_logic_vector(3 downto 0);
11
         CLK : IN  std_logic
12
        );
13
    END COMPONENT;
14
    
15
16
   --Inputs
17
   signal CLK : std_logic := '0';
18
19
  --BiDirs
20
   signal DATA_INOUT : std_logic_vector(3 downto 0);
21
22
   -- Clock period definitions
23
   constant CLK_period : time := 10 ns;
24
 
25
BEGIN
26
 
27
  -- Instantiate the Unit Under Test (UUT)
28
   uut: TEST1 PORT MAP (
29
          DATA_INOUT => DATA_INOUT,
30
          CLK => CLK
31
        );
32
33
   -- Clock process definitions
34
   CLK_process :process
35
   begin
36
    CLK <= '0';
37
    wait for CLK_period/2;
38
    CLK <= '1';
39
    wait for CLK_period/2;
40
   end process;
41
 
42
43
   -- Stimulus process
44
   stim_proc: process
45
   begin    
46
      -- hold reset state for 100 ns.
47
      wait for 100 ns;  
48
49
      wait for CLK_period*10;
50
51
      -- insert stimulus here 
52
    DATA_INOUT <="1001" after 100 ns;
53
    
54
      wait;
55
   end process;
56
57
END;

Warum werden DATA_IN bzw. DATA_OUT nicht zugewiesen?

Danke Pit

von P. K. (pek)


Lesenswert?

Beim zweiten Prozess hast Du mal sicher eine unvollständige 
Sensitivity-Liste (DATA_INOUT fehlt). Würde das eh concurrent machen, 
etwa in dieser Art:
1
  DATA_IN     <= DATA_INOUT;
2
  DATA_INOUT  <= 'Z' when READ_DATA = '1' else DATA_OUT;

von bko (Gast)


Lesenswert?

Welchen Wert hat "COUNTER" in deiner Simulation?
Ich meine da fehlt entweder ein Reset oder ein init-wert.

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


Lesenswert?

bko schrieb:
> Welchen Wert hat "COUNTER" in deiner Simulation?
> Ich meine da fehlt entweder ein Reset oder ein init-wert.
Du meinst richtig. Denn "UUUU"+1 ergibt "UUUU".

Pit schrieb:
> COUNTER <= STD_LOGIC_VECTOR(unsigned(COUNTER) + 1);
Nimm zum zählen doch besser einen integer, dann wird das viel 
übersichtlicher und du kannst auf "normale Zahlen" vergleichen. Oder 
mach ihn wenigstens unsigned, wenn du den (impliziten) Überlauf nach 
16 Takten brauchst. Dann steht da:
1
  signal COUNTER    : unsigned (3 downto 0) := "0000";
2
3
begin
4
  process (CLK) 
5
  begin
6
    if rising_edge(CLK) then
7
      COUNTER <= COUNTER + 1;
8
      
9
      if COUNTER = "0000" then
10
        READ_DATA <= '0';
oder gar
1
  signal COUNTER    : integer range 0 to 15 := 0;
2
3
begin
4
  process (CLK) 
5
  begin
6
    if rising_edge(CLK) then
7
      if counter<15 then counter <= counter + 1; -- falls Überlauf interessant
8
      else               counter <= 0;
9
      end if;
10
      
11
      if COUNTER = 0 then
12
        READ_DATA <= '0';


> Hier der Code:
Nimm zum Posten von VHDL-Code besser [vhdl] statt [pre]

Und: schreib Signalnamen klein, evtl. mit einem großen 
Anfangsbuchstaben, DENN SONST BEKOMMST DU BALD DIE KRÄTZE ANS AUGE, UND 
DU MUSST JEDES WORT ZWEIMAL LESEN, WEIL DAS GEHIRN DIESE DAUERNDE 
GROSSSCHREIBEREI NICHT GEWÖHNT IST.

von Pit (Gast)


Lesenswert?

Erstmal Danke für die Tipps. Ich probiere das auch gleich mal alles aus. 
Aber irgendwie werd ich das Gefühl nicht los, daß ich ein ganz anderes 
Problem habe.

Folgendes ist Zweck der Übung:
Gegeben sind vier Pins, die als inout definiert sind. Innerhalb der 
StateMAchine soll genau einmal von diesen Pins gelesen werden. Der 
gelesene Wert soll gespeichert werden und dann innerhalb der 
StateMAchine im weiteren Verlauf als Konstante verwendet werden.
Nachdem dieser Wert (die Konstante) gelesen wurde, schalten alle Pins 
auf Ausgang, d.h. ab sofort werden über die Pins nur noch Werte 
ausgegeben.

Mein Problem ist, egal was ich mache, entweder lese ich nur 'UUUU' von 
den Pins oder die gewünschte Konstante wechselt den Wert, sobald ich 
Anfange Werte über die Pins auszugeben.

Mein prinzipielles Vorgehen:
-STEP0 (Konstante einlesen):
INOUT <= "ZZZZ"
KONSTANTE <= INOUT

-STEP1 (Konstante verwenden):
if KONSTANTE = "1010" then
  INOUT <= "1111"
else
  INOUT <= "0000"
end if

Naja, wie gesagt da kommt nur Käse dabei raus.

von Eike (Gast)


Lesenswert?

Hey,
nur so am Rande, solltest du nicht VOR dem Auslesen der inouts diese auf 
'Z' setzen? (mind. 1 takt vorher?) Wenn mich nicht alles täuscht 
passiert das bei dir alles beim selben Takt, bzw beim READ_DATA'event 
... Ich bin selber nicht so vertraut damit, ich simuliere es mal eben

von Eike (Gast)


Lesenswert?

Hmm, scheint auch so zu gehen. Kann mir jemand in einem Satz erklären 
warum?

Bleiben wir aber beim Thema, also bei mir funktioniert es (es tut 
zumindest etwas, ob es das Richtige ist... naja), sofern ich dem counter 
nen Startwert gebe und in der Testbench mit 'H' und 'L' arbeite, 
anstelle von '0' und '1'. Ich meine H/L bedeuten soviel wie externe 
PullUps / Pulldowns, kollidiert also nicht mit einem entgegengesetztem 
internen Zusatnd (wenn inout nicht als Eingang arbeitet). Glaube so war 
das, oder?

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


Lesenswert?

Pit schrieb:
> Mein Problem ist, egal was ich mache, entweder lese ich nur 'UUUU' von
> den Pins oder die gewünschte Konstante wechselt den Wert, sobald ich
> Anfange Werte über die Pins auszugeben.
Mein Glückwunsch, du hast die Latency entdeckt.
Das hier
        READ_DATA <= '1';
        MAX_COUNT <= DATA_IN;
bedeutet in der Hardware:
Genau mit dem oder gar wegen dem nächsten Takt wird MAX_COUNT 
eingelesen, und ein paar ps später (Signallaufzeit bis zum 
Ausgangstreiber) wird der Eingang hochohmig geschaltet.

Pit schrieb:
> DATA_OUT nicht zugewiesen?
Läuft dein Zähler?
Wird der irgendwann mal "0000"?

Pit schrieb:
> Mein Problem ist, egal was ich mache, entweder lese ich nur 'UUUU' von
> den Pins oder die gewünschte Konstante wechselt den Wert, sobald ich
> Anfange Werte über die Pins auszugeben.
Screenshot möglich?

von Pit (Gast)


Lesenswert?

Die gute Nachricht vorab: Es macht was ich will.

>Welchen Wert hat "COUNTER" in deiner Simulation?
und
>Du meinst richtig. Denn "UUUU"+1 ergibt "UUUU".
Ich dacht, es ist egal, ob ich da was initialisiere oder nicht, da ich 
den Wert erst nach der ersten Zuweisung verwende. Falsch gedacht.

>und in der Testbench mit 'H' und 'L' arbeite
Das hilft, da ich nach dem Einlesen nur noch den Ausgangstreiber habe. 
Änderung in der Testbench von
1
DATA_INOUT <="1001" after 100 ns;
auf
1
DATA_INOUT <="1001" after 100 ns, "HHHH" after 200 ns;

Fragen bleiben trotzdem. So wie im folgenden habe ich es jetzt und so 
funktioniert es.
1
process (CLK,...)
2
  if enable = '1' then
3
    if busy = '0' then
4
      if my_constant = 0 then
5
        my_constant <= to_integer(unsigned(data_in));
6
      end if;
7
8
      busy <= '1';
9
      data_read = '0';
10
11
    else --busy
12
      --StateMAchine mit verschiedenen data_out -Zuweisungen unter Verwendung von my_constant
13
      ...
14
    end if; --busy
15
  else --enable
16
    my_constant = 0;
17
    data_read = '1';
18
19
  end if; --enable
20
end process;
21
22
data_in <= data_inout;
23
24
process(data_read, data_out, data_inout)
25
begin
26
  if data_read = '1' then
27
    data_inout <= ( others => 'Z' );
28
  else
29
    data_inout <= data_out;
30
  end if;
31
end process;

Fragen bleiben trotzdem:
1. Wenn ich die Prüfung auf 'my_constant = 0' vor der Zuweisung von 
my_constant weglasse, dann erhalte ich wieder nur Käse für my_constant. 
Warum? Etwa deshalb, weil my_constant fest verdrahtet mit data_in ist? 
Also nicht so wie beim Programmieren, wo nur bei der Zuweisung der Wert 
geändert wird? Ich frage deshalb, weil der Zuweisungspfad ja in jedem 
Fall nur einmal durchlaufen wird.

2. Wenn ich den zweiten Prozess wie folgt ändere, funktioniert das Ganze 
auch (die Zeile 'data_in <= data_inout;' ist jetzt innerhalb des 
Prozesses).
1
process(data_read, data_out, data_inout)
2
begin
3
  if data_read = '1' then
4
    data_inout <= ( others => 'Z' );
5
    data_in <= data_inout;
6
  else
7
    data_inout <= data_out;
8
  end if;
9
end process;
Aber ich erhalte eine Warnung von wegen Latch und so und man sollte das 
vermeiden. Wie relevant ist diese Warnung und was hat das zu bedeuten?

Und natürlich Danke für Eure Hilfe!

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.