mikrocontroller.net

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


Autor: Basti1984 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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;

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur kurz überflogen, aber das hier gibt mir zu denken:
  when 5|10|20|25 =>        -- ACK
    ACK <= SDA; SCL <= '1';
    if ACK = '0' then
      ACK <='1';
      SCL <='0';
      I2Cstate := I2Cstate+2;
    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:
  when 5|10|20|25 =>        -- ACK
    if ACK = '0' then
      ACK <='1';
      SCL <='0';
      I2Cstate := I2Cstate+2;
    end if;
    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?

Autor: Basti1984 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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..

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Basti1984 (Gast)
Datum:

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

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Basti1984 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Basti1984 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [vhdl]VHDL-Code[/vhdl]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.