mikrocontroller.net

Forum: FPGA, VHDL & Co. SPI in VHDL, unerklärliches Verhalten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
Autor: Md M. (Firma: Potilatormanufaktur) (mdma)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte einen ADC vom Typ MCP3008 per SPI ansprechen. Dazu benutze 
ich folgenden Prozess, um eine Kommunikation zu erreichen, wie sie in 
FIGURE 6.1 auf Seite 21 des Datenblatts zu sehen ist:
  process(fxclk_signal)
    variable delay_counter0 : integer := 0; 
  begin
    if rising_edge(fxclk_signal) then
      case state is        

        when 0 =>
          TX_Data0_signal                 <= "000000011000000000000000";
          TX_Start0_signal                <= '1';
          lsi_in_strobe_signal            <= '0';
          if TX_Done0_signal = '1' then
            state                         <= 1;
          end if;

        when 1 =>
          TX_Start0_signal                <= '0';
          state                           <= 2;

        when 2 =>
          TX_Start0_signal                <= '1';
          if TX_Done0_signal = '1' then
            state                         <= 3;
          end if;

        when 3 =>
          TX_Start0_signal                <= '0';
          state                           <= 4;

        when 4 =>
          TX_Start0_signal                <= '1';
          if TX_Done0_signal = '1' then
            state                         <= 5;
          end if;

        when 5 =>
          led2(9 downto 0)                <= RX_Data0_signal(9 downto 0);
          lsi_out_data_signal(9 downto 0) <= RX_Data0_signal(9 downto 0);
          lsi_out_adress_signal           <= std_logic_vector(to_unsigned(0, 8));
          --lsi_in_strobe_signal            <= '1';
          TX_Start0_signal                <= '0';
          state                           <= 6;

        -- delay
        when 6 =>
          if delay_counter0 = delay0 then
            delay_counter0                := 0;
            state                         <= 0;
          else
            delay_counter0                := delay_counter0 + 1;
          end if;

        when others =>

      end case;
    end if;
  end process;

Ich habe noch nicht ganz begriffen, wie genau die SPI-Schnittstelle des 
MCP3008 arbeitet, insbesondere, weil es anscheinend einen Modus gibt, 
bei dem eine Abfrage 24 Takte braucht und einen, bei dem es 16 sind. 
Egal, ich habe das mit 24 Takten versucht: Hier wird also 
"000000011000000000000000" zum MCP3008 geschoben. Die erste '1' ist das 
Startbit. Die folgenden Bits '1000' bewirkt, dass Channel 0 single-ended 
abgerufen wird. Das funktioniert auch alles einigermaßen. Allerdings ist 
folgendes Problem aufgetreten: Ich habe versucht, in den Prozess direkt 
dahinter eine weitere Abfrage eines anderen Channels einzubauen, also 
die Anzahl der states verdoppelt und beim zweiten Durchlauf einfach die 
Bits angepasst. Es sollte also immer nacheinander ...Ch0-Ch1-Ch0-Ch1... 
abgefragt werden. Komischerweise kam dabei aber die Abfragesequenz 
...Ch0-Ch0-Ch1-Ch0-Ch0-Ch1... raus. Ich hab absolut nicht verstanden, 
wie das sein kann. Deshalb habe ich das ganze wieder auf eine einzige 
sich wiederholdende Abfrage reduziert und hinter die Abfrage mit einem 
counter ein delay gesetzt. Auch hier zeigt sich ein Fehler. Er ist aus 
den angehängten screenshots vom LA ersichtlich: Auf dem ersten Bild ist 
eine Abfrage zu sehen. Das Funktioniert grundsätzlich. Auf dem zweiten 
Bild habe ich etwas herausgezoomt. Man man sieht, dass nach jedem 
zweiten Durchlauf der delay nicht greift. Das kann ich mir nicht 
erklären, aber ich vermute, dass es die selbe Ursache hat wie mein 
Problem bei zwei Abfragen hintereinander. Was mach ich falsch?

VG

: Verschoben durch Moderator
Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Md M. schrieb:
> Er ist aus den angehängten screenshots vom LA ersichtlich
Was sagt denn die Simulation? Zeigt die den selben Effekt?

