www.mikrocontroller.net

Forum: FPGA, VHDL & Co. Kommunikations FPGA<-PIC: Fehlerhafte Erkennung der Daten


Autor: full well (realjey)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin gerade dabei mich in VHDL einzuarbeiten und möchte eine 
vermutlich "einfache" Aufgabe lösen, komme aber nicht weiter :/.

Ich müchte Daten vom PIC an den FPGA senden. Dafür habe ich den 
PIC18F2450 mit einem Spartan3A-DSP-Board über 11 Leitungen verbunden.

Der FPGA arbeitet mit 100MHz.
Der PIC mit 20MHz.

Dabei sind 8 Leitungen mit Port-d des PIC verbunden (8Bit-Datenbus).

Zusätzlich verwende ich zwei Bits des Port-b (RB0 und RB1) als 
Statusbits welche Art von Daten gesendet werden (Adresse, NWT, HWT). Der 
PIC setzt diese zwei Pins auf die Kombinationen "10"=>Adresse, 
"11"=>NWT, "01"=>HWT.

Der letzte Kanal ist dann RC2 und ist für den "shake" des FPGAs 
vorgesehen.

Ein Blockschaltbild des Prinzips habe ich angehängt.

Nun möchte ich im FPGA den Status der zwei Statusbits korrekt erkennen. 
Ich synchronisiere diese beiden Bits wie von http://www.lothar-miller.de 
beschrieben ein und frage die einsynchronisierten Signale dann per 
IF-Anweisung ab.
Dies scheint soweit auch einwandfrei zu funktionieren. Zur Überprüfung 
setze ich jeweils eine von vier LED's (LED_test1,...) bei korrekter 
Erkennung auf '1'.

Dazu habe ich folgenden vhdl-Code geschrieben (Der Code ist jetzt nur 
für die Übergabe einer Adresse abgebildet (also RB0=1 und RB1=0) und die 
Deklarationen der LED_test's habe ich mal weggelassen, der 
übersichtshalber):
Library IEEE;
Use IEEE.Std_Logic_1164.All;
Use IEEE.Numeric_Std.All;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity uCread_topModule is
  Port (  clock     : In Std_Logic;   
    shake     : out std_logic;   
                hand_uC   : in std_logic;
    hand2_uC  : in std_logic;
    databus_uC: in std_logic_vector(7 downto 0);); 
end entity uCread_topModule;

architecture RTL of uCread_topModule is

-----------------------------------------------------------------
signal sync_hand_uC, sync_hand2_uC: std_logic_vector(1 downto 0);
signal LED_test1, LED_test2, LED_test3, LED_test4: std_logic:='0';
signal uCData:  std_logic_vector(31 downto 0);
-----------------------------------------------------------------

-----\
begin 
-----/

-- Einsynchronisieren
process begin
   wait until rising_edge(clock);
   -- Schieberegister
   sync_hand_uC <= sync_hand_uC(0) & hand_uC;
   sync_hand2_uC <= sync_hand2_uC(0) & hand2_uC;
end process;

process begin 
   wait until rising_edge(clock);
  if (sync_hand_uC(1) & sync_hand2_uC(1)= "10") then
          shake<='1';
    LED_test1<='1';
    uCData(31 downto 24)<=databus_uC;
    if (uCData(31 downto 24)="00000001") then
      LED_test2<='1';
    else
      LED_test2<='0';
    end if;
  else
    shake<='0';
    LED_test1<='0';
    LED_test2<='0';
    uCData<=(others=>'0');
  end if;
end process;
  
end RTL;

Der Ablauf ist also folgender: Haben die einsynchronisierten Bits den 
Status "10", wird LED_test1=grün, der FPGA sendet sein shake-Signal, was 
dem PIC signalisieren soll, das er jetzt Daten auf den Datenbus legen 
darf. Um dann zu testen ob die Daten auch korrekt sind, sende ich zzt. 
vom PIC nur eine definierte Adresse (00000001) und überprüfe im FPGA ob 
er diese auch erkannt hat. Falls ja, schaltet er die zweite LED=grün.

Der PIC-Code dazu ist folgender (Reiner Testcode, die eingebauten 
delay's sind nur dazu da, um die LED's noch in einem Takt blinken zu 
lassen den ich mit blossem Auge auch erkennen kann ;)
while(1)
{    
  portd=0x0;
  portb=0x0;
  portb=0x01;  //Setze Bits auf Kombination für send:Adresse
  delay_ms(500);
      
  if(portc.2==1) //Wenn shake=1, sende Daten
  {
    portd=0x01;  //Sende Daten
    portb=0x0;  //setze Hand-Signale wieder auf 0
  }
    delay_ms(500);
}    

