Forum: FPGA, VHDL & Co. Bidirektionaler I/O will nicht


von Fabian S. (jacky2k)


Lesenswert?

Hallo,
ich versuche gerade einen bidirektionalen I/O zu realisieren (es geht 
letztlich um 1-wire), jedoch macht VHDL nicht so wie ich will ;)
Hier die Kurzfassung meines Codes:
1
entitiy onewirebit is
2
  port(
3
    CLK : in bit;
4
    dq : inout std_logic;
5
    invalue : out bit;
6
    -- ...
7
  );
8
end onewirebit;
9
10
architecture Behavioral of onewirebit is
11
signal dq_outvalue : bit;
12
signal dq_invalue : bit;
13
-- ...
14
begin
15
  process(CLK)
16
  begin
17
    if CLK='1' and CLK'event then
18
      -- ...
19
      invalue <= dq_invalue;
20
      -- ...
21
    end if;
22
  end process;
23
24
  process(dq_outvalue, dq)
25
  begin
26
    if dq_outvalue = '1' then
27
      dq <= 'Z';
28
    else
29
      dq <= '0';
30
    end if;
31
    if dq='0' then
32
      dq_invalue <= '0';
33
    else
34
      dq_invalue <= '1';
35
    end if;
36
  end process;
37
end Behavioral;

So, hoffe das ist einigermaßen verständlich. Im synchronen Teil setze 
ich mit dq_outvalue ob der Pin hochohmig oder Low sein soll, das 
funktioniert auch soweit. Jetzt hätte ich gerne in dq_value den 
aktuellen Wert des Busses, egal ob ich den nun nach Masse ziehe oder 
nicht.
Zwei Probleme: Auf was steht dq jeweils? Und warum bekomme ich im Moment 
diese Warnung?
1
WARNING:Xst:1710 - FF/Latch <invalue> (without init value) has a constant value of 0 in block <onewirebit>. 
2
This FF/Latch will be trimmed during the optimization process.
3
WARNING:Xst:1348 - Unit onewirebit is merged (output interface has tristates)

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


Lesenswert?

Fabian S. schrieb:
>     CLK : in bit;
>     dq : inout std_logic;
>     invalue : out bit;
Wieso denn der Mischbetrieb?
Verwende doch einfach wie der Rest der Welt nur std_logic und dessen 
Vektoren...

Nehmen wir mal deine Beschreibung
1
  process(dq_outvalue, dq)
2
  begin
3
    if dq_outvalue = '1' then
4
      dq <= 'Z';
5
    else
6
      dq <= '0';
7
    end if;
8
    if dq='0' then
9
      dq_invalue <= '0';
10
    else
11
      dq_invalue <= '1';
12
    end if;
13
  end process;
und machen eine funktionsgleiche Umstellung
1
  dq <= 'Z' when dq_outvalue = '1' else '0';
2
  dq_invalue <= '0' when dq='0' else '1';
du hast da m.E. eine Macke in der Umschaltung...
Ein bidirektionaler Pin hat 3 Signale:
Eingangswert, Ausgangswert und Richtung.
Dir fehlt eines davon... :-o

Das wäre ein Tristate-Port:
1
:
2
    dq : inout std_logic;
3
:
4
signal dq_outvalue : std_logic;
5
signal dq_invalue  : std_logic;
6
signal dq_dir      : std_logic;
7
:
8
  dq <= dq_outvalue when dq_dir='1' else 'Z';
9
  dq_invalue <= dq;
10
:
Und jetzt kannst du mit dq_outvalue und dq_invalue arbeiten...

von Fabian S. (jacky2k)


Lesenswert?

Gegenfrage: Was für ein Mischbetrieb?
invalue hat jetzt damit direkt erstmal nichts zu tun, dass ist nur ein 
"Rückgabewert" an die höher gestellte entity.
Und warum sollte ich nen vollen Tri-State Pin definieren wenn ich davon 
nur die hälfte brauche? Der soll ja als Open-Drain arbeiten. Also 
brauche ich Z, 0 und Eingang.

Und es bleibt die Frage: Wenn dq auf 'Z' steht und ich lese dq, was 
kommt dann da raus? 1 und 0? H und L? Z? Oder was? Und was kommt da raus 
wenn ich dq auf 0 stehen habe?

Edit: Wenn ich das verwende:
1
dq <= 'Z' when dq_outvalue='1' else '0';
Bekomme ich diesen Fehler:
1
Line 102. parse error, unexpected WHEN, expecting SEMICOLON

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


Lesenswert?

