Forum: FPGA, VHDL & Co. FPGA, Datenbus & Register


von John (Gast)


Lesenswert?

Hallo,
ich will gerne einen FPGA mit dem Datenbus eines Mikrocontrollers 
verbinden.
Ich habe nun also 10 Adressleitungen sowie 8 Datenleitungen mit dem FPGA 
verbunden, ausserdem noch WE, OE und CE.
Nun sollen in dem FPGA mehrere "Register" erstellt werden, wo ich was 
speichern kann, und der Inhalt dieser Register beeinflusst dann 
bestimmte Vorgänge im FPGA (z.B. macht der FPGA eine 12 Phasen PWM, und 
über ein entsprechendes 16 Bit breites Register soll der Tastgrad davon 
eingestellt werden können).

Jetzt habe ich dazu mehrere Fragen.
Erstmal: wie mache ich das Interface zum Datenbus, dass es auch sicher 
funktioniert?

Ich habe folgendes:
1
entity test is
2
  port(
3
    clk : in std_ulogic;
4
    d : inout std_logic_vector(7 downto 0);
5
    a : in std_logic_vector(9 downto 0);
6
    we : in std_logic;
7
    oe : in std_logic;
8
    ce : in std_logic
9
    );
10
end project;
11
12
architecture behv of test is
13
  signal dat : std_logic_vector(7 downto 0);
14
begin
15
  process begin
16
    wait until rising_edge(CLK);
17
    if ce = '0' then
18
      if oe = '0' then
19
        d <= dat;
20
      end if;
21
      if we = '0' then
22
        dat <= d;
23
      end if;
24
    else
25
      d <= (others => 'Z');
26
    end if;
27
  end process;
28
end architecture;

das soll mal als erster Test dienen, ob ich ein einzelnes Byte im FPGA 
speichern und wieder raus lesen kann. Wird es so funktionieren?

Des Weiteren soll natürlich jetzt Abhängig von der angelegten Adresse 
der Wert in unterschiedlichen Registern abgelegt werden. Das hier
1
entity test is
2
  port(
3
    clk : in std_ulogic;
4
    d : inout std_logic_vector(7 downto 0);
5
    a : in std_logic_vector(9 downto 0);
6
    we : in std_logic;
7
    oe : in std_logic;
8
    ce : in std_logic
9
    );
10
end project;
11
12
architecture behv of test is
13
  signal r0 : std_logic_vector(7 downto 0);
14
  signal r1 : std_logic_vector(7 downto 0);
15
  signal r2 : std_logic_vector(7 downto 0);
16
begin
17
  process begin
18
    wait until rising_edge(CLK);
19
     if ce = '0' then
20
      if oe = '0' then
21
        case to_integer(unsigned(a)) is
22
          when 0 =>
23
            d <= r0;
24
          when 1 =>
25
            d <= r1;
26
          when 2 =>
27
            d <= r2;
28
          when others =>
29
            null;
30
        end case;
31
      end if;
32
      if we = '0' then
33
        case to_integer(unsigned(a)) is
34
          when 0 =>
35
            r0 <= d;
36
          when 1 =>
37
            r1 <= d;
38
          when 2 =>
39
            r2 <= d;
40
          when others =>
41
            null;
42
        end case;
43
      end if;
44
    else
45
      d <= (others => 'Z');
46
    end if;
47
  end process;
48
end architecture;

funktioniert vielleicht, aber ist sehr unelegant. Gibt es dafür eine 
einfachere Schreibweise?

Noch was:
Der Mikrocontroller, der das ganze steuern soll, ist ein LPC2378. Es 
kann durchaus auch vorkommen, dass ein Register mehr als 8 Bits breit 
ist; z.B. eben bei der PWM - der Tastgrad wird über 16 Bits eingestellt. 
Ich kann wohl im Programm des Mikrocontrollers einen 16 Bit 
Speicherzugriff realisieren; doch wie schaut dies dann aus Sicht des 
FPGAs aus? Wie muss ich mit den Registern hantieren, um am Schluss den 
korrekten 16 Bit Wert zu erhalten?

Ich hoffe, ihr könnt mir ein paar Tipps geben. Bin gespannt :)

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


Lesenswert?

> Wird es so funktionieren?
Oft. Aber garantiert nicht immer.
Denn die Signale des uCs sind (vermutlich) asynchron zum FPGA-Takt.

Zudem wirst du Treiberkonflikte auf dem Datenbus bekommen, denn das 
Abschalten der Treiber erfolgt nicht direkt mit we, sondern mit dem 
nächsten FPGA-Takt...

