Forum: FPGA, VHDL & Co. I2C Daten INOUT umschalten


von Ralf (Gast)


Lesenswert?

Hallo zusammen,

ich habe in meinem VHDL Modul einen I2C Slave verbaut. Dieser kann Daten 
empfangen und senden.

In meiner Top-Testbench habe ich einen I2C Master eingebunden, der den 
I2C Slave ansprechen soll. Leider hat der den Nachteil/die dumme 
Angewohnheit, dass er die Leitungen nur auf '0' treiben kann und 
ansonsten SCL und SDA auf 'Z' legt.

Mit einem 'Z' kann mein I2C Slave nur leider nicht anfangen.
Da sowohl Slave, als auch Master hier im Uninetzwerk im Bibliotheken 
vorliegen, kann ich diese auch nicht ändern. Ein Änderungsvorschlag habe 
ich schon gemacht, der wird gerade geprüft.

SDA ist ein Port vom Typ INOUT.
Ich habe also in meinem VHDL Modul eine Art Buffer verbaut, der für SDA 
die Umschaltung vornimmt. Er schaltet also SDA_IN und SDA_OUT mit einem 
OEN Pin um und damit auf dem INOU Port meines Top-Moduls.

Nun muss ich mir was einfallen lassen, wie ich den "Fehler" mit dem 
Zustand 'Z' behandeln soll.

Wenn ich es so versuche:
1
SCL_IN_SLAVE <= '1' when SCL_IN_MASTER = 'Z' else SCL_IN_MASTER ;
2
SDA_IN_SLAVE <= '1' when SDA_IN_MASTER = 'Z' else SDA_IN_MASTER ;
klappt es zwar für SCL, denn der ist unidirektional, aber nicht für SDA.

Sobald der Slave versucht die Daten auf '0' zu ziehen, gibt es ein 'X', 
weil dann SDA_IN_SLAVE und SDA_IN_MASTER gegeneinander treiben.

Gibt es eine Möglichkeit, wie ich die bidirektionalen Daten sicher 
umschalten kann?

Vielen Dank!
Ralf

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


Lesenswert?

Ralf schrieb:
> Leider hat der den Nachteil/die dumme
> Angewohnheit, dass er die Leitungen nur auf '0' treiben kann und
> ansonsten SCL und SDA auf 'Z' legt.
Das ist I2C. Du musst von aussen noch Pullup anschliessen. In VHDL ist 
das ein 'H' Pegel, der auf das SDA Signal getrieben wird.

> Sobald der Slave versucht die Daten auf '0' zu ziehen, gibt es ein 'X',
> weil dann SDA_IN_SLAVE und SDA_IN_MASTER gegeneinander treiben.
Was kollidiert denn da?

> Gibt es eine Möglichkeit, wie ich die bidirektionalen Daten sicher
> umschalten kann?
Da ist nichts umzuschalten. Beim I2C ergibt sich ein 'H', wenn niemand 
eine '0' treibt (es gibt aber eigentlich niemals eine '1', weil kein 
Telnemher aktiv eine '1' ausgeben darf!). Deine Schaltungsbeschreibung 
ist einfach noch falsch...

von Bronco (Gast)


Lesenswert?

Ralf schrieb:
> Mit einem 'Z' kann mein I2C Slave nur leider nicht anfangen.

Warum nicht?

Ein I2C-Teilnehmer darf abfragen auf '0' oder nicht-'0':
1
if (SDA = '0') then
2
  -- starke '0'
3
else
4
  -- schwache '1'
5
end if;

Und er darf ausgeben '0' und 'Z':
1
if (auszugebenerZustand = '0') then
2
  SDA <= '0';
3
else
4
  SDA <= 'Z';
5
end if;

von Ralf (Gast)


Lesenswert?

Hallo,

und wie verwendet ich den Pull-Up in VHDL?
1
SDA_IN_SLAVE <= 'H';
setzt mir das Signal ja dauerhaft auf HIGH, auch wenn ich meinen Port im 
Top-Modul dann mit
1
SDA => to_x01(SDA_IN_SLAVE);
belege.

Der I2C Slave aus der Uni-Library meldet einen Fehler, wenn ich außer 
'0' und '1' noch andere Zustände auf die Ports gebe. 'H' ist also 
scheinbar verboten :(

Vielen Dank!
Ralf

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


Lesenswert?

Ralf schrieb:
> SDA_IN_SLAVE <= 'H';
> setzt mir das Signal ja dauerhaft auf HIGH
Ja, genau das willst du ja. Denn merke: 'H' ist nicht '1'...

> Der I2C Slave aus der Uni-Library meldet einen Fehler, wenn ich außer
> '0' und '1' noch andere Zustände auf die Ports gebe. 'H' ist also
> scheinbar verboten :(
Dann ist offenbar noch ein Fehler im Modell...

von Ralf (Gast)


Lesenswert?

Hallo,

ich habe es jetzt so getestet, ist das die korrekte Schreibweise für den 
Pullup?
1
-- pull-up
2
SCL_IN_SLAVE <= 'H';
3
SDA_IN_SLAVE <= 'H';
4
5
SCL_IN_SLAVE <= SCL_IN_MASTER;
6
SDA_IN_SLAVE <= SDA_IN_MASTER;

Die Funktion to_x01 bei der Portzuweisung richtet den offenbar im Modell 
vorhandenen Fehler erstmal... muss ich mal Bescheid geben, dass das 
geändert wird.

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


Lesenswert?

Ralf schrieb:
> SCL_IN_SLAVE <= SCL_IN_MASTER;
Warum hast du 2 SCL_IN_xxx?
Es gibt eigentlich nur 1 Signal SCL, und das geht an den Master und 
genau das selbe an den Slave. Und der Master hat einen inout-Port SCL 
(wg. Clock-Stretching). Und auf der Slave hat einen SCL Port. Und die 
Testbench verbindet diese beiden Ports mit einem SCL Signal. Und 
gleichzeitig legt die Testbench an diese Leitung einen 'H' Pegel (als 
Pullup-Ersatz) an.

> SDA_IN_SLAVE <= SDA_IN_MASTER;
Und die obige Beschreibung gilt genau so auch für den SDA.

> -- pull-up
> SCL_IN_SLAVE <= 'H';
> SDA_IN_SLAVE <= 'H';
Das ist dann im Top-Level der Testbench zu finden.

von Ralf (Gast)


Lesenswert?

Ja ok, das war noch etwas umständlich:
1
instanz_master : ENTITY work.i2c_master
2
      PORT MAP (
3
         ...
4
         SCL => SCL_MASTER,
5
         SDA => SDA_MASTER,
6
         ...);
7
8
SCL_MASTER <= 'H';
9
SDA_MASTER <= 'H';
10
11
instanz_slave : ENTITY work.i2c_slave
12
      PORT MAP (
13
         ...
14
         SCL => to_x01(SCL_MASTER),
15
         SDA => to_x01(SDA_MASTER),
16
         ...);

Vielen Dank! :)

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


Lesenswert?

Ralf schrieb:
> SCL => to_x01(SCL_MASTER),
> SDA => to_x01(SDA_MASTER),
Und das geht auch mit inout Ports?
Mindestens der SDA wird ein inout Port sein müssen (wg. ACK)...

von Ralf (Gast)


Lesenswert?

Hallo,

Lothar Miller schrieb:
> Und das geht auch mit inout Ports?
> Mindestens der SDA wird ein inout Port sein müssen (wg. ACK
Ja es scheint so. Das ACK kommt zum Master durch und die I2C 
Kommunikation funktioniert...

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.