Fabian S. schrieb:
> Gegenfrage: Was für ein Mischbetrieb?
bit und std_logic
Wie ich schon im
Lothar Miller schrieb:
>> Verwende doch einfach wie der Rest der Welt nur std_logic und dessen
>> Vektoren...


Fabian S. schrieb:
> Und warum sollte ich nen vollen Tri-State Pin definieren wenn ich davon
> nur die hälfte brauche? Der soll ja als Open-Drain arbeiten. Also
> brauche ich Z, 0 und Eingang.
Also, das ist ja nicht schwierig, das hattest du tatsächlich schon...

Ich würde allerdings die dominante '0' vorrangig beschreiben:
1
:
2
    dq : inout std_logic;
3
:
4
signal dq_outvalue : std_logic;
5
signal dq_invalue  : std_logic;
6
:
7
  dq <= '0' when dq_outvalue='0' else 'Z';
8
  dq_invalue <= dq;
9
:

Damit ist es wie so oft:
Das Problem liegt offenbar nicht im geposteten Code...

Fabian S. schrieb:
> Und es bleibt die Frage:
> Wenn dq auf 'Z' steht und ich lese dq, was kommt dann da raus?
Das, was jemand anders von aussen auf das Signal treibt.
Wenn keiner was treibt, dann 'Z'.

EDIT:
Fabian S. schrieb:
> Edit: Wenn ich das verwende:
Das ist ein Concurrent Statement.
Das geht nur ausserhalb eines Prozesses.

von Fabian S. (jacky2k)


Lesenswert?

> Lothar Miller schrieb:
>>> Verwende doch einfach wie der Rest der Welt nur std_logic und dessen
>>> Vektoren...
Aso, ne das kann ich nicht machen, unserem Prof ist das sehr wichtig, 
dass überall da wo es geht nur bit verwendet wird weil das seiner 
Meinung nach schneller ist und weniger Fehler verursacht. Also da komme 
ich nicht drum rum.

> Also, das ist ja nicht schwierig, das hattest du tatsächlich schon...
Das das nicht schwierig ist steht hier nicht zur Debatte, warum geht es 
nicht anders?

> Damit ist es wie so oft:
> Das Problem liegt offenbar nicht im geposteten Code...
Das habe ich eben auch festgestellt. Hier nochmal der aktuelle komplette 
Code:
1
library IEEE;
2
use IEEE.STD_LOGIC_1164.all;
3
use IEEE.STD_LOGIC_ARITH.all;
4
use ieee.numeric_std.all;
5
use IEEE.STD_LOGIC_UNSIGNED.ALL;
6
7
-- 
8
-- onewirebit
9
-- onewirebit is the implementation of the lowest protocol
10
-- layer, the bit layer. This entity is able to send bit to
11
-- the bus and receive bity from the bus.
12
--
13
14
entity onewirebit is
15
  port(
16
    CLK : in bit;         -- system clock
17
    dq : inout std_logic;   -- route this to the physical pin connected to the onewire bus
18
    reset : in bit;       -- set this bit to '1' to send a reset condition, if a slave is present invalue will be set to '1', otherwise to '0'
19
    writing : in bit;     -- set this bit to '1' to start write process, one clock later clear this bit, after that for finished becoming '1'
20
    outvalue : in bit;    -- set this bit to the value to be written to the bus. Do not change this value while the entity is writing this value!
21
    readbit : in bit;     -- set this bit to '1' to read a bit from the bus
22
    invalue : out bit;    -- after finishing the readbit command, the readed value can be read here. Alternative it is used for the return value of reset.
23
    finished : out bit    -- after setting writing or readbit to '1' wait after one cycle for this bit to become '1' again
24
  );
25
end onewirebit;
26
27
architecture Behavioral of onewirebit is
28
type states is (state_idle, state_reset0, state_reset1, state_reset2, state_wb, state_rb0, state_rb1, state_finished);
29
signal state : states := state_idle;
30
signal timer : std_logic_vector (31 downto 0) := (others=>'0');
31
signal dq_outvalue : bit;
32
signal dq_invalue : bit;
33
begin
34
  process(CLK)
35
  begin
36
    if CLK='1' and CLK'event then
37
      timer <= timer + '1';  -- increment the timer each cycle
38
      --invalue <= dq_invalue;
39
      case state is
40
        when state_idle =>
41
          dq_outvalue <= '1';
42
          finished <= '1';
43
          if writing='1' then -- there is a new bit to be written to the bus
44
            state <= state_wb;
45
            timer <= (others => '0');  -- reset the timer for the next state
46
            finished <= '0';
47
            dq_outvalue <= '0';  -- pull down the line