Autor: Md M. (Firma: Potilatormanufaktur) (mdma)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Oh je, wie peinlich. Die genaue Ursache hab ich zwar nicht gefunden, 
aber die Simulation hat mich zumindest veranlasst, die ganzen 
überflüssigen states zu entfernen, die ich ursprünglich zum debuggen 
drin hatte. Ohne die läuft es jetzt wie es soll. Auf die Idee, den Code 
zu entrümpeln hätte ich natürlich auch vorher schonmal kommen können.
  process(fxclk_signal)
    variable delay_counter0 : integer := 0; 
  begin
    if rising_edge(fxclk_signal) then
      case state is        

        when 0 =>
          TX_Data0_signal                 <= "000000011000000000000000";
          TX_Start0_signal                <= '1';
          if TX_Done0_signal = '1' then
            TX_Start0_signal              <= '0';
            state                         <= 1;
          end if;

        when 1 =>
          led2(9 downto 0)                <= RX_Data0_signal(9 downto 0);
          lsi_out_data_signal(9 downto 0) <= RX_Data0_signal(9 downto 0);
          lsi_out_adress_signal           <= std_logic_vector(to_unsigned(0, 8));
          TX_Start0_signal                <= '0';
          if delay_counter0 = delay0 then
            delay_counter0                := 0;
            state                         <= 2;
          else
            delay_counter0                := delay_counter0 + 1;
          end if;

        when 2 =>
          TX_Data0_signal                 <= "000000011001000000000000";
          TX_Start0_signal                <= '1';
          if TX_Done0_signal = '1' then
            TX_Start0_signal              <= '0';
            state                         <= 3;
          end if;

        when 3 =>
          led2(19 downto 10)              <= RX_Data0_signal(9 downto 0);
          lsi_out_data_signal(9 downto 0) <= RX_Data0_signal(9 downto 0);
          lsi_out_adress_signal           <= std_logic_vector(to_unsigned(0, 8));
          TX_Start0_signal                <= '0';
          if delay_counter0 = delay0 then
            delay_counter0                := 0;
            state                         <= 0;
          else
            delay_counter0                := delay_counter0 + 1;
          end if;

        when others =>

      end case;
    end if;
  end process;

Autor: Ingo S. (logikneuling)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Du scheinst dein Problem ja schon gelöst zu haben, daher kommt das 
vielleicht etwas zu spät... aber vielleicht hilft Dir das trotzdem noch.

Ich habe mich vor ein paar Wochen auch selbst an einer SPI Schnittstelle 
zum MCP3008 in VHDL versucht (und im Endeffekt eher Probleme mit dem 
Analogteil gehabt: siehe Beitrag "SAR ADC erzeugt Spikes während AD Wandlung?" 
und Beitrag "Hilfe Auslegung low-pass Filter und Verbindung zu ADC"), aber irgendwie doch 
ungewollt immer ein oder zwei überflüssige States eingebaut. Schließlich 
hab ich mir dann doch mal den Referenz-Code zu meinem Board angesehen 
und nach ausführlichem Studium jeder einzelnen Code-Zeile bin ich zu dem 
Schluss gekommen, dass ich es wohl nicht smarter und kürzer selbst 
aufschreiben kann (vielleicht kann Lothar es doch, er scheint ja ein 
Meister darin zu sein ;)).

Beispielweise bin ich eingangs nicht selbst auf so etwas simples wie 
dies hier, obwohl es natürlich nur eine klassische 
Shiftregister-Beschreibung ist (quasi bis zum vollständigen DAC Wert 
"ungueltige" Werte weiter zu schieben, aber den momentanen adc_miso Wert 
direkt in Q abzulegen, so dass dann mit dem letzten Hineintakt-State, 
ohne im Anschluss eine weitere Kopie von Q irgendwo "abzulegen", in 
einem anderen Prozess Q direkt übernommen werden kann, ...), da hätte 
ich wieder extra-states verschenkt:
  -- MISO shift register (rising edge)
  shift_in : process(adc_clock)
  begin
    if adc_clock'event and adc_clock = '1' then
      if state = '1' then
        Q(0)          <= adc_miso;
        Q(9 downto 1) <= Q(8 downto 0);
      end if;
    end if;
  end process;

Oder beispielweise auch, das invertierte "state"-Bit direkt als CS 
Ausgangssignal zu benutzen...

Vermutlich muss ich mir noch mehr solcher Implementationen ansehen, um 
solche Konstrukte in Zukunft wie ein Template einfach aus dem Kopf holen 
zu können.

Der vollständige MCP3008/SPI VHDL Code ist zu finden hier: 
https://www.micro-nova.com/resources/ unter "Tutorials & Example Code", 
"On-board ADC Reference Design" (ich wollte die ZIP-Datei jetzt nicht 
einfach so verlinken).

Viele Grüße,
Ingo

: Bearbeitet durch User
Autor: Md M. (Firma: Potilatormanufaktur) (mdma)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Ingo,

ja, der Codeschnipsel sieht in der Tat elegant aus. Das merk ich mir auf 
jeden Fall. Wobei ich aber eigentlich ohnehin nie abschätzen kann, was 
das Synthesetool am Ende aus meinem Code macht. Da fehlt mir definitiv 
die Erfahrung. Deine beiden threads hab ich übrigens schon gesehen und 
gebookmarked. Die wollte ich auch durchgehen, wenn ich beim 
Antialiasing-Filter angekommen bin. Ich rechne mit einigen Problemen, 
über die du dann zu meinen Glück vielleicht schon gestolpert bist.

VG

: Bearbeitet durch User

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.