Das Problem was ich jetzt habe ist: Der FPGA erkennt zwar immer korrekt 
die hand-Signale (RB0, RB1-Kombinationen), allerdings nie die auf dem 
Bus anliegenden Daten. Das Problem wird ja höchstwahscheinlich die 5fach 
höhere Taktrate des FPGA's sein. Bis der PIC dazu kommt die Daten auf 
den 8bit-Bus zu legen ist der FPGA schon wieder einige Schritte weiter. 
Ich hoffe mir kann jemand einen Tip/Ansatz zur Problemlösung geben und 
ich habe nicht zuviel rumgetextet. Sollte ich den Thread noch einmal 
überarbeiten weil er zu undurchsichtig ist, bitte einfach bescheid geben 
:)

THX for RE!

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zuerst die Daten anlegen und dann die Handshake-Signale?

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

Bewertung
0 lesenswert
nicht lesenswert
Jey Soon schrieb:
> Das Problem wird ja höchstwahscheinlich die 5fach
> höhere Taktrate des FPGA's sein.
Eher nicht. Das Problem liegt woanders:
Du mußt zuerst gültige Daten anlegen.
Und dann darfst du dem FPGA signalisieren, dass da gültige Daten da 
sind.


> Bis der PIC dazu kommt die Daten auf
> en 8bit-Bus zu legen ist der FPGA schon wieder einige Schritte weiter.
Wohin soll der dann gegangen sein?
Da einzige, was passiert, ist, dass etliche Taktzyklen lang die falschen 
Daten eingelesen werden...

Ich würde sagen: die LED geht schon an.
Aber nur für ein paar us. Und dann schaltest du sie wieder aus.
Porbier mal das
while(1)
{    
  portd=0x0;
  portb=0x0;
  portb=0x01;  //Setze Bits auf Kombination für send:Adresse
  delay_ms(500);
      
  if(portc.2==1) //Wenn shake=1, sende Daten
  {
    portd=0x01;  //Sende Daten
    delay_ms(500);
    portb=0x0;  //setze Hand-Signale wieder auf 0
  }
}    

EDIT:
Nur, dass du mich nicht falsch verstehst:
das ist nicht die Lösung deines Problems!!!
Es ist nur eine Visualisierung des Problems...

BTW:
Ich hoffe, dir ist bewusst, dass du hier einen Takt Latency hast:
    uCData(31 downto 24)<=databus_uC;
    if (uCData(31 downto 24)="00000001") then
      LED_test2<='1';
    else
      LED_test2<='0';
    end if;
Du könntest das ohne jegliche Funktionsänderung auch so schreiben:
    if (uCData(31 downto 24)="00000001") then
      LED_test2<='1';
    else
      LED_test2<='0';
    end if;
    uCData(31 downto 24)<=databus_uC;

Autor: full well (realjey)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erstmal Danke für die Tipps. Ich habe den PIC und den FPGA jetzt so 
umgeschrieben, das zuerst die Daten auf den Bus gelegt werden und dann 
die Handshakes ausgetauscht werden. Das sieht dann folgendermaßen aus:
portd=0x0; //Definierter Anfangszustand
portb=0x0; //Definierter Anfangszustand
delay_us(10);
portd=0x01; //Lege Daten auf Datenbus
portb|=(1<<0)|(0<<1); //Setze Bits auf Kombination für send:Adresse "01" (Hand-Signal)

delay_ms(500);

if(portc.2==1) //Wenn shake=1, setzte Datenbus zurück und lösche die 
               //Hand-Signale
{
   portd=0x0;  
   portb&=~((1<<0)|(1<<1));  //setze Hand-Signale wieder auf 0
   delay_s(1);
}
process begin -- Einsynchronisieren
   wait until rising_edge(clock);
   sync_hand_uC <= sync_hand_uC(0) & hand_uC;
   sync_hand2_uC <= sync_hand2_uC(0) & hand2_uC;
end process;

process begin 
   wait until rising_edge(clock);
  if (sync_hand_uC(1) & sync_hand2_uC(1)= "10") then
    LED_test1<='1';
    if (uCData(31 downto 24)="00000001") then
      LED_test2<='1';
    else
      LED_test1<='0';
    end if;
    uCData(31 downto 24)<=databus_uC;
    shake<='1';
         else
                shake<='0';
    LED_test1<='0';
    LED_test2<='0';
    LED_test3<='0';
    LED_test4<='0';
    uCData<=(others=>'0');
