Forum: FPGA, VHDL & Co. Kompassmodul "cmps03" per I2C in VHDL ansprechen


von Basti1984 (Gast)


Lesenswert?

Hallo!

Ich habe hier ein Spartan 3 Board sowie ein cmps03 Kompassmodul liegen. 
Dieses habe ich bereits erfolgreich per PWM auslesen können, 
funktioniert ohne Probleme. Nun wollte ich das Ganze gern per I2C 
ansteuern, nur leider funktioniert das bisher nicht richtig. Ich habe 
das I2C Protokoll erstmal (vielleicht ein wenig unübersichtlich) mit 
einem recht langen Automaten implementiert, laut LogicAnalyzer sende ich 
auch das richtige raus (so wie es im Datenblatt steht). Geschwindigkeit 
ist unter 100kHz,das sollte auch nicht das Problem sein. Ich poste 
gleich mal den Automaten, vielleicht kann mir ja hier jemand den 
entscheidenden Hinweis geben.. :-) Vielen Dank schonmal!!

main: process(clk)
variable I2Cstate: integer range 0 to 30:=0;
variable adr_cnt: integer range 0 to 15:=15;

begin
if clk='1' and clk'event then

if btn = '1' then  -- Kalibrierung, Pin 6 kurzzeitig auf GND ziehen
  calibrate <= '0';
else
  calibrate <= 'Z';
end if;

case I2Cstate is
        when 0 =>
          SDA <= '1'; SCL <= '1'; ready<='1';
    I2Cstate := I2Cstate+1;

  when 1=>
    if Start = '1' and ready = '1' then

      SDA <= '0'; ready<='0';
      I2Cstate := I2Cstate+1;
    else
      I2Cstate := 1;
    end if;


  when 2 =>

    SCL<='1';
    I2Cstate := I2Cstate+1;

  wen 3 =>  -- Kompassadresse C0
    case adr_cnt is
      when 15|13|11|9|7|5|3 =>
        SCL <= '0';
        SDA <= Adr((adr_cnt-1)/2);
        adr_cnt := adr_cnt-1;
      when 14|12|10|8|6|4|2 =>
        SCL <= '1';
        adr_cnt := adr_cnt-1;
      when 1 =>
        SCL <= '0';
        SDA <= Adr(adr_cnt-1);
        adr_cnt := adr_cnt-1;
      when 0 =>
        SCL <= '1';
        adr_cnt := 15;
        I2Cstate := I2Cstate+1;

      end case;

  when 17 =>
    SCL <= '0';
    I2Cstate := I2Cstate+1;

  when 4|9|19|24 =>
    SCL <= '0'; SDA <= 'Z';
    I2Cstate := I2Cstate+1;

  when 5|10|20|25 =>        -- ACK
    ACK <= SDA; SCL <= '1';
    if ACK = '0' then
      ACK <='1';
      SCL <='0';
      I2Cstate := I2Cstate+2;
    end if;
  when 6|7|11|12|16|21|26|27|29 =>
    I2Cstate := I2Cstate+1;

  when 8 =>  -- Registeradresse (1=Kompass Wert)
    case adr_cnt is
      when 15|13|11|9|7|5|3 =>
        SCL <= '0';
        SDA <= RegNr((adr_cnt-1)/2);
        adr_cnt := adr_cnt-1;
      when 14|12|10|8|6|4|2 =>
        SCL <= '1';
        adr_cnt := adr_cnt-1;
      when 1 =>
        SCL <= '0';
        SDA <= RegNr(adr_cnt-1);
        adr_cnt := adr_cnt-1;
      when 0 =>
        SCL <= '1';
        adr_cnt := 15;
        I2Cstate := I2Cstate+1;

      end case;
    when 22 =>
    SCL <= '0'; SDA <= '0';
    I2Cstate := I2Cstate+1;

  when 13|30 =>
    SDA <= '1';  -- repeated Startbit
    I2Cstate := I2Cstate+1;

  when 14|28 =>
    SCL <= '1';
    I2Cstate := I2Cstate+1;

  when 15 =>
    SDA <= '0';
    I2Cstate := I2Cstate+1;

  when 18 =>  -- Kompassadresse C1 (gesetztes R/W Bit)

    case adr_cnt is
      when 15|13|11|9|7|5|3 =>
        SCL <= '0';
        SDA <= AdrRW((adr_cnt-1)/2);
        adr_cnt := adr_cnt-1;
      when 14|12|10|8|6|4|2 =>
        SCL <= '1';
        adr_cnt := adr_cnt-1;
      when 1 =>
        SCL <= '0';
        SDA <= AdrRW(adr_cnt-1);
        adr_cnt := adr_cnt-1;
      when 0 =>
        SCL <= '1';
        adr_cnt := 15;
        I2Cstate := I2Cstate+1;

      end case;

  when 23 =>  -- Kompass Wert lesen
    SDA <= 'Z';
    case adr_cnt is
      when 15|13|11|9|7|5|3 =>
        SCL <= '0';
        cmps((adr_cnt-1)/2) <= SDA;
        adr_cnt := adr_cnt-1;
      when 14|12|10|8|6|4|2 =>
        SCL <= '1';
        adr_cnt := adr_cnt-1;
      when 1 =>
        SCL <= '0';
        cmps(adr_cnt-1) <= SDA;
        adr_cnt := adr_cnt-1;
      when 0 =>
        SCL <= '1';
        adr_cnt := 15;
        i2csig <= cmps;  -- Kompasswert übergeben
        I2Cstate := I2Cstate+1;
    end case;

  when 31 =>
    I2Cstate := 0;
    end case;
  end if;