48
          elsif reset='1' then -- there is a reset to be executed
49
            state <= state_reset0;
50
            finished <= '0';
51
            timer <= (others => '0');  -- reset the timer for the next state
52
            dq_outvalue <= '0';  -- pull down the line
53
          elsif readbit='1' then
54
            state <= state_rb0;
55
          end if;
56
        when state_reset0 => -- wait fore reset time (500µs) to be over
57
          if timer=std_logic_vector(to_unsigned(8000,timer'length)) then
58
            state <= state_reset1;
59
            timer <= (others => '0');  -- reset the timer for the next state
60
            dq_outvalue <= '1'; -- release the line
61
          end if;
62
        when state_reset1 => -- the reset command has been sent, wait for slave responses after 70µs
63
          if timer=std_logic_vector(to_unsigned(1120,timer'length)) then
64
            invalue <= dq_invalue;
65
            state <= state_reset2;
66
            timer <= (others => '0');  -- reset the timer for the next state
67
          end if;
68
        when state_reset2 => -- the response has been recorded, wait for rising edge on the bus
69
          if dq_invalue='1' then
70
            state <= state_idle;  -- go back to the idle state
71
          end if;
72
        when state_wb =>  -- the line is pulled low, pull it up after 10µs or 65µs µs, depending on outvalue
73
          -- this two conditions could be made in one
74
          -- outvalue should be buffered
75
          if outvalue='1' and timer=std_logic_vector(to_unsigned(160,timer'length)) then -- when 10µs passed, release the line to write a logic one
76
            dq_outvalue <= '1';
77
            state <= state_finished;
78
            timer <= (others => '0');  -- reset the timer for the next state
79
          elsif outvalue='0' and timer=std_logic_vector(to_unsigned(1040,timer'length)) then  -- when 65µs passed, release the line to write a logic zero
80
            dq_outvalue <= '1';
81
            timer <= (others => '0');  -- reset the timer for the next state
82
            state <= state_finished;
83
          end if;
84
        when state_rb0 =>
85
        when state_rb1 =>
86
        when state_finished =>  -- wait 20µs for recovery and make shure the line is high (should be 2µs)
87
          dq_outvalue <= '1';
88
          if timer=std_logic_vector(to_unsigned(320,timer'length)) then
89
            state <= state_idle;
90
            finished <= '1';
91
          end if;
92
      end case;
93
    end if;
94
  end process;
95
  
96
  process(dq_outvalue, dq)
97
  begin
98
    if dq_outvalue = '1' then
99
      dq <= 'Z';
100
    else
101
      dq <= '0';
102
    end if;
103
    --dq <= 'Z' when dq_outvalue='1' else '0';
104
    --if dq='0' then
105
    --  dq_invalue <= '0';
106
    --else
107
    --  dq_invalue <= '1';
108
    --end if;
109
    --dq_invalue <= '0' when dq='0' else '1';
110
  end process;
111
  dq_invalue <= to_bit(dq);
112
end Behavioral;

> Das, was jemand anders von aussen auf das Signal treibt.
> Wenn keiner was treibt, dann 'Z'.
Ähhh aber der kann wohl kaum zwischen einem Pull-Up und einem High 
Strong Drive unterscheiden? Also lese ich dort IMMER 0, 1 oder Z? Aber 
woher soll er erkennen ob das Z ist? Irgend ein Pegel wird das Signal ja 
immer haben...


Edit: Ups, vergessen... Es bestehen weiterhin folgende Warnungen:
1
WARNING:Xst:1710 - FF/Latch <invalue> (without init value) has a constant value of 0 in block <onewirebit>. This FF/Latch will be trimmed during the optimization process.
2
WARNING:Xst:1348 - Unit onewirebit is merged (output interface has tristates)

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


Lesenswert?

Fabian S. schrieb:
> unserem Prof ist das sehr wichtig,
Und auf keinen Fall zuviele Kommentare, weil: die machen den Code so 
langsam...  :-/
> weil das seiner Meinung nach schneller ist
Lasst euch das mal beweisen...
> und weniger Fehler verursacht
Die Fehler passieren woanders!

> unserem Prof ist das sehr wichtig,
> signal timer : std_logic_vector (31 downto 0) := (others=>'0');
DAS nenne ich mal konsequent!!!
Warum machst du dann nicht deinen Zähler wenigstens als unsigned 
Vektor?
Oder als Integer?
Ach: zum Rechnen dürft ihr die alten Synopsys-Libs und 
uneingeschränkte Vektoren verwenden... :-o

> Aber woher soll er erkennen ob das Z ist?
> Irgend ein Pegel wird das Signal ja immer haben...
In der Hardware schon. Aber nicht im Simulator.

> use IEEE.STD_LOGIC_ARITH.all;
> use IEEE.STD_LOGIC_UNSIGNED.ALL;
> use ieee.numeric_std.all;
Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"


>>> WARNING:Xst:1710 - FF/Latch <invalue> has a constant value ...
Was macht denn deine Simulation?
Kommst du je in den Zustand state_reset1 ?

von Fabian S. (jacky2k)


Lesenswert?

Lothar Miller schrieb:
> Die Fehler passieren woanders!
Das brauchst du mir nicht zu sagen...

>> unserem Prof ist das sehr wichtig,
>> signal timer : std_logic_vector (31 downto 0) := (others=>'0');
> DAS nenne ich mal konsequent!!!
> Warum machst du dann nicht deinen Zähler wenigstens als /unsigned/
> Vektor?
> Oder als Integer?
> Ach: zum Rechnen dürft ihr die alten Synopsys-Libs und
> uneingeschränkte Vektoren verwenden... :-o
Keine Ahnung, kenne das nur so und das hat bislang immer gut 
funktioniert.

>> Aber woher soll er erkennen ob das Z ist?
>> Irgend ein Pegel wird das Signal ja immer haben...
> In der Hardware schon. Aber nicht im Simulator.
Das ist wohl eher umgekehrt, erklär mir mal bitte woher die Hardware 
erkennen soll ob da am Ende nen Pull-Up oder nen Strong-Drive drin 
ist...
>
>> use IEEE.STD_LOGIC_ARITH.all;
>> use IEEE.STD_LOGIC_UNSIGNED.ALL;
>> use ieee.numeric_std.all;
> Beitrag "IEEE.STD_LOGIC_ARITH.ALL obsolete"
Aha, werde ich mir mal reinziehen, soblad diese Probleme hier gelöst 
sind...

>>>> WARNING:Xst:1710 - FF/Latch <invalue> has a constant value ...
> Was macht denn deine Simulation?
> Kommst du je in den Zustand state_reset1 ?
Keine Ahnung. Ich habe noch keinen Simulator zum laufen bekommen unter 
Linux. Ich teste das hier alles auf echter Hardware...

von Fabian S. (jacky2k)


Lesenswert?

Soooo, einen Fehler habe ich gefunden. Der Zustand state_reset1 wurde 
tatsächlich nie erreicht, hätte jedoch nicht gedacht, dass das Teil so 
intelligent ist, weil die Entscheidung das bit zu setzen oder nicht 
fällt einige Ebenen weiter oben :D Wenn ich es da setze ist die Meldung 
weg.
Bleibt nur noch die eine Warnung:
1
Unit onewirebit is merged (output interface has tristates)
Jemand eine Idee?
Ich habe IRGENDWO im Netz gelesen, dass das unwichtig ist und man es 
igorieren kann, dann frage ich mich aber warum es dann ein Warning und 
kein Note oder sowas ist :-/
Und es bleibt noch die Frage was ich aus dem dq auslese wenn ich es lese 
je nachdem was für ein Zustand vorhanden ist.

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


Lesenswert?

Fabian S. schrieb:
>>> Aber woher soll er erkennen ob das Z ist?
>>> Irgend ein Pegel wird das Signal ja immer haben...
>> In der Hardware schon. Aber nicht im Simulator.
> Das ist wohl eher umgekehrt...
Die Hardware wird immer entweder '0' oder '1' erkennen. Der Simulator 
kennt auch 'Z' (und die anderen Zustände von std_logic).

von Fabian S. (jacky2k)


Lesenswert?

Wunderbar, ich denke dann sind auch alle Fragen geklärt bis auf das
1
Unit onewirebit is merged (output interface has tristates)
Aber das ignoriere ich nun erstmal getrost und werde kommenden Montag 
meinen Prof dazu ausquetschen :D
Ich habe nun für die Zähler/Timer ein integer genommen, ist das besser? 
:D

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


Lesenswert?

Fabian S. schrieb:
> Ich habe nun für die Zähler/Timer ein integer genommen, ist das besser?
Ja, es ist schlüssiger. Wie gesagt: Mit Verktoren rechnet man nicht. 
Wofür wurden sonst die anderen Datentypen erfunden. Also: nur die 
numeric_std statt der std_logic_arith+std_logic_unsigned!

Und frag mal deinen Prof, wofür man denn die signed und unsigned 
Vektoren brauchen kann, wenn es doch die integer gibt...  ;-)

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.