> Erstmal: wie mache ich das Interface zum Datenbus, dass es auch sicher
> funktioniert?
Wie hoch ist dein uC-Takt?
Wie hoch ist dein FPGA-Takt?
Kannst du den FPGA-Takt mit dem uC-Takt koppeln (synchrones Design)?
Hast du die Möglichkeit Waitstates für den Buszugriff zu konfigurieren?

> Wie muss ich mit den Registern hantieren, um am Schluss den
> korrekten 16 Bit Wert zu erhalten?
Lies mal nach, wie uCs das intern machen:
Da wird z.B. zuerst das untere Byte in ein Schattenregister geschrieben, 
und nur wenn gleich danach das obere Byte kommt, wird das komplette Wort 
ins FPGA übernommen...

von Christian R. (supachris)


Lesenswert?

Als erstes empfehle ich dir eine Simulation, dann siehst du schnell, was 
schief läuft.

Wie Lothar schon sagte, mach die I/O Umschaltung am besten 
kombinatorisch:
1
d <= dat when oe = '0' and ce = '0' else (others => 'Z');

Sonst bekommst du in der Simulation schöne rote 'X' und in der Hardware 
eventuell Treiber-Defekte oder zumindest stark erhöhte Stromaufnahme...

von John (Gast)


Lesenswert?

Hi Lothar,
die Signale vom Daten- und Adressbus und die Steuersignale sind synchron 
zum FPGA-Takt, denn der FPGA-Takt ist gleich dem CPU-Takt. Somit dürfte 
das kein Problem darstellen, oder?
Wie kann ich die Datenbustreiber zum richtigen Zeitpunkt abschalten? 
Kannst du mir mal einen Codeschnipsel geben.
Der Takt beträgt 48 MHz, und ich kann beliebige Waitstates konfigurieren 
(aber ich möchte natürlich so wenige wie nur möglich verwenden).

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


Lesenswert?

> denn der FPGA-Takt ist gleich dem CPU-Takt.
Dann hast du tolles Glück und mußt nur mit geeigneten Mittel (Xilinx: 
DCM) den Skew (Laufzeitversatz) zwischen dem FPGA-Takt und dem uC-Takt 
korrigieren.
Der Vorteil dabei ist, dass du (höchstwahrscheinlich) ganz ohne 
Waitstates auskommen wirst.

> Wie kann ich die Datenbustreiber zum richtigen Zeitpunkt abschalten?
Wie bereits von Christian gepostet.
Alles getaktete käme (um genau einen Takt) zu spät  :-/

von Andreas (Gast)


Lesenswert?

Hallo John,

nach den sachdienlichen Hinweisen von Lothar und Christian:

>Erstmal: wie mache ich das Interface zum Datenbus, dass es auch sicher 
funktioniert?

Neben der reinen logischen Funktion musst Du noch das korrekte Timing 
sicherstellen...

Hierzu musst Du die Setup und Hold Anforderungen deiner CPU deinem FPGA 
als Constraint mitgeben.
Zusaetzlich waere es sinnvoll die Taktgeschwindigkeit ebenfall mit 
zuzugeben.

Gruss

Andreas

von John (Gast)


Lesenswert?

Hi,
danke für eure Tipps!
könnt ihr mir noch sagen, wie ich das im Altera Quartus II einstelle? 
ich denke, das wird sicher über den Assignment Editor passieren, nur 
weiss ich nicht genau wo.

von John (Gast)


Lesenswert?

Hallo,
ich habe mal ein bisschen gegoogelt, und ein Projekt gefunden, wo mit 
einem CPLD etwas ähnliches gemacht wurde.
Nun habe ich meinen VHDL-Code umgeschrieben:
1
write_proc : process begin
2
  wait until falling_edge(clk);
3
  if ce = '0' and we = '0' then
4
    my_register <= d;
5
  end if;
6
end process;
7
8
read_proc : process begin
9
  wait until falling_edge(clk);
10
  if ce = '0' and oe = '0' then
11
    dat <= my_register;
12
  end if;
13
end process;
14
15
d <= dat when ce = '0' and oe = '0' else (others => 'Z');

Ich habe anhand eines Timing-Diagramms herausgefunden, dass immer bei 
der fallenden Taktflanke die Adressen und Daten gültig sind.

von John (Gast)


Lesenswert?

kann mir keiner weiterhelfen?

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


Lesenswert?

Du hast keine Frage gestellt...   :-o

von Purzel H. (hacky)


Lesenswert?

Man kann das Ganze auch per Schemaeingabe zusammenclicken...

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.