end process;

Sowohl in Modelsim als auch auf dem Board scheint es jetzt einwandfrei 
zu funktionieren. Ich habe alle verschiedenen Hand-Signale ["01", "10", 
"11"] mit verschiedensten Daten auf dem Datenbus getestet und die 
Erkennung lief einwandfrei.

Ist dieser Code den generell OK ok muss ich hier befürchten das doch 
auch metastabile Zustände auftauchen können, da ich irgendeine 
Grundlegende Designregel nicht beachtet habe?

@Lothar Noch einmal zu deiner Anmerkung mit der Takt-Latency: Ich habe 
es so verstanden, das die Befehle innerhalb einer IF-Schleife 
sequentiell abgearbeitet werden, in der Geschwindigkeit des 
Systemtaktes.

Das müsste doch bedeuten, das wenn ich schreibe:
process begin
   wait until rising_edge(clock);
   shake<='1';
   if(...) then
   .
   .
   end if;
end process;

das das shake-statement parallel zur Bedingungs-Abfrage in der 
IF-Schleife ausgeführt wird, richtig?

Das wiederum müsste doch bedeuten das wenn ich schreibe:
process begin
   wait until rising_edge(clock);
   if(...) then
   .
   .
   end if;
   shake<='1';
end process;

die statements in genau der selben Taktfolge abgearbeitet werden. Wo 
liegt dann der Unterschied?

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

Bewertung
0 lesenswert
nicht lesenswert
Jey Soon schrieb:
> Wo liegt dann der Unterschied?
Es gibt keinen Unterschied in diesen beiden Beispielen.

>> portb|=(1<<0)|(0<<1);
Sieh dir unbedingt nochmal das Kapitel "Bitoperationen in C" an.
Es bringt nichts, eine '0' irgendwohinzischieben, wenn die dann 
anschliessend verodert wird. Ein dort gesetztes Bit wird so nicht 
gelöscht!!!


> Sowohl in Modelsim als auch auf dem Board scheint es jetzt
> einwandfrei zu funktionieren.
Da sind noch einige Lücken im Ablauf...
Z.B. gehen die Daten am PortD weg, bevor die Handshakesignale weggehen.

Das was du willst ist offenbar ganz einfach:
Mit 2 Kommandoleitungen irgendwelche Daten an das FPGA senden.

Das ist eigentlich nichts anderes, als z.B. ein asynchrones RAM zu 
beschreiben. Nur sieht dort die Lösung anders aus: erst werden die 
Adresse (=dein Kommando) und die Daten an das RAM angelegt, dann wird 
mit einer Steuerleitung die entsprechende Aktion ausgelöst.
Da gibt es keinen "Rückkanal" vom RAM...

Und so ähnlich kannst du das doch auch machen:
1. Leg dein Kommando an.
2. Leg die Daten an.
3. Validiere die angelegten Signale.

Auf der uC-Seite also ganz ohne Handshake:
portd=0x01;   // Lege Daten auf Datenbus
portb=0x01;   // Setze Bits auf Kombination für send:Adresse "01" (Hand-Signal)

portc.2 = 1;  // Datenübergabe
delay_us(10);
portc.2 = 1;

Und auf der FPGA-Seite:
Use IEEE.Std_Logic_1164.All;
Use IEEE.Numeric_Std.All;

entity uCread_topModule is
  Port (  clock     : in Std_Logic;   
          shake     : in std_logic;   
          addr_uC   : in std_logic_vector(1 downto 0);  -- Kommando
          databus_uC   : in std_logic_vector(7 downto 0)); 
end entity uCread_topModule;
:
:
process begin -- Einsynchronisieren
   wait until rising_edge(clock);
   sync_shake <= sync_shake (0) & shake;
end process;

process begin 
 wait until rising_edge(clock);
 if (sync_shake = "01") then  -- steigende Flanke --> Daten sind stabil
   if (addr_uC="10") then     -- kein sync nötig, weil hier garantiert stabil
     LED_test2<='0';
     LED_test1<='0';
     if (uCData(31 downto 24)="00000001") then
       LED_test2<='1';
     else
       LED_test1<='1';
     end if;
     uCData(31 downto 24)<=databus_uC;
   end if;
 end if;
end process;
Use IEEE.Std_Logic_1164.All;
Use IEEE.Numeric_Std.All;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
Niemals die numeric_std zusammen mit den synopsis-Libs verwenden!!
Da gibt es sonst einige Definitionen doppelt... :-o

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.