end process;

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


Lesenswert?

Nur kurz überflogen, aber das hier gibt mir zu denken:
1
  when 5|10|20|25 =>        -- ACK
2
    ACK <= SDA; SCL <= '1';
3
    if ACK = '0' then
4
      ACK <='1';
5
      SCL <='0';
6
      I2Cstate := I2Cstate+2;
7
    end if;
Du hast hier einen Takt Latency, ist dir das Verhalten von Signalen in 
einem Prozess klar? ACK wird gelesen, aber die Abfrage wird auf den 
alten ACK-Wert gemacht! Das hier macht genau das selbe:
1
  when 5|10|20|25 =>        -- ACK
2
    if ACK = '0' then
3
      ACK <='1';
4
      SCL <='0';
5
      I2Cstate := I2Cstate+2;
6
    end if;
7
    ACK <= SDA; SCL <= '1';
Hast du das gewollt?
Ähnliches kann ich mir auch mit dem Tristate-Schalten vorstellen...

Solche Latency-Geschichten findest du am ehesten mit einer Simulation 
der FSM. Hast du die schon simuliert?

von Basti1984 (Gast)


Lesenswert?

Hallo!

Ja, mit den Acknowledges hab ich schon ein wenig hin und her geändert, 
daher wohl grade die nicht so tolle Variante. die if-Anweisung kann dort 
meines Erachtens auch komplett weggelassen werden, die Zuweisung ACK <= 
SDA ist so gewollt. Ich habe mir die Signale per Logic Analyzer 
angeschaut, es sah alles so aus, wie es sein soll, richtiger Takt und 
SDA / SCL haben die Korrekten Werte.

Ich habe grade zufällig noch was interessantes herausgefunden, was mir 
einen neuen Ansatz geben könnte..

Wenn ich die 1,8k Pull-Ups zwischen SDA /SCL und +5V kurz entferne und 
wieder verbinde, wird mir ein Wert angezeigt, der durchaus richtig sein 
könnte. sobald die Pull-Ups wieder drin sind, bleibt der Wert fest 
stehen und egal wie ich den Kompass drehe, es verändert sich nichts. 
Wenn ich aber an einer geänderten Position wiederum kurz die Pull-Ups 
entferne und kurz darauf wieder verbinde, dann habe ich auch einen 
geänderten Wert, der auch durchaus realistisch ist. Das wiederum würde 
bedeuten, dass die I2C Schnittstelle korrekt arbeitet und es anscheinend 
ein Problem mit den Pegeln gibt.. da muss ich mich nochmal ein wenig mit 
beschäftigen..

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


Lesenswert?

> habe hier ein Spartan 3 Board ...
> ... die 1,8k Pull-Ups zwischen SDA /SCL und +5V kurz entferne
Das mit den 5V und der IO-Spannung hast du beachtet?
Der S3 ist nicht 5V IO-tolerant. Gut, mit den Pullups kann das noch 
gehen, aber "schön" schreibt sich anders...

von Basti1984 (Gast)


Lesenswert?

Also sollte ich lieber eine externe 5V Spannungsquelle nehmen und die 
nicht vom Spartan "anzapfen"?

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


Lesenswert?

> Also sollte ich lieber eine externe 5V Spannungsquelle nehmen und die
> nicht vom Spartan "anzapfen"?
Die Frage die sich stellt ist: Wo hat dein S3 5 Volt?
Am IO-Pin eines S3 haben 5V nichts verloren (wobei handverlesene 
Ausnahmen nur die Regel bestätigen).

von Basti1984 (Gast)


Lesenswert?

ich glaub jetzt weiß ich, was du meinst. Die Versorgungsspannung des 
Moduls ist 5V, die nehme ich direkt vom Board über den Connector. Die 
I/O Pins haben allerdings eine wesentlich geringere Spannung, da hab ich 
gar nicht dran gedacht.. Schande über mein Haupt! D.h. so wie ich das 
Verbunden habe, habe ich nen 5V Pullup auf die I/O Leitungen gehauen, 
was natürlich viel zu hoch ist.. richtig?

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


Lesenswert?

> D.h. so wie ich das Verbunden habe, habe ich nen 5V Pullup auf die I/O
> Leitungen gehauen, was natürlich viel zu hoch ist.. richtig?
Ja.
Aber ich denke der wird das Dank der internen Schutzdioden überlebt 
haben. Allerdings hast du an deinem I2C-Bus keine 5V-Pegel. Das könnte 
Probleme machen...

von Basti1984 (Gast)


Lesenswert?

das Board hats überlebt, ja. :-)
hm, naja, auf jeden Fall scheint hier der Hund begraben zu liegen.. Ich 
werd auf dieser Ebene mal weitersuchen.

Vielen Dank auf jeden Fall schonmal für